This is driving me nuts.
Could someone please help me out?
I do not understand how to create multiple instances of a component by the
configurator factory and how to reference all these instances.
I played around, and it seems, that the configuration is loaded successfully.
This is my configuration json file (OSGI-INF/configurator/text.json) {
// Resource Format Version
":configurator:resource-version" : 1,
// First Configuration
"my.config~system1":
{
"test.securityEnabled": false,
"test.name": "System1"
},
// Second Configuration
"my.config~system2":
{
"test.securityEnabled": true,
"test.name": "System2"
}
}
This is my annotation proxy for holding the configuration:
public @interface MyConfig
{
boolean test_securityEnabled() default true;
String test_name() default "Empty"; }
I've two components.
The first one should have access to the config.
So, I created a activate and modified annotated method that has a parameter of
type MyConfig.
This is executed only once. I would have expected, that this component is
created twice as I have two configurations for this factory pid, right?
@RequireConfigurator
@Component(service = ISecurityChecker.class,
configurationPid = "my.config",
configurationPolicy = ConfigurationPolicy.OPTIONAL) public
class SecurityChecker implements ISecurityChecker {
private MyConfig _myConfig;
@Activate
public void activate(MyConfig config)
{
_myConfig = config;
}
@Modified
public void modified(MyConfig config)
{
_myConfig = config;
}
@Override
public boolean isSecure(String name, String signature)
{
if(!_myConfig.isSecurityEnabled())
return true;
if(name.equals(signature))
// do some fancy checks
return true;
throw new NotAuthorizedException("Signature check failed!");
}
}
The other component is a JaxRS Whiteboard resource serving a small rest service.
I am desperately trying to reference ALL instances of the SecurityChecker
class, but no matter what I am doing it does not work or only one instance is
available.
@Component(service=ServerInfoControllerImpl.class)
@JaxrsResource
@Path("serverInfo")
public class ServerInfoControllerImpl
{
@Reference
private List<ISecurityChecker> _securityCheckers;
...
}
When I set the policy of the reference to dynamic, as Ray suggested, the
component is not loaded.
Also, when I set the configurationPolicy of the SecurityChecker component to
REQUIRED, the SecurityChecker component is not loaded.
BUT, when looking in the web console both configurations are available, even
though obviously not bound to a bundle. Is that correct?
test.name System1
test.securityEnabled false
Configuration Information
Persistent Identity (PID) my.config~system1
Factory Persistent Identifier (Factory PID) my.config
Configuration Binding ?
test.name System2
test.securityEnabled true
Configuration Information
Persistent Identity (PID) my.config~system2
Factory Persistent Identifier (Factory PID) my.config
Configuration Binding ?
Any help is appreciated. 😊
Thanks,
Philipp
-----Ursprüngliche Nachricht-----
Von: Philipp Höfler <philipp.hoef...@pernexas.com>
Gesendet: Mittwoch, 1. August 2018 10:53
An: users@felix.apache.org
Betreff: AW: Configurator R7 example
May I ask you again for help.
I am still stuck at the multi-tenant implementation.
As described in my last mail, I have slightly modified your suggestion.
I was busy the last couple of days. For some reason, when I try to build the project
including a reference to the Map<Map<>> I am getting the following error:
[ERROR] Failed to execute goal
biz.aQute.bnd:bnd-export-maven-plugin:4.1.0-SNAPSHOT:export (default)
on project my-app: Unable to resolve <<INITIAL>>: missing requirement
osgi.identity;filter:='(osgi.identity=com.my.app.rest-service)'
[caused by: Unable to resolve com.my.app.rest-service
version=1.0.0.201808010851: missing requirement
osgi.service;filter:='(objectClass=java.util.Map)';effective:='active'
] -> [Help 1]
Again, you can find the project on GitHub
https://github.com/phhoef/osgi-test/blob/master/rest-service/src/main/
java/com/my/app/rest/rest/ServerInfoControllerImpl.java
Thanks
-----Ursprüngliche Nachricht-----
Von: Raymond Auge <raymond.a...@liferay.com>
Gesendet: Dienstag, 17. Juli 2018 16:43
An: felix users <users@felix.apache.org>
Betreff: Re: Configurator R7 example
On Tue, Jul 17, 2018 at 10:18 AM, Philipp Höfler <
philipp.hoef...@pernexas.com> wrote:
Hallo Ray,
I am sorry, I do not understand your pseudo code example.
I've modified my test project to show you my current structure.
From my point of view, I would need something like a "Router" to
route the Requests to the right instance of the controller. According
to my current understanding, I will have several controllers for each
configuration due to the configuration factory, right?
Would you mind looking over my example and guide me through?
This is the RestController:
https://github.com/phhoef/osgi-test/blob/master/rest-
service/src/main/java/com/my/app/rest/rest/ServerInfoControllerImpl.j
a
va
Ok, I will use the terms I see in your code.
This JAXRS resource IS the router in my mind. So,
- remove all the configuration details from
ServerInfoControllerImpl.java
@Component(service=ServerInfoControllerImpl.class)
@JaxrsResource
@Path("serverInfo")
public class ServerInfoControllerImpl ....
- move all these configuration details to IRepository impl:
@Component(
configurationPid = "my.config",
configurationPolicy = ConfigurationPolicy.REQUIRE
)
public class IRepositoryImpl implements IRepository ...
- make IRepository implement the security checking methods itself
based on it's config
- make ServerInfoControllerImpl.java track _all_ IRepositories:
@Reference(
policy = ReferencePolicy.DYNAMIC,
policyOption = ReferencePolicyOption.GREEDY
)
private volatile Map<Map<String, Object>, IRepository>
_repositories;
- make getServiceInfo(...) find a IRepository by filtering through the
tracked _repositories using the inputs, something like:
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getServerInfo(@QueryParam(REPO_NAME) String repoName,
@QueryParam(SIGNATURE) String signature) {
try {
Filter filter = FrameworkUtil.createFilter("(repoName=" + repoName +
")");
IRepository repo = _repositories.entrySet().stream().filter(
e -> filter.matches(e.getKey())
).map(
Map.Entry::getValue
).findFirst().orElse(null);
if (repo != null) {
if (repo.isSecurityEnabled()) {
// do sec
return ...
}
else {
// no sec
return ...
}
}
}
catch (InvalidSyntaxException e1) {
// ignore
}
return "Not Found";
That's practically the whole impl.
I hope it helps.
- Ray
Thanks,
Philipp
-----Ursprüngliche Nachricht-----
Von: Raymond Auge <raymond.a...@liferay.com>
Gesendet: Montag, 16. Juli 2018 16:48
An: felix users <users@felix.apache.org>
Betreff: Re: Configurator R7 example
On Mon, Jul 16, 2018 at 10:42 AM, David Jencks
<david.a.jen...@gmail.com>
wrote:
Inline...
Sent from my iPhone
On Jul 16, 2018, at 6:34 AM, Raymond Auge
<raymond.a...@liferay.com>
wrote:
On Mon, Jul 16, 2018 at 6:16 AM, Philipp Höfler <
philipp.hoef...@pernexas.com> wrote:
Hallo Ray,
thanks for your detailed explanation. You're right, I think one
can consider this scenario as multi-tenant.
This sounds pretty promising.
The following points are unclear to me:
* Even if I decouple the configuration from the endpoint, the
security check has to be done in the endpoint, as it depends on
the function
that is
invoked.
I've several classes / endpoints for handling different functions.
Basically, it is about the CRUD functions, but there are also some
additional ones.
Is it still possible to handle the security check based on the
configuration in the endpoint itself, but "route" the call to the
right instance of the endpoint based on the ID coming from the
rest
call?
First off let me answer your second bullet, the two interfaces I
used
were
just "mock" types based on your example. The Endpoint is whatever
you endpoint object was. The Tenant was just an object I made up
which should encompass the instance of your configuration with
which you can make security checks.
* I was trying to implement your suggestion, but I am facing problems.
What is Endpoint and Tenant for interfaces? Are they part of the
JAX-RS framework or osgi or are they custom interfaces?
See above, they are just pseudo code of your design.
* Can I still use endpoints with the annotations (@Path, @Get, etc)?
Yeah! this is what Endpoint was suppose to represent, again in
pseudo
code.
* You have a map of tenants in the endpoint A. How do you create
and
fill
these tenants? Is this done automagically be the factory
configuration?
DS supports tuples of services (as in my example), and it's
maintained
for
you. Then you have each "Tenant" created for you by configuration
admin from a component that requires factory configuration,
automagically ;)
Don’t you mean something like...
Specify the “Require” configuration policy for your DS tenant component.
Then, when a management agent creates a factory configuration for
each tenant, DS will create a corresponding instance of the tenant component.
?
Config admin isn’t going to create component instances for you. This
is close to nitpicking, but if you aren’t familiar with who does
what even a little imprecision can be very confusing, at least to me.
Of course you're right David. I was trying to describe effects rather
than exact mechanics :)
- Ray
Thanks
David Jencks
Sincerely,
- Ray
Again, thanks for your help.
Philipp
-----Ursprüngliche Nachricht-----
Von: Raymond Auge <raymond.a...@liferay.com>
Gesendet: Freitag, 13. Juli 2018 16:01
An: felix users <users@felix.apache.org>
Betreff: Re: Configurator R7 example
On Fri, Jul 13, 2018 at 4:37 AM, Philipp Höfler <
philipp.hoef...@pernexas.com> wrote:
I've tested the factory configuration and I am afraid that my
problem is not being solved with this approach.
I think I might have to explain the problem in more detail, that
you'll get a better understanding.
I am implementing a REST service using the HTTP Whiteboard mechanism.
This interface is described in a quite old standard.
Each call contains an identifier. I would like to configure my
service based on this identifier.
Meaning, depending on this identifier I would like to use
different configuration.
Example:
I am receiving a call with identifier for S1 (System 1).
{
// Resource Format Version
":configurator:resource-version" : 1,
// First Configuration
"my.config~system1":
{
"test.securityEnabled": false,
"test.test": false
},
// Second Configuration
"my.config~system2":
{
"test.securityEnabled": true,
"test.test": false
}
}
}
Then, I would like to disable the security when the call comes
from System 1.
But when the call comes from System 2 the security should be enabled.
Maybe I am still misunderstanding the factory configuration.
No I think you have understood it well. However I think what you
need is to break up the concerns a little.
If if were me building your system, I would:
- decouple the configuration from the rest endpoint. Let's call
the endpoint A and the configuration Tenants (because it sounds
like you are building a multi-tenant system):
@Component
class A implements Endpoint {
@Reference(
policy = ReferencePolicy.DYNAMIC,
policyOption = ReferencePolicyOption.GREEDY
)
private volatile Map<Map<String, Object>, Tenant> _tenants;
String handleRequest(String tenantId) {
try {
Filter filter = FrameworkUtil.createFilter("(
tenantId="
+
tenantId + ")");
return _tenants.entrySet().stream().filter(
e -> filter.matches(e.getKey())
).map(
Map.Entry::getValue
).findFirst().orElse("Not Found");
}
catch (InvalidSyntaxException e1) {
// ignore
}
return "Not Found";
}
}
- create a component managed through factory configuration as above
@Component(
configurationPid = "my.config",
configurationPolicy = ConfigurationPolicy.REQUIRE
)
class TenantImpl implements Tenant {
private TenantConfig config;
@Activate
void activate(TenantConfig config) {
this.config = config;
}
}
this becomes a "service" for every factory configuration instance
which is then tracked by A
Create new tenants as needed.
I hope that illustrates the model a little better.
- Ray
But according to my current understanding, osgi will create two
rest endpoints for each configuration, right?
When the rest call arrives, only one instance handles it, as the
URL is the same.
I do not know the identifier at compile time.
To summarize:
I basically want to load/use the config, based on a parameter
coming with the request.
If possible at all, I do not want to limit the amount of systems.
Could you imagine any easy solution for that problem?
-----Ursprüngliche Nachricht-----
Von: Raymond Auge <raymond.a...@liferay.com>
Gesendet: Donnerstag, 12. Juli 2018 18:23
An: felix users <users@felix.apache.org>
Betreff: Re: Configurator R7 example
On Thu, Jul 12, 2018 at 11:58 AM, Philipp Höfler <
philipp.hoef...@pernexas.com> wrote:
Right, this is missing.
I added the @RquireConfigurator annotation to the GoGo Command
class.
Is that a suitable place for it?
The json is now being loaded. The value is set to false.
Could you please explain, how this is working?
It's not completely clear to me, why the @interface MyConfig is
automatically used to hold the configuration.
DS is merely creating a proxy of the annotation type which fronts
(or is backed by) the configuration dictionary, using the default
values as well, default values if that particular property is not
defined or if no configuration is available.
In each class, that needs access to the config I've a activate
and modified method with this signature: public void
modified(MyConfig
config)
Is the type resolved based on the pid and the param type of the
method?
The Component Property Type will be backed by whatever
configuration is associated with the component. so if you use the
same Component Property Types on two different components which
refer to two different pids, the proxies will show different
values (based on the backing configuration dictionary of the
component).
---
Back to my root problem:
Is it now possible to have the following configuration?
{
// Resource Format Version
":configurator:resource-version" : 1,
// First Configuration
"my.config":
{
"system1":
{
"test.securityEnabled": false,
"test.test": false
},
"system2":
{
"test.securityEnabled": false,
"test.test": false
}
}
}
Sure in this case the configuration dictionary will hold values:
system1 = {"test.securityEnabled": false, "test.test": false}
system2 = {"test.securityEnabled": false, "test.test": false}
which is probably not what you intended.
IF what you want is to create N instances of the component, one
per set of configuration properties, you'd want to use Factory
Configurations like so:
{
// Resource Format Version
":configurator:resource-version" : 1,
// First Configuration
"my.config~system1":
{
"test.securityEnabled": false,
"test.test": false
},
// Second Configuration
"my.config~system2":
{
"test.securityEnabled": true,
"test.test": false
}
}
}
Then you will have 2 component activations; one for each system1,
system2, each with a MyConfig instance backing a different
factory configuration instance.
HTH
- Ray
Is it possible to have such a config with n systems?
Meaning, I do not know the amount of systems at compile time.
Further, how would the @interface MyConfig annotation look like?
Is it possible to expect an array of MyConfig for the
modified(MyConfig[]
configs) method?
Thanks for your help,
Philipp
-----Ursprüngliche Nachricht-----
Von: Raymond Auge <raymond.a...@liferay.com>
Gesendet: Donnerstag, 12. Juli 2018 16:43
An: felix users <users@felix.apache.org>
Betreff: Re: Configurator R7 example
Did you add the requirement to your configuration bundle?
Require-Capability: osgi.extender; \
filter:="(&(osgi.extender=osgi.configurator) \
(version>=1.0
<https://osgi.org/specification/osgi.cmpn/7.0.0/
service.configurator.html#org.osgi.service.configurator>)(!(
version>=2.0)))"
That or on some bit of code in the configuration bundle add the
annotation:
@org.osgi.service.configurator.annotations.RequireConfigurator
- Ray
On Thu, Jul 12, 2018 at 10:23 AM, Philipp Höfler <
philipp.hoef...@pernexas.com> wrote:
Hallo David,
thanks for the explanation.
So, the configurator is just a "wrapper" for the
ConfigAdminService to read json and transfer it into a key
value
format, right?
I still have problems to use the I put a test.json file in the
OSGI-INF/configurator folder of a bundle with the following
content:
{
// Resource Format Version
":configurator:resource-version" : 1,
// First Configuration
"my.config":
{
"test.securityEnabled": false,
"test.test": false
}
}
In addition, I have an annotation for holding the values:
public @interface MyConfig
{
boolean test_securityEnabled () default true;
boolean test_test() default true; }
Besides that, I've a custom GoGo command for configuration.
But I am not sure, if this is really needed for loading the json?
Unfortunately, the json is obviously not loaded.
Both values are set to true, according to the default value.
Do I have to do something in addition to load the json file?
Thanks,
Philipp
-----Ursprüngliche Nachricht-----
Von: David Bosschaert <david.bosscha...@gmail.com>
Gesendet: Donnerstag, 12. Juli 2018 11:15
An: users@felix.apache.org
Betreff: Re: Configurator R7 example
Hi Philipp,
In the end the configuration specified with the Configurator
will end up in OSGi Configuration Admin, so the Configurator is
limited to the same types as ConfigAdmin. The Configurator
allows complex JSON values to be specified, they will end up as
JSON text in Configuration Admin if they go beyond what
ConfigAdmin supports
natively.
So to use the Configurator you need the Configurator bundle
plus the ConfigAdmin bundle.
The Configurator handles configuration resources in
OSGI-INF/configurator inside bundles but can also be provided
with external configuration via the configurator.initial
framework/system property. This is described in sections 150.4
and
150.5 in [1]. To provide Configurator configuration into the
system you don't need to write any classes, but depending on
how you use the configuration you may have to add classes that
consume it. But again, the consumption can be done by anything
that understands ConfigAdmin configs, so there
are a lot of options for this.
I'm not aware of a complete tutorial on this topic yet. I agree
it would be nice to have that.
Hope this helps,
David
[1] https://osgi.org/specification/osgi.cmpn/7.0.0/
service.configurator.html
On Thu, 12 Jul 2018 at 10:55, Philipp Höfler
<philipp.hoef...@pernexas.com
wrote:
Hi,
I am searching for a possibility to load complex configurations.
I tried the ConfigurationAdminService, but key value pairs are
not sufficient as I need complex types.
Raymond pointed out that I should have a look at the
Configurator Specification.
https://osgi.org/specification/osgi.cmpn/7.0.0/
service.configurator.
ht
ml
I read the specification and it sounds promising.
But I am stuck how to use the Configuration in my project.
I understand that I've to add the following dependency.
org.apache.felix.configurator
But I don't understand if I've to add some classes, where the
json file has to be placed and if it's possible to place it
outside of the
bundle?
Is there any tutorial or sample project out there?
Thanks,
Philipp
--------------------------------------------------------------
--
--
--
- To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org
--
*Raymond Augé*
<http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.*
<http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)
---------------------------------------------------------------
--
---
- To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org
--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.*
<http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)
--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)
-----------------------------------------------------------------
--
-- To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org
--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)
--------------------------------------------------------------------
- To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org
--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org
--
*Raymond Augé* <http://www.liferay.com/web/raymond.auge/profile>
(@rotty3000)
Senior Software Architect *Liferay, Inc.* <http://www.liferay.com>
(@Liferay)
Board Member & EEG Co-Chair, OSGi Alliance <http://osgi.org>
(@OSGiAlliance)
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org