Hi Konrad,
The next step IMHO is to formally rename this to Sling Models and move
it to extensions/models. I'll start a separate thread about that.

Regards,
Justin

On Fri, Jan 10, 2014 at 10:13 AM, Konrad Windszus <[email protected]> wrote:
> I see that most of the suggestions have been implemented and the feedback was 
> mainly positive. What are the next steps here?
> Can you create a branch containing that piece of code and in parallel create 
> a JIRA ticket for that contribution?
> Thanks
> Konrad
>
> On 07 Jan 2014, at 20:55, Justin Edelson <[email protected]> wrote:
>
>> 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
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>
>>>
>

Reply via email to