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.ja > 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