Hi Georg- Thanks for the suggestion. I think I found a way to handle this with PhantomReferences.
Justin On Tue, Jan 7, 2014 at 11:47 AM, Georg Henzler <[email protected]> wrote: > Hi Justin, > > I have a solution for the unget problem - for a recent project I have > created a class OsgiServiceProxy (also used for the howm-grown injection > mechanism) that allows to use a service without having access to the request > (using java.lang.reflect.Proxy, see [1],[2]). The proxy gets/ungets the > service for every method call (not ideal from a performance perspective, but > it is surprisingly fast and we didn't have a significant performance penalty > here). It could probably be rewritten to use a ServiceTracker (to be more > efficient), but it works as is and the beauty in the solution is, that you > can use/store the service like a service reference because the service proxy > never holds on to the actual service between method calls. > > Regards > Georg > > [1] Usage > MyService myService = OsgiServiceProxy.create(abstractComponent.getClass(), > MyService.class); > > > [2] Impl > public final class OsgiServiceProxy implements InvocationHandler { > > private static final Logger LOG = > LoggerFactory.getLogger(OsgiServiceProxy.class); > > /** > * Creates a proxy for a OSGI service. > * > * @param hostClass The class that uses the service > * @param osgiServiceClass the service class > * @return proxy to the service > */ > public static <T> T create(final Class<?> hostClass, final Class<T> > osgiServiceClass) { > OsgiServiceProxy osgiServiceProxy = new OsgiServiceProxy(hostClass, > osgiServiceClass); > Object service = Proxy.newProxyInstance(hostClass.getClassLoader(), > new Class[] { osgiServiceClass }, osgiServiceProxy); > @SuppressWarnings("unchecked") > T retVal = (T) service; > return retVal; > } > > private Class<?> hostClass; > private Class<?> osgiServiceClass; > > private OsgiServiceProxy(final Class<?> hostClass, final Class<?> > osgiServiceClass) { > this.hostClass = hostClass; > this.osgiServiceClass = osgiServiceClass; > } > > @Override > public Object invoke(final Object proxyObj, final Method method, final > Object[] methodArgs) throws Throwable { > LOG.debug("OsgiServiceProxy: Invocation on service {} method {}", > this.osgiServiceClass, method); > BundleContext componentTypeBundleContext = > FrameworkUtil.getBundle(this.hostClass).getBundleContext(); > ServiceReference serviceReference = > componentTypeBundleContext.getServiceReference(this.osgiServiceClass.getName()); > > if (serviceReference == null) { > throw new IllegalStateException("Cannot call " + > method.getName() + " as service " + osgiServiceClass + " is not available"); > } > > LOG.debug("OsgiServiceProxy: Retrieved service ref for {} ", > this.osgiServiceClass); > Object result = null; > try { > Object service = > componentTypeBundleContext.getService(serviceReference); > result = method.invoke(service, methodArgs); > } finally { > LOG.debug("OsgiServiceProxy: Ungetting service ref for {}", > this.osgiServiceClass); > componentTypeBundleContext.ungetService(serviceReference); > } > return result; > > } > > } > > > > > >> That's unfortunately correct. What I'm in the process of doing is >> changing the OSGiServiceInjector so that if the adaptable is a >> request, it uses SlingScriptHelper intead of the bundle context so at >> least the references are released if you use a request as the >> adaptable. But I don't see a good way to handle this otherwise. Any >> ideas? >> >> Regards, >> Justin >> >>> >>> Cheers, >>> Konrad >>> >>> >>> On 24 Dec 2013, at 22:16, Justin Edelson <[email protected]> >>> wrote: >>> >>>> Thanks everyone for your feedback. I've updated both the wiki and >>>> implementation to include support for: >>>> * declaring an injection as being provided specifically by a >>>> particular injector, using the @Source annotation (as well as adding >>>> this annotation to @Filter) >>>> * composition support (without new annotations) >>>> * switched package to .annotations from .api >>>> * using BundleTracker rather than BundleListener >>>> * a new injector type for child resources >>>> >>>> I also tried to add some reference information to the wiki. >>>> >>>> I think this captured all of the feedback received so far. Thanks again. >>>> >>>> Justin >>>> >>>> On Sat, Dec 21, 2013 at 1:47 AM, Georg Henzler >>>> <[email protected]> wrote: >>>>> >>>>> Hi all, >>>>> >>>>> first of all I have to say that I'm really happy to see that effort is >>>>> being >>>>> made to come up with a annotation based model binding mechansim. We've >>>>> been >>>>> using our own-grown for a while, but a standard is better! :) >>>>> >>>>> I also think it would be useful to inject "sub models". Using only the >>>>> @Inject annotation is ambiguous though, as the class could be either an >>>>> OSGi >>>>> Service or a sub model. A solution for this could be to use an >>>>> annotation >>>>> like @SubModel and make OSGi services the default. >>>>> >>>>> @Inject @SubModel >>>>> private ImageModel image; // using the field name as context path for >>>>> the >>>>> sub model as default, in this case ./image >>>>> >>>>> @Inject @SubModel(path="image2") // path explicitly provided, here >>>>> ./image2 >>>>> private ImageModel anotherImage; >>>>> >>>>> @Inject // assumed to be an OSGi service for non-primitive types >>>>> private SomeOtherClass myService; >>>>> >>>>> >>>>> -Georg >>>>> >>>>> >>>>> Am 20.12.2013 15:19, schrieb Justin Edelson: >>>>> >>>>>> Hi Konrad, >>>>>> Thanks for the clarification. >>>>>> >>>>>> It seems straightforward enough to be able to adapt the injected value >>>>>> if it is not assignable to the field's class. >>>>>> >>>>>> @Inject >>>>>> private ImageModel image >>>>>> >>>>>> image would be a Resource object natively which could then be adapted >>>>>> to the ImageModel class. >>>>>> >>>>>> Justin >>>>>> >>>>>> >>>>>> >>>>>> On Fri, Dec 20, 2013 at 8:08 AM, Konrad Windszus <[email protected]> >>>>>> wrote: >>>>>>> >>>>>>> >>>>>>> Hi Justin, >>>>>>> let me give a concrete example where switching resource nodes is >>>>>>> actually >>>>>>> useful: I do have a composition model of two image models (i.e. the >>>>>>> same >>>>>>> class). Obviously they cannot share the same node, as both models are >>>>>>> referring to the same value names. Therefore an approach similar to >>>>>>> <sling:include path="..." resourceType=".."> would be very useful on >>>>>>> the >>>>>>> model side. I admit that in the case of models it is a little bit >>>>>>> different, >>>>>>> because we are not doing real request dispatching here. Rather I want >>>>>>> to >>>>>>> have a way to tell the factory (or only the ValueMap injector) to act >>>>>>> on a >>>>>>> certain sub node of the request resource instead of the request >>>>>>> resource >>>>>>> itself. That way we could tell the instance1 of the image model to >>>>>>> act on >>>>>>> subnode 'image1" and the instance2 of that model to act on subnode >>>>>>> "image2". >>>>>>> >>>>>>> Regards, >>>>>>> Konrad >>>>>>> >>>>>>> Am 20.12.2013 um 13:41 schrieb Justin Edelson >>>>>>> <[email protected]>: >>>>>>> >>>>>>>> Hi Konrad, >>>>>>>> This makes sense, except for the part about "switch the current >>>>>>>> resource"? What do you mean by this? It seems we should be treating >>>>>>>> the request resource (which is what I think of as the "current" >>>>>>>> resource) as immutable. >>>>>>>> >>>>>>>> Regards, >>>>>>>> Justin >>>>>>>> >>>>>>>> On Fri, Dec 20, 2013 at 5:31 AM, Konrad Windszus <[email protected]> >>>>>>>> wrote: >>>>>>>>> >>>>>>>>> >>>>>>>>> Hi Justin, >>>>>>>>> another useful feature just came to my mind (in fact we are using >>>>>>>>> it in >>>>>>>>> our own annotation framework) which is composition. Would it be >>>>>>>>> much effort >>>>>>>>> to allow injecting one model into another? >>>>>>>>> We do have the following usecase for that (although this is CQ, I >>>>>>>>> guess >>>>>>>>> there is a similar usecase in Sling only): >>>>>>>>> >>>>>>>>> You have a model for an image with title, alternative text. >>>>>>>>> You have a model for multiline text fields and alignment. >>>>>>>>> There exist resourceTypes for each of the models as well as a >>>>>>>>> composite >>>>>>>>> resourceType multilineImage. >>>>>>>>> For the composite resourceType I would like to reuse the existing >>>>>>>>> models, but I cannot split up the view (i.e. the JSPs and work with >>>>>>>>> sling:include), because the html is somehow intertwined. >>>>>>>>> Therefore I would define another composite model exposing the >>>>>>>>> models >>>>>>>>> for both image and multiline and use that composite model in my >>>>>>>>> JSP. >>>>>>>>> >>>>>>>>> It would be great if for the injection of other models it would be >>>>>>>>> possible to switch the current resource as well (i.e. descent into >>>>>>>>> subnode >>>>>>>>> image). >>>>>>>>> That do you think about that? >>>>>>>>> >>>>>>>>> Thanks in advance, >>>>>>>>> Konrad >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Am 19.12.2013 um 18:07 schrieb Justin Edelson >>>>>>>>> <[email protected]>: >>>>>>>>> >>>>>>>>>> Hi, >>>>>>>>>> I've published a page to the wiki about a concept I've been >>>>>>>>>> working on >>>>>>>>>> to consolidate the various appproaches I have seen in the wild to >>>>>>>>>> model object creation. I'm calling this YAMF for now, although >>>>>>>>>> ideally >>>>>>>>>> we'll just call it Sling Models :) >>>>>>>>>> >>>>>>>>>> Without repeating the whole contents of the wiki page, at a high >>>>>>>>>> level, this is a purely annotation driven approach supporting both >>>>>>>>>> classes and interfaces. Your model class simply needs to declare >>>>>>>>>> from >>>>>>>>>> which other classes it can be adapted: >>>>>>>>>> >>>>>>>>>> @Model(adaptables=Resource.class) >>>>>>>>>> >>>>>>>>>> And then annotate the fields (for classes) and methods (for >>>>>>>>>> interfaces) which need injection: >>>>>>>>>> >>>>>>>>>> @Inject >>>>>>>>>> private String propertyName; >>>>>>>>>> >>>>>>>>>> You can inject properties, OSGi services, request attributes, and >>>>>>>>>> entries from SlingBindings. >>>>>>>>>> >>>>>>>>>> New injector types can be created through an SPI. >>>>>>>>>> >>>>>>>>>> Additional annotations are supported for special cases: >>>>>>>>>> >>>>>>>>>> @Optional - mark a field/method as optional. >>>>>>>>>> @Filter - provide a filter (i.e. for OSGi services) >>>>>>>>>> @Named - specify a name (other than the default field/method name) >>>>>>>>>> to >>>>>>>>>> use for the inejction lookup. >>>>>>>>>> >>>>>>>>>> More detail can be found here: >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> https://cwiki.apache.org/confluence/display/SLING/YAMF+-+Yet+Another+Model+Factory >>>>>>>>>> >>>>>>>>>> The working code is up in my whiteboard: >>>>>>>>>> >>>>>>>>>> https://svn.apache.org/repos/asf/sling/whiteboard/justin/yamf/ >>>>>>>>>> >>>>>>>>>> Look forward to your feedback. >>>>>>>>>> >>>>>>>>>> Regards, >>>>>>>>>> Justin >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>> >>>>> >>> >
