You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@sling.apache.org by Justin Edelson <ju...@justinedelson.com> on 2013/12/19 18:07:50 UTC

[RFC] YAMF - Yet Another Model Factory

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

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi Dan,

On Thu, Dec 19, 2013 at 12:37 PM, Daniel Klco <dk...@apache.org> wrote:
> Justin,
>
> This seems like a really nice addition.  I was working on something
> similar using Java's Dynamic Proxy to allow injection from the
> repository.  The model is slightly different where instead of
> annotating member variables, you annotate methods on an interface.
> http://svn.apache.org/repos/asf/sling/whiteboard/dklco/dynamic-proxy/

Yes - proxy based injection (of methods) works too. Most of the tests
are written with classes, but there is one or two with interfaces. The
SPI handles both cases.

>
> Overall, I'd actually say I like the approach you've defined.  A
> couple thoughts though:
>
> - Would it make sense to separate the property/service injection
> annotations to make it more clear what's being injected?

I don't think so - as a model developer, I shouldn't necessarily care
where my injections are coming from, just that they are being
injected.

> - How about adding support for the naming as variables in the Inject
> annotation instead of a separate annotation?  This would also go for
> some of the other annotations.  I think from a developer's perspective
> it makes more sense to configure an annotation than have to look up a
> bunch of different unconnected annotations,

As I wrote, one of the design goals is to use standard annotations.
@Inject and @Named are common annotations defined in the JDK.

> - Do the filters just work on service injection?

Correct, although there's no reason a different Injector couldn't use them.

> - So this one confuses me a little:
>
>  @Inject
>     @Named("log")
>     private Logger logger;
>
> Is the @Named being used for the page / request attributes?

Yes - in this case, "log" is the name of the SlingBindings attribute.

> How can
> one tell from where the injectable object will be loaded?

You can't :)

> Would there
> be any value/reason to being able to specify?

I don't think so, but I'm curious for others opinions. As someone who
builds a model class, why should it matter? I just say "I want a
String instance named 'firstProperty'" and it "magically" appears. Too
magical?

Justin

>
> Very cool though over all!
>
> -Dan
>
> On Thu, Dec 19, 2013 at 12:21 PM, Konrad Windszus <ko...@gmx.de> wrote:
>>
>> HI Justin,
>> thank a lot for that. I am assuming a lot of developers were waiting for just that. Could you extend the wiki page with an example on how the model bean should then be used from within the view (i.e. the JSP) and also some words about the scope of one instance?
>> One very good addition to the annotations would probably be a default value in case there is nothing reasonable to be injected (very useful for resource values which are not yet set).
>> Thanks,
>> Konrad
>>
>> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>>
>> > 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
>>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Daniel Klco <dk...@apache.org>.
Justin,

This seems like a really nice addition.  I was working on something
similar using Java's Dynamic Proxy to allow injection from the
repository.  The model is slightly different where instead of
annotating member variables, you annotate methods on an interface.
http://svn.apache.org/repos/asf/sling/whiteboard/dklco/dynamic-proxy/

Overall, I'd actually say I like the approach you've defined.  A
couple thoughts though:

- Would it make sense to separate the property/service injection
annotations to make it more clear what's being injected?
- How about adding support for the naming as variables in the Inject
annotation instead of a separate annotation?  This would also go for
some of the other annotations.  I think from a developer's perspective
it makes more sense to configure an annotation than have to look up a
bunch of different unconnected annotations,
- Do the filters just work on service injection?
- So this one confuses me a little:

 @Inject
    @Named("log")
    private Logger logger;

Is the @Named being used for the page / request attributes?  How can
one tell from where the injectable object will be loaded? Would there
be any value/reason to being able to specify?

Very cool though over all!

-Dan

On Thu, Dec 19, 2013 at 12:21 PM, Konrad Windszus <ko...@gmx.de> wrote:
>
> HI Justin,
> thank a lot for that. I am assuming a lot of developers were waiting for just that. Could you extend the wiki page with an example on how the model bean should then be used from within the view (i.e. the JSP) and also some words about the scope of one instance?
> One very good addition to the annotations would probably be a default value in case there is nothing reasonable to be injected (very useful for resource values which are not yet set).
> Thanks,
> Konrad
>
> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>
> > 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
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Konrad Windszus <ko...@gmx.de>.
Hi Justin, 
thanks a lot. I would like to see a section in the wiki where required injections are described in detail. I guess in case for injected Sling values which are not there the instantiation fails (i.e. adaptTo will return null). What happens in case a default value is specified? In my regard the annotations Optional and Default should not be combined. 
Regards,
Konrad
Am 19.12.2013 um 22:33 schrieb Justin Edelson <ju...@justinedelson.com>:

> Hi Konrad,
> Defaults have been implemented. Check the wiki.
> 
> Regards,
> Justin
> 
> On Thu, Dec 19, 2013 at 12:21 PM, Konrad Windszus <ko...@gmx.de> wrote:
>> HI Justin,
>> thank a lot for that. I am assuming a lot of developers were waiting for just that. Could you extend the wiki page with an example on how the model bean should then be used from within the view (i.e. the JSP) and also some words about the scope of one instance?
>> One very good addition to the annotations would probably be a default value in case there is nothing reasonable to be injected (very useful for resource values which are not yet set).
>> Thanks,
>> Konrad
>> 
>> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>> 
>>> 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
>> 


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi Konrad,
Defaults have been implemented. Check the wiki.

Regards,
Justin

On Thu, Dec 19, 2013 at 12:21 PM, Konrad Windszus <ko...@gmx.de> wrote:
> HI Justin,
> thank a lot for that. I am assuming a lot of developers were waiting for just that. Could you extend the wiki page with an example on how the model bean should then be used from within the view (i.e. the JSP) and also some words about the scope of one instance?
> One very good addition to the annotations would probably be a default value in case there is nothing reasonable to be injected (very useful for resource values which are not yet set).
> Thanks,
> Konrad
>
> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>
>> 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
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi Konrad,
Thanks for the feedback.

>From a client perspective (i.e. a JSP), they are just using the
adapter framework. The fact that that adaption is annotation driven
isn't important to the client (or visible for that matter). I'll try
to make that more obvious.

Defaults are a good idea.

Justin

On Thu, Dec 19, 2013 at 12:21 PM, Konrad Windszus <ko...@gmx.de> wrote:
> HI Justin,
> thank a lot for that. I am assuming a lot of developers were waiting for just that. Could you extend the wiki page with an example on how the model bean should then be used from within the view (i.e. the JSP) and also some words about the scope of one instance?
> One very good addition to the annotations would probably be a default value in case there is nothing reasonable to be injected (very useful for resource values which are not yet set).
> Thanks,
> Konrad
>
> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>
>> 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
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Konrad Windszus <ko...@gmx.de>.
HI Justin,
thank a lot for that. I am assuming a lot of developers were waiting for just that. Could you extend the wiki page with an example on how the model bean should then be used from within the view (i.e. the JSP) and also some words about the scope of one instance?
One very good addition to the annotations would probably be a default value in case there is nothing reasonable to be injected (very useful for resource values which are not yet set).
Thanks,
Konrad

Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:

> 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


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi Bertrand,


On Fri, Dec 27, 2013 at 5:48 AM, Bertrand Delacretaz
<bd...@apache.org> wrote:
> Hi Justin,
>
> Finally found time to review YAMF.
>
> On Thu, Dec 19, 2013 at 6:07 PM, Justin Edelson
> <ju...@justinedelson.com> wrote:
>> ...I'm calling this YAMF for now, although ideally
>> we'll just call it Sling Models...
>
> +1 for Sling Models, that's consistent with our general naming.
>
> My comments, after looking at the wiki page only:
>
> 1) Should it be @SlingModel rather than @Model? By analogy with @SlingServlet.

I thought about this, but honestly the "Sling" part here is
duplicative. sling is already part of the package name, so why include
it in the annotation name as well?

>
> 2) For adaptation, would my SLING-2938 adapter methods prototype make sense?

Possibly, although as I wrote on the wiki page, one of the design
goals was to not require changes to existing Sling bundles which
AFAICT SLING-2938 does.

>
> 3) Is it a good idea to use @Inject for both services and resource
> values? Using @ResourceValue for the latter makes it easier to explain
> both IMO.

There are already 5 injectors available and I would guess that we need
at least one or two others in the core. And other injectors can be
added by downstream projects. I don't think it makes sense to have
injector-specific annotations unless absolutely necessary (@Filter
being the one obvious example of where an annotation is
injector-specific).

>
> 4) Also, would @Path make sense instead of @Named? Does the
> implementation then support @Path("child-node/some-property") ?

See above. The idea (beyond the goal of using standard annotations
where possible) is that @Named works across injector types. @Path
doesn't make sense for a binding value or request attribute.

>
> 5) @Projection is not obvious to me from its name, how about @ChildPath ?

Yeah, I'm not thrilled with @Projection either, but for the same
reasons as above @ChildPath won't work consistently. How about @From
as in

@Model(adaptables = Resource.class)
public class Model {

   @Inject @From("parent") @Named("jcr:title")
   private String parentTitle;

}

Which means.... set the parentTitle field to the "jcr:title" property
of the parent resource (i.e. resource.getParent()).

>
> Naming nitpicks mostly, YAMF looks good to me, thanks!

I need all the naming help I can get :)

Thanks,
Justin

> -Bertrand

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Bertrand Delacretaz <bd...@apache.org>.
Hi Justin,

Finally found time to review YAMF.

On Thu, Dec 19, 2013 at 6:07 PM, Justin Edelson
<ju...@justinedelson.com> wrote:
> ...I'm calling this YAMF for now, although ideally
> we'll just call it Sling Models...

+1 for Sling Models, that's consistent with our general naming.

My comments, after looking at the wiki page only:

1) Should it be @SlingModel rather than @Model? By analogy with @SlingServlet.

2) For adaptation, would my SLING-2938 adapter methods prototype make sense?

3) Is it a good idea to use @Inject for both services and resource
values? Using @ResourceValue for the latter makes it easier to explain
both IMO.

4) Also, would @Path make sense instead of @Named? Does the
implementation then support @Path("child-node/some-property") ?

5) @Projection is not obvious to me from its name, how about @ChildPath ?

Naming nitpicks mostly, YAMF looks good to me, thanks!
-Bertrand

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
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 <ko...@gmx.de> 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 <ju...@justinedelson.com> 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
>> <sl...@cq-eclipse-plugin.net> 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 <ju...@justinedelson.com>
>>>>> 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
>>>>>> <sl...@cq-eclipse-plugin.net> 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 <ko...@gmx.de>
>>>>>>>> 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
>>>>>>>>> <ju...@justinedelson.com>:
>>>>>>>>>
>>>>>>>>>> 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 <ko...@gmx.de>
>>>>>>>>>> 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
>>>>>>>>>>> <ju...@justinedelson.com>:
>>>>>>>>>>>
>>>>>>>>>>>> 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
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>
>>>
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Konrad Windszus <ko...@gmx.de>.
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 <ju...@justinedelson.com> 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
> <sl...@cq-eclipse-plugin.net> 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 <ju...@justinedelson.com>
>>>> 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
>>>>> <sl...@cq-eclipse-plugin.net> 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 <ko...@gmx.de>
>>>>>>> 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
>>>>>>>> <ju...@justinedelson.com>:
>>>>>>>> 
>>>>>>>>> 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 <ko...@gmx.de>
>>>>>>>>> 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
>>>>>>>>>> <ju...@justinedelson.com>:
>>>>>>>>>> 
>>>>>>>>>>> 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
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>> 
>>>>>> 
>>>> 
>> 


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
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
<sl...@cq-eclipse-plugin.net> 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 <ju...@justinedelson.com>
>>> 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
>>>> <sl...@cq-eclipse-plugin.net> 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 <ko...@gmx.de>
>>>>>> 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
>>>>>>> <ju...@justinedelson.com>:
>>>>>>>
>>>>>>>> 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 <ko...@gmx.de>
>>>>>>>> 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
>>>>>>>>> <ju...@justinedelson.com>:
>>>>>>>>>
>>>>>>>>>> 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
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>
>>>
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Georg Henzler <sl...@cq-eclipse-plugin.net>.
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 <ju...@justinedelson.com> 
>> 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
>>> <sl...@cq-eclipse-plugin.net> 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 
>>>>> <ko...@gmx.de> 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 
>>>>>> <ju...@justinedelson.com>:
>>>>>>
>>>>>>> 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 
>>>>>>> <ko...@gmx.de>
>>>>>>> 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
>>>>>>>> <ju...@justinedelson.com>:
>>>>>>>>
>>>>>>>>> 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
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi,

On Tue, Jan 7, 2014 at 11:50 AM, Bertrand Delacretaz
<bd...@apache.org> wrote:
> Hi,
>
> On Tuesday, January 7, 2014, Justin Edelson wrote:
>
>> ...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?...
>
> IIUC the general problem is making sure things are cleaned up when Sling is
> done processing the current request - we might design a specific mechanism
> for that. Maybe an object in the request attributes to which you can add
> Callables that are executed at the end of a request?

In a request context, this already works - SlingScriptHelper keeps
track of the OSGi services it obtains and calls unget on them when the
request is finished. The problem is in a non-request context, like a
scheduled job, where there is no obvious (at least not obvious to me)
transaction boundary.

The only thing I can think of is to add a special "Disposer" injection
which then a model object needs to call via some method, i.e.

@Model(adaptables = Resource.class)
public class MyModel {

@Inject
private Disposer disposer

public void dispose() {
   disposer.dispose()
}

}

So a client would do:
MyModel model = resource.adaptTo(MyModel.class)
// do some work with model
model.dispose();


Justin

>
> Unless we have such a general mechanism already, but I don't think so.
>
> -Bertrand

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Bertrand Delacretaz <bd...@apache.org>.
Hi,

On Tuesday, January 7, 2014, Justin Edelson wrote:

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

IIUC the general problem is making sure things are cleaned up when Sling is
done processing the current request - we might design a specific mechanism
for that. Maybe an object in the request attributes to which you can add
Callables that are executed at the end of a request?

Unless we have such a general mechanism already, but I don't think so.

-Bertrand

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi Konrad,

On Tue, Jan 7, 2014 at 10:42 AM, Konrad Windszus <ko...@gmx.de> wrote:
> Hi Justin,
> thanks for the additions.
> It would be great if you could extend the documentation in the wiki with the following information:
> - which injectors are available for which adaptables

done.

> - the order in which the injectors are called

I agree that this needs better definition.

> - some more information about @Projection (when it is necessary to call it, i.e. if a desired injector can only act on a child object of the adaptable)

@Projection has been renamed to @Via and I added a better example.

> - some example code on how to use @Source

There's now an example of this on the wiki.

>
> Maybe a table with the different injectors in the rows and the behaviour in terms of the injection-specific annotations like @Named, @Filter as well as the supported adaptable would be the best.

I've converted the list to a table.

@Named isn't injector specific. It is, however, ignored for OSGI
services, something which is identified in the table.

>
> Regarding the OSGiServiceInjector: I did not see the ungetService, therefore the service reference is probably never released.

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 <ju...@justinedelson.com> 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
>> <sl...@cq-eclipse-plugin.net> 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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>>>>>
>>>>>> 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 <ko...@gmx.de>
>>>>>> 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
>>>>>>> <ju...@justinedelson.com>:
>>>>>>>
>>>>>>>> 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
>>>>>>>
>>>>>>>
>>>>>
>>>
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Konrad Windszus <ko...@gmx.de>.
Hi Justin,
thanks for the additions.
It would be great if you could extend the documentation in the wiki with the following information:
- which injectors are available for which adaptables
- the order in which the injectors are called
- some more information about @Projection (when it is necessary to call it, i.e. if a desired injector can only act on a child object of the adaptable)
- some example code on how to use @Source

Maybe a table with the different injectors in the rows and the behaviour in terms of the injection-specific annotations like @Named, @Filter as well as the supported adaptable would be the best.

Regarding the OSGiServiceInjector: I did not see the ungetService, therefore the service reference is probably never released.

Cheers,
Konrad


On 24 Dec 2013, at 22:16, Justin Edelson <ju...@justinedelson.com> 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
> <sl...@cq-eclipse-plugin.net> 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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>>>> 
>>>>> 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 <ko...@gmx.de>
>>>>> 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
>>>>>> <ju...@justinedelson.com>:
>>>>>> 
>>>>>>> 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
>>>>>> 
>>>>>> 
>>>> 
>> 


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
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
<sl...@cq-eclipse-plugin.net> 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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>>>
>>>> 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 <ko...@gmx.de>
>>>> 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
>>>>> <ju...@justinedelson.com>:
>>>>>
>>>>>> 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
>>>>>
>>>>>
>>>
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Georg Henzler <sl...@cq-eclipse-plugin.net>.
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 <ko...@gmx.de> 
> 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 
>> <ju...@justinedelson.com>:
>>
>>> 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 <ko...@gmx.de> 
>>> 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 
>>>> <ju...@justinedelson.com>:
>>>>
>>>>> 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
>>>>
>>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>
>> 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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>>>
>>>> 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
>>>
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Konrad Windszus <ko...@gmx.de>.
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 <ju...@justinedelson.com>:

> 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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>> 
>>> 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
>> 


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
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 <ko...@gmx.de> 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 <ju...@justinedelson.com>:
>
>> 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
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Konrad Windszus <ko...@gmx.de>.
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 <ju...@justinedelson.com>:

> 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


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Felix Meschberger <fm...@adobe.com>.
Hi Justin

Am 20.12.2013 um 13:55 schrieb Justin Edelson <ju...@justinedelson.com>:

> Hi Felix,
> 
> On Fri, Dec 20, 2013 at 5:32 AM, Felix Meschberger <fm...@adobe.com> wrote:
>> Hi Justin
>> 
>> Wow ! I really like this !
>> 
>> Still, as always, I have some comments:
>> 
>> * I share Dan's concerns with respect to the @Inject annotation: Isn't that too generic ? (Yes, I am the strongly typed guy, so I love to know things upfront in a  fail early style)
> 
> I'd love to better understand this. What is a use case in which you
> would need to explicitly state that an injected field should be
> sourced from a particular Injector?
> 
> Even if there was, I'd prefer to do that as a separate annotation, i.e.
> 
> @Inject @Source("osgi-service")
> private Something something;
> 
> Keep in mind that in my worldview, 80% of cases will be handled by
> *just* @Model and @Inject.

I am fine with and if it not too much magic to cope with ;-)

> 
>> 
>> * I see support for interfaces is implemented as proxies which are loaded through the interface type's class loader. But the InvocationHandler is created for each invocation of adaptTo. Would it make sense to cache the generated proxy classes and just create new instances of them on each invocation ? (well this maybe already falls into the optimization category)
> 
> Perhaps, but this is definitely premature optimization :)
> 
>> 
>> * I assum the value to @Filter is supposed to be a valid OSGi Filter argument. Should thus the respective sample in the wiki be fixed by having the string value be surrounded by parentheses ? Also, the existence of the @Filter annotation would stipulate the respective @Incject annotation to only be considered by the service injector.
> 
> Filter example has been fixed. I'm not sure that there's a need to
> restrict the @Filter annotation to one particular Injector.
> 
>> 
>> * I would think the api bundle and package should rather be called annotations, right ?
>> 
>> * The annotations are currently RUNTIME scoped and the packaged classes are eagerly loaded on bundle start time (you might want to leverage the BundleTracker for easier tracking of bundles). This sounds like a performance problem. How about doing it like Declarative Services and tooling generate a descriptor which will be loaded on bundle startup and the respective classes loaded on-demand ? (OTOH this runtime analysis copes better with Java extensions)
> 
> And another Maven plugin and then an Ant task and an Eclipse plugin
> and an IntelliJ plugin... I really think runtime is the right
> approach.
> 
> The better solution IMHO would to implement the wildcard adapter
> support we discussed when Dan introduced dynamic proxies. The
> YamfAdapterFactory could figure out that this was enabled and skip the
> whole bundle scanning bit. But since one of the design goals was to
> work with existing Sling bundles, I didn't deal with this now.
> 
> I was also trying to use Scannotation to scan the class files instead
> of doing class loading. Ran into trouble, but will come back to this.
> 
>> 
>> * YAMF model classes must be exported for them to be usable in code. Maybe that is just how this kind of thing works but we should be aware of that and that exporting these classes in fact defines API. This would fall into the Model class requirements category: Must be exported and is considered API, classes must have public default constructore, etc.
> 
> Actually, this isn't the case - YAMF model classes do not need to be
> exported *to be used by YAMF*. They do need to be exported to be
> referenced in JSPs or other bundles, but that's just normal stuff.
> YAMF itself doesn't put any requirements on the visibility of
> packages.

That's what I wanted to express, actually.

Regards
Felix

> 
> Justin
> 
>> 
>> Thanks
>> Felix
>> 
>> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>> 
>>> 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
>> 


Re: [RFC] YAMF - Yet Another Model Factory

Posted by Justin Edelson <ju...@justinedelson.com>.
Hi Felix,

On Fri, Dec 20, 2013 at 5:32 AM, Felix Meschberger <fm...@adobe.com> wrote:
> Hi Justin
>
> Wow ! I really like this !
>
> Still, as always, I have some comments:
>
> * I share Dan's concerns with respect to the @Inject annotation: Isn't that too generic ? (Yes, I am the strongly typed guy, so I love to know things upfront in a  fail early style)

I'd love to better understand this. What is a use case in which you
would need to explicitly state that an injected field should be
sourced from a particular Injector?

Even if there was, I'd prefer to do that as a separate annotation, i.e.

@Inject @Source("osgi-service")
private Something something;

Keep in mind that in my worldview, 80% of cases will be handled by
*just* @Model and @Inject.

>
> * I see support for interfaces is implemented as proxies which are loaded through the interface type's class loader. But the InvocationHandler is created for each invocation of adaptTo. Would it make sense to cache the generated proxy classes and just create new instances of them on each invocation ? (well this maybe already falls into the optimization category)

Perhaps, but this is definitely premature optimization :)

>
> * I assum the value to @Filter is supposed to be a valid OSGi Filter argument. Should thus the respective sample in the wiki be fixed by having the string value be surrounded by parentheses ? Also, the existence of the @Filter annotation would stipulate the respective @Incject annotation to only be considered by the service injector.

Filter example has been fixed. I'm not sure that there's a need to
restrict the @Filter annotation to one particular Injector.

>
> * I would think the api bundle and package should rather be called annotations, right ?
>
> * The annotations are currently RUNTIME scoped and the packaged classes are eagerly loaded on bundle start time (you might want to leverage the BundleTracker for easier tracking of bundles). This sounds like a performance problem. How about doing it like Declarative Services and tooling generate a descriptor which will be loaded on bundle startup and the respective classes loaded on-demand ? (OTOH this runtime analysis copes better with Java extensions)

And another Maven plugin and then an Ant task and an Eclipse plugin
and an IntelliJ plugin... I really think runtime is the right
approach.

The better solution IMHO would to implement the wildcard adapter
support we discussed when Dan introduced dynamic proxies. The
YamfAdapterFactory could figure out that this was enabled and skip the
whole bundle scanning bit. But since one of the design goals was to
work with existing Sling bundles, I didn't deal with this now.

I was also trying to use Scannotation to scan the class files instead
of doing class loading. Ran into trouble, but will come back to this.

>
> * YAMF model classes must be exported for them to be usable in code. Maybe that is just how this kind of thing works but we should be aware of that and that exporting these classes in fact defines API. This would fall into the Model class requirements category: Must be exported and is considered API, classes must have public default constructore, etc.

Actually, this isn't the case - YAMF model classes do not need to be
exported *to be used by YAMF*. They do need to be exported to be
referenced in JSPs or other bundles, but that's just normal stuff.
YAMF itself doesn't put any requirements on the visibility of
packages.

Justin

>
> Thanks
> Felix
>
> Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:
>
>> 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
>

Re: [RFC] YAMF - Yet Another Model Factory

Posted by Felix Meschberger <fm...@adobe.com>.
Hi Justin

Wow ! I really like this !

Still, as always, I have some comments:

* I share Dan's concerns with respect to the @Inject annotation: Isn't that too generic ? (Yes, I am the strongly typed guy, so I love to know things upfront in a  fail early style)

* I see support for interfaces is implemented as proxies which are loaded through the interface type's class loader. But the InvocationHandler is created for each invocation of adaptTo. Would it make sense to cache the generated proxy classes and just create new instances of them on each invocation ? (well this maybe already falls into the optimization category)

* I assum the value to @Filter is supposed to be a valid OSGi Filter argument. Should thus the respective sample in the wiki be fixed by having the string value be surrounded by parentheses ? Also, the existence of the @Filter annotation would stipulate the respective @Incject annotation to only be considered by the service injector.

* I would think the api bundle and package should rather be called annotations, right ?

* The annotations are currently RUNTIME scoped and the packaged classes are eagerly loaded on bundle start time (you might want to leverage the BundleTracker for easier tracking of bundles). This sounds like a performance problem. How about doing it like Declarative Services and tooling generate a descriptor which will be loaded on bundle startup and the respective classes loaded on-demand ? (OTOH this runtime analysis copes better with Java extensions)

* YAMF model classes must be exported for them to be usable in code. Maybe that is just how this kind of thing works but we should be aware of that and that exporting these classes in fact defines API. This would fall into the Model class requirements category: Must be exported and is considered API, classes must have public default constructore, etc.

Thanks
Felix

Am 19.12.2013 um 18:07 schrieb Justin Edelson <ju...@justinedelson.com>:

> 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