Re: [RT] Sling Models as scoped Dependency Injection Framework

2014-06-30 Thread Justin Edelson
Hi Stefan,
The big problem IMHO with injecting by class vs. name is that by class
is too ambigious in many cases. For example, in AEM, it is relatively
common to want to inject a Page object, but in fact there are two
different page objects which come into play (currentPage and
resourcePage) and getting the wrong one could be highly problematic.
You are correct that things like the request and response could
presumably be injected by class rather than by name, but the question
then becomes how do we judge these cases? In my opinion, the bindings
names are sensible. I personally don't find myself wanting to write
this very often:

@Inject
private SlingHttpServletRequest somenameOtherThanRequest;

The self injector is interesting. I held off on that initially because
it seems too easy to create a circular injection. Any thoughts on how
that can be avoided?

I'm certainly open to patches which broaden the scope for constructor
injection and @PreDestroy.

Regards,
Justin

On Mon, Jun 30, 2014 at 10:13 AM, Stefan Seifert sseif...@pro-vision.de wrote:
 in the last days we played around with Sling Models as underpinning of our 
 views in a Sling+Sightly based application. it works fantastic. but during 
 our experiments we detected that we were not using Sling Models for accessing 
 resource content, i.e. we are not adapting resources to models to access its 
 data. this is not required when using JSP or Sightly because you can access 
 the properties directly. but we were using Sling Models as Dependency 
 Injection frameworks for our java controller classes which are used behind 
 the views, which need access to scoped objects of the current request like 
 resource resolver and others. and if those controller classes need other 
 business classes which depend on scope objects, we use Sling Models injection 
 for them as well.

 a very simple example for illustration:

 this is a controller class behind the view:

 @Model(adaptables = SlingHttpServletRequest.class)
 public class MyController {

   @Inject
   private MyBusinessClass businessClass;

   private String result;

   @PostConstruct
   protected void activate() {
 result = this.businessClass.calculateTheResult();
   }

   public String getResult() {
 return this.result;
   }

 }

 and this is the business classes used by the controller

 @Model(adaptables = SlingHttpServletRequest.class)
 public class MyBusinessClass {

   @Inject
   private ResourceResolver resourceResolver;

   public String calculateTheResult() {
 // access resources using resource resolver
 return myResult;
   }

 }

 effectively we can use Sling Models to navigate through a hierarchy of loose 
 coupled POJOs all using DI for getting the dependencies they need - much like 
 in Spring. we have already dependency injection in Felix SCR/OSGi? that's 
 right, but only for OSGi services, and not for scoped objects depending on 
 a current request or resource resolver instance.

 using the adapter concept to adapt the controller and business classes from 
 the scope object they depend on (e.g. from SlingHttpServletRequest for 
 request scope, from ResourceResolver if they need access to resources in 
 context of a JCR user session etc.) they get all scope context objects they 
 need, and those that can be adapted from them. and of course it's still 
 possible to inject OSGi services as well.

 out of the box the sample displayed above will not work with Sling Models - a 
 small custom injector is required:

 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 50)
 public class SelfAdaptInjector implements Injector {

   public String getName() {
 return selfadapt;
   }

   public Object getValue(Object pAdaptable, String pName, Type pType, 
 AnnotatedElement pElement, DisposalCallbackRegistry pCallbackRegistry) {
 if (!(pType instanceof Class)) {
   return null;
 }
 if (!(pAdaptable instanceof Adaptable)) {
   return null;
 }
 return ((Adaptable)pAdaptable).adaptTo((Class?)pType);
   }

 }

 which effectively supports navigation through a graph of objects which share 
 the same scope adaptable. using another custom injector which allows indirect 
 adaption from SlingHttpServletRequest-ResourceResolver-CustomClass it is 
 possible to have classes that can be used both in request scope, and in 
 ResourceResolver-only scope as well (the latter may be a resource resolver 
 instance which is opened in context of an OSGi service or event handler). 
 this is already possible via via, but i want to avoid boilerplate code as 
 much as possible for much-used context objects.

 additionally all relevant context objects that can be derived from the 
 adaptable should be supported for injection. Justin already added in 
 SLING-3700 as custom injector for resource resolver, but it should support 
 others as well, e.g. injecting the request, the response etc. and in my 
 opinion this should be done primary using detection by class 

RE: [RT] Sling Models as scoped Dependency Injection Framework

2014-06-30 Thread Stefan Seifert
ok, i've touched multiple different topics in my post, i created 4 ticket for 
each of them so we can discuss them further separately:
https://issues.apache.org/jira/browse/SLING-3715
https://issues.apache.org/jira/browse/SLING-3716
https://issues.apache.org/jira/browse/SLING-3718
https://issues.apache.org/jira/browse/SLING-3718

stefan


-Original Message-
From: justinedel...@gmail.com [mailto:justinedel...@gmail.com] On Behalf Of
Justin Edelson
Sent: Monday, June 30, 2014 6:16 PM
To: dev@sling.apache.org
Subject: Re: [RT] Sling Models as scoped Dependency Injection Framework

Hi Stefan,
The big problem IMHO with injecting by class vs. name is that by class
is too ambigious in many cases. For example, in AEM, it is relatively
common to want to inject a Page object, but in fact there are two
different page objects which come into play (currentPage and
resourcePage) and getting the wrong one could be highly problematic.
You are correct that things like the request and response could
presumably be injected by class rather than by name, but the question
then becomes how do we judge these cases? In my opinion, the bindings
names are sensible. I personally don't find myself wanting to write
this very often:

@Inject
private SlingHttpServletRequest somenameOtherThanRequest;

The self injector is interesting. I held off on that initially because
it seems too easy to create a circular injection. Any thoughts on how
that can be avoided?

I'm certainly open to patches which broaden the scope for constructor
injection and @PreDestroy.

Regards,
Justin

On Mon, Jun 30, 2014 at 10:13 AM, Stefan Seifert sseif...@pro-vision.de
wrote:
 in the last days we played around with Sling Models as underpinning of our
views in a Sling+Sightly based application. it works fantastic. but during our
experiments we detected that we were not using Sling Models for accessing
resource content, i.e. we are not adapting resources to models to access its
data. this is not required when using JSP or Sightly because you can access
the properties directly. but we were using Sling Models as Dependency
Injection frameworks for our java controller classes which are used behind the
views, which need access to scoped objects of the current request like
resource resolver and others. and if those controller classes need other
business classes which depend on scope objects, we use Sling Models injection
for them as well.

 a very simple example for illustration:

 this is a controller class behind the view:

 @Model(adaptables = SlingHttpServletRequest.class)
 public class MyController {

   @Inject
   private MyBusinessClass businessClass;

   private String result;

   @PostConstruct
   protected void activate() {
 result = this.businessClass.calculateTheResult();
   }

   public String getResult() {
 return this.result;
   }

 }

 and this is the business classes used by the controller

 @Model(adaptables = SlingHttpServletRequest.class)
 public class MyBusinessClass {

   @Inject
   private ResourceResolver resourceResolver;

   public String calculateTheResult() {
 // access resources using resource resolver
 return myResult;
   }

 }

 effectively we can use Sling Models to navigate through a hierarchy of loose
coupled POJOs all using DI for getting the dependencies they need - much like
in Spring. we have already dependency injection in Felix SCR/OSGi? that's
right, but only for OSGi services, and not for scoped objects depending on a
current request or resource resolver instance.

 using the adapter concept to adapt the controller and business classes from
the scope object they depend on (e.g. from SlingHttpServletRequest for request
scope, from ResourceResolver if they need access to resources in context of a
JCR user session etc.) they get all scope context objects they need, and those
that can be adapted from them. and of course it's still possible to inject
OSGi services as well.

 out of the box the sample displayed above will not work with Sling Models -
a small custom injector is required:

 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 50)
 public class SelfAdaptInjector implements Injector {

   public String getName() {
 return selfadapt;
   }

   public Object getValue(Object pAdaptable, String pName, Type pType,
AnnotatedElement pElement, DisposalCallbackRegistry pCallbackRegistry) {
 if (!(pType instanceof Class)) {
   return null;
 }
 if (!(pAdaptable instanceof Adaptable)) {
   return null;
 }
 return ((Adaptable)pAdaptable).adaptTo((Class?)pType);
   }

 }

 which effectively supports navigation through a graph of objects which share
the same scope adaptable. using another custom injector which allows indirect
adaption from SlingHttpServletRequest-ResourceResolver-CustomClass it is
possible to have classes that can be used both in request scope, and in
ResourceResolver-only scope as well (the latter may be a resource resolver
instance which