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


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)

Reply via email to