Hello Pierre and Reymond

First of all, thank you very much for taking the time to provide detailed
and patient answers.

My usecase was to somehow "Cheat" that service registry, so that a bundle
getting a service reference (For example via
BundleContext.getServiceReferences) would not actually be supplied by a
service from the service registry, but rather a proxy i made, which fronts
the interface in question.
So:
Bundle A calls
BundleContext.getServiceReference(MyAnnotatedInterface.class) <Note that
nothing is registered on this interface at the time of the call>
Some interceptor logic (The component i am trying to make) registers that
the interface is called and, instead of looking in the serviceregistry,
creates a proxy which it returns to BundleA
Bundle A happily uses the proxy it got back, completely oblivious to the
fact that it never got to the service registry.
Bundle A calls
BundleContext.ungetService(myAnnotatedInterfaceServiceReference), at which
point the proxy is told to close and dispose.

So the point would be that the client bundle is completely oblivious to the
"hack", and that the solution works without first having to register any
service on the MyAnnotatedInterface interface.

>From the answers i have seen here, it looks like that usage is not
possible, as any calls to getServiceReference requires something already be
registered on that interface. Correct?

In that case, it would seem that i would have to actually register
MyAnnotatedInterface as a service, and then hot-swap it from there. DM
aspects seems like a good place to start, but i can't quite figure out if
you can use it without doing something more in the client than just
registering the service?

Again, thanks for your help, i you will suffer my ignorance for a wee bit
longer :)

-Martin

On Thu, Oct 6, 2016 at 5:29 PM, Pierre De Rop <pierre.de...@gmail.com>
wrote:

> Hello Martin,
>
> If you are interested, I can describe here DM aspects, which is a feature
> that might be interesting in your case.
> DM aspects are kind of (non functional) interceptors at the OSGi service
> level. DM aspects are real components, they can have a lifecycle,
> can be started/stopped at anytime, and they can declare service
> dependencies, if they need some.
>
> Basically, you can programatically (or using annotations) define some
> aspect services that will be applied to any relevant original services
> matching some given service properties. Multiple aspects can be applied to
> the same original service and in such case, the aspects are chained using
> some ranking order.
>
> Regarding the start ordering, if a client is already bound to a given
> original service, then any post-registered aspects will replace the
> original service already bound to the client (either the volatile field in
> the client pointing to the original service will be updated or a "swap"
> callback will be invoked in order to replace the original service with the
> new aspects). If you have a start ordering requirement (that is: you need
> any client to be injected at the first time with the aspects and not with
> the original service), then as Raymond said you will have to arrange to
> register the aspects before the original services.
>
> Let's take an example using the dm-lambda library (but the original DM api
> or the DM annotations also work):
>
> Assuming you have an original log service with a property "vendor=apache",
> and you want to apply a chain of two aspects on that log service (which has
> a vendor service property). Let's assume the first aspect is an
> "UpperCaseLogService" which rewrites each log message to uppercase, and the
> second one: "ErrorLogEventLogService" is an aspect which triggers an OSGi
> event (using EventAdmin) in case the log is emitted using an ERROR level.
>
> Then you would declare those two aspects like this:
>
> public class Activator extends DependencyManagerActivator {
>     public void init(BundleContext ctx, DependencyManager dm) throws
> Exception {
>         // Create the first aspect which is applied to any LogService
> having a "service=vendor" service property.
>         // Notice the "rank(1)" which means this aspect will be the first
> in the chain
>
>         aspect(LogService.class, aspect -> aspect
>             .impl(UpperCaseLogService.class)
>             .filter("(vendor=apache)")
>             .rank(1));
>
>         // Create the second aspect which is applied to any LogService
> having a "service=vendor" service property
>         // Notice that this aspect has a dependency required on an
> EventAdmin service
>         // Also notice the "rank(2)" which means this aspect will be the
> second one in the chain
>
>         aspect(LogService.class, aspect -> aspect
>             .impl(ErrorLogEventLogService.class)
>             .filter("(vendor=apache)")
>             .rank(2)
>             .withSvc(EventAdmin.class, true));
>    }
> }
>
> Now the UpperCaseLogService aspect class, which convert all logs to upper
> case:
>
> public class UppercaseLogAspect implements LogService{
>     private volatile LogService logService; // injected, possibly the
> original LogService, or the next aspect in the chain
>
>     void start() {
>         // optional lifecycle start callback: our aspect is starting
>     }
>
>     void stop() {
>         // optional lifecycle stop callback: our aspect is stopping
>     }
>
>     public void log(int level, String message) {
>         logService.log(level, message.toUpperCase());
>         ...
>     }
> }
>
> And the ErrorLogEventLogService aspect, which is injected with the original
> LogService , as well as with
> the EventAdmin service: it will trigger an event in case the log level is
> LOG_ERROR:
>
> public class UppercaseLogAspect implements LogService{
>     private volatile LogService logService; // injected, possibly the
> original LogService, or the next aspect in the chain
>     private volatile EventAdmin eventAdmin; // injected, used to trigger an
> event when the logged message level is in error
>
>     void start() {
>         // optional lifecycle start callback: our aspect is starting
>     }
>
>     public void log(int level, String message) {
>         if (level == LogService.LOG_ERROR) {
>             // fire an event using the EventAdmin service injected in this
> class
>         }
>         logService.log(level, message.toUpperCase());
>     }
> }
>
> So, now, if a client is already injected with a log service, then it will
> be swapped at the time the aspect chain is registered.
> The aspect chain will be injected automatically in the volatile field which
> points to the original service, or you can define a swap callback.
>
> let's take an example, using a volatile field:
>
> first the client:
>
> class Client {
>    volatile LogService logService; // the original LogService, or the
> aspect chain
>
>    void doLog() {
>          logService.log(...);
>    }
> }
>
> and the corresponding client activator:
>
> public class ClientActivator extends DependencyManagerActivator {
>
>     public void init(BundleContext ctx, DependencyManager dm) throws
> Exception {
>         component(Client.class, comp -> comp
>             .impl(Client.class.class)
>             .withSrv(LogService.class, true));
>     }
>
> }
>
> And if you want the client to define a swap callback, you can then define
> some the callback like this:
>
> class Client implements Runnable {
>    volatile LogService logService; // the original LogService, or the
> aspect chain
>
>    // bind the required dependency (possibly the original service, or an
> aspect)
>    void set(LogService logService) {
>          this.logService = logService;
>    }
>
>    // called if the original service is swapped with an aspect
>    void swap(LogService oldLog, LogService newLog) {
>        // handle the swapped service
>        this.logService = newLog;
>    }
>
>    public void run() {
>          logService.log(...);
>    }
> }
>
> then here is the ClientActivor, defining the swap callback like this:
>
>         component(Client.class, comp -> comp
>             .impl(Client.class.class)
>             .provides(Runnable.class)
>             .withSrv(LogService.class, srv -> srv.required().add(Client::
> set).swap(Client::swap)));
>
>
> here, the initial LogService is first injected using the "set" callback,
> and if it's the original service, then the swap callback will be invoked
> if (ever) an aspect has to replace the original bound service.
>
> finally, you might also take a look at [1]. I never looked at it, but
> aspecio seems to be another solution allowing to manage osgi aspect
> services.
>
> Hope this helps;
>
> cheers;
> /Pierre
>
> [1] http://www.mail-archive.com/users@felix.apache.org/msg17262.html
>
>
> On Thu, Oct 6, 2016 at 4:04 PM, Raymond Auge <raymond.a...@liferay.com>
> wrote:
>
> > The problem with the above solution is that you will end up in a race
> where
> > a service might already be registered without a proxy, then what? So you
> > should try to avoid ordering issues in your design otherwise you will
> > regret it later.
> >
> > What really should happen is that the thing creating the service should
> add
> > the proxy around the service before the service is ever published. An
> > extender is an ideal place to do this. Felix DM, and IPojo are ideal for
> > this use case since they imperative APIs for managing services and can be
> > "trained" to add proxies based on arbitrary heuristics.
> >
> > It's a wish I have also for Felix SCR.
> >
> > Sincerely,
> > - Ray
> >
> > On Thu, Oct 6, 2016 at 6:45 AM, Martin Nielsen <mny...@gmail.com> wrote:
> >
> > > I think what i wrote might have made more sense in my own head:) I
> > > apologize for the lousy problem description.
> > > Maybe an actual use case would help:
> > >
> > > I would like to use the OSGi serviceregistry to proxy specific
> > interfaces.
> > > For example:
> > > Say that i attempt to get a serviceReference for an interface with a
> > > mybatis annotation on it. What i would like is that the service
> registry
> > > returns a proxy that i define (My idea was through something like a
> > > ServiceBindingInterceptor). The proxy should then be closed down again
> > when
> > > get unget method is called on the service.
> > >
> > > Basically, i would like to supply a proxy implementation of interfaces
> in
> > > certain situations, but still allow for the serviceregistry lifecycle
> > > (get/unget) to handle opening and closing the proxies.
> > >
> > > It doesn't have to use any specific part of the runtime, i just spotted
> > the
> > > interceptors and mistook their purpose a bit i think.
> > >
> > > On Thu, Oct 6, 2016 at 12:32 PM, Clement Escoffier <
> > > clement.escoff...@gmail.com> wrote:
> > >
> > > > Hi,
> > > >
> > > > The service binding interceptor requires to have a “service”
> available.
> > > > You should be able to do what you want by either:
> > > >
> > > > - combining a “default-implementation” strategy and a binding
> > interceptor
> > > > (it would require to have the dependency marked as optional)
> > > > - or create your own handler that inject what you want to inject (
> > > > http://felix.apache.org/documentation/subprojects/
> > > > apache-felix-ipojo/apache-felix-ipojo-devguide/how-to-
> > > > write-your-own-handler.html <http://felix.apache.org/
> > > > documentation/subprojects/apache-felix-ipojo/apache-
> > > > felix-ipojo-devguide/how-to-write-your-own-handler.html>)
> > > >
> > > > Clement
> > > >
> > > >
> > > > > On 6 oct. 2016, at 04:02, Martin Nielsen <mny...@gmail.com> wrote:
> > > > >
> > > > > Hello everyone
> > > > >
> > > > > I am looking at the felix servicebinding interceptors with a
> certain
> > > > amount
> > > > > of enthusiasm, but i am having trouble figuring out if they can
> > solve a
> > > > > specific task.
> > > > >
> > > > > http://felix.apache.org/documentation/subprojects/
> > > > apache-felix-ipojo/apache-felix-ipojo-userguide/ipojo-
> > > > advanced-topics/service-binding-interceptors.html
> > > > >
> > > > > What i would like to do is the following: Whenever a
> ServiceReference
> > > is
> > > > > requested for an interface (No matter which one), i want an
> > interceptor
> > > > to
> > > > > examine it. If the interface meets some criteria, the an
> interceptor
> > > > should
> > > > > create a proxy for that interface, regardless of a matching
> > > > implementation
> > > > > being registered.
> > > > > So: Even if no object is actually registered as a service to that
> > > > > interface, i want the interceptor to return a proxy anyway. Is that
> > > > > possible to do in any way?
> > > > >
> > > > > Thank you in advance.
> > > > >
> > > > > -Martin
> > > >
> > > >
> > >
> >
> >
> >
> > --
> > *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