Sunday, August 6, 2017

Deep Dive on Sling Models in AEM6.3 : Part-1


Hello Everyone,

From AEM 6.0 onward, Sling Models has made AEM Development easier. I, being an AEM Dev realized that we are taking very less  benefits of sling models.so I decided to go in deep and find out what sling model can provide us in all.We  are now standing on AEM 6.3 with sling models 1.3.2 version.
So we will start from the basics and will touch each and every concept in detail.
Design Goals of Sling Models
  • Entirely annotation driven. "Pure" POJOs.
  • Use standard annotations where possible.
  • Pluggable
  • OOTB, support resource properties (via ValueMap), SlingBindings, OSGi services, request attributes
  • Adapt multiple objects - minimal required Resource and SlingHttpServletRequest
  • Client doesn't know/care that these objects are different than any other adapter factory
  • Support both classes and interfaces.
  • Work with existing Sling infrastructure (i.e. not require changes to other bundles).

How to start using Sling Models
1.Add maven dependency to the pom.xml. If you are working with AEM 6.3, Make sure you are using the recent sling model version (1.3.2)
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
<version>1.3.2</version>
<scope>provided</scope>
</dependency>
2. Create a package under which you will be writing all sling models and make an entry of that package (here com.sling.models.core.models) in bundle(core) ‘s pom.xml in Sling-Model-Packages tag within maven-bundle-plugin.
Here:
<plugin>
<groupId>org.apache.felix</groupId>              <artifactId>maven-bundle-plugin</artifactId>
               <extensions>true</extensions>
              <configuration>
                   <instructions>
                       <Sling-Model-Packages>
                           com.sling.models.core.models
                       </Sling-Model-Packages>
                   </instructions>
                 </configuration>
</plugin>

Validate that your class is actually working as a sling model.
Capture.PNG
Fig- Sling Adapters in Felix Console

  • Sling Model class must be visible over here.
How to write a basic sling model?

// This model gets the path of the resource . @Model(adaptables = Resource.class)
public class TestModel {
@Inject
Resource resource;

public String getPath() {
return resource.getPath();
}
}

In the initial state of sling models, we used to use @Inject annotation to inject services, pagemanager, sling objects etc. This is a generic Injector.
  • @Inject queries all Injector implementations “First Match” wins based on the service ranking.
  • Usage of Injector-specific annotations (Introduced in sling models Impl 1.0.6) will reduce the overall work of the internal execution as it specify the source explicitly so it is good to use Injector specific annotations.
Injector Specific Annotations in Sling Model
In AEM Felix console, you can see all the available injectors in sling models 1.3.2
Sling Model Injectors.PNG
Fig - Injector Specific Annotations in Sling Model
list of injectors.PNG
Fig - List of specific injectors
Let’s understand these injectors with the help of examples.
1. Script Variable: This Injector is used to get the currentPage, PageManager, Design, PageProperties etc. This injector is adaptable to request.This injector is adaptable to SlingHttpServletRequest.
ScriptVariable annotation has these attributes:
  • name
  • injectionStrategy: The Strategy can be Optional, Required or Default.

@Model(adaptables = SlingHttpServletRequest.class)
public class TestModel {
  
 // Injects currentPage using ScriptVariable annotation
   @ScriptVariable(name="currentPage")
   Page page;

   public String getPagePath() {
       return  page.getPath();
   }
}
Note: Here it is mandatory to use the object name currentPage. If there is a need to change the name of page object(currentPage), the “nameattribute can help us to do so.
The sightly script to call a sling model is:
<div data-sly-use.example="com.sling.models.core.models.TestModel">
              ${example.pagePath}<br/>
</div>

2. ChildResource : This injector is adaptable to resource and is used to get the specific child of a resource.
The attributes of the ChildResource are:
  • name
  • injectionStrategy
  • via

It works like:
@Model(adaptables = Resource.class)
public class TestModel {

   // Injects the child of the resource using ChildResource annotation
   @ChildResource(name="content")
   Resource child;

   public String getChildPath() {
     return  child.getPath();
   }
}
resourcePath1.png
Fig - Inject Child resource directly

ChildResource annotations with its attributes:
@Model(adaptables = SlingHttpServletRequest.class)
public class TestModel {

   // Injects the child of the resource using ChildResource annotation
   @ChildResource(name="content",injectionStrategy= InjectionStrategy.OPTIONAL,via = "resource")
   Resource child;

   public String getChildPath() {
      return child.getPath();
   }
}

Note: ChildResource is adaptable to resource,but in the above sample, adaptables is a request.So "via" attribute is used to tell the property that the property is supposed to be fetch via resource.
The Demonstration video on @ScriptVariable and @ChildResource annotation:


3.ValueMapValue: This injector is adaptable to resource.Through this injector,the properties of the resource can be directly injected in the sling models.
The attributes of the ValueMapValue is:
  • name
  • injectionStrategy
  • via

@Model(adaptables = Resource.class)
public class TestModel {
   // Injects Resource and get ValueMap from the resource
   @SlingObject
   Resource resource;

   public String getTitle() {
       ValueMap valueMap = resource.adaptTo(ValueMap.class);
       return valueMap.get(“title”, String.class);
   }
}

In place of adapting valueMap from the resource and getting title from valueMap,we can directly use ValueMapValue annotation in sling models.
@Model(adaptables = Resource.class)
public class TestModel {
   // Injects title from ValuMapValue
   @ValueMapValue
   String title;

   public String getTitle() {
       return title;
   }
}
resourcePath2.png
Fig - Value Map Sample

The ValueMapValue annotation using its attributes:
@Model(adaptables = SlingHttpServletRequest.class)
public class Test {
  // Injects title from ValuMap annotation using its attributes
  @ValueMapValue(name = "title",via = "resource",injectionStrategy = InjectionStrategy.REQUIRED)
   String pageTitle;

   public String getTitle() {
       return pageTitle;
   }
}


4.ResourcePath:
➤ If a resource is having a property whose value is a path, you can directly use that property as a resource.
You can directly inject a path as a resource using this annotation.

The attributes of the ResourcePath annotation is:
  • name
  • injectionStrategy
  • path
  • paths[]

@Model(adaptables = Resource.class )
public class TestModel {
 
  //directly inject a path as a resource
   @ResourcePath(path = ”/etc/social”)
   Resource pathResource;

@ResourcePath(name = "path")
   Resource resourcePath;
   @ResourcePath(paths = {"/etc/social","/etc/tags"})
   Resource[]  paths;
}
resourcePath.PNG
Fig - Get the Resource by passing the path dynamically in sling model

5. OSGiService: If we need to inject OSGiService in Sling Models, we can use it like this:

@Model(adaptables = Resource.class)
public class TestModel {
   @OSGiService
   SlingSettings slingSetttings;
}

The Demonstration video on @ValueMapValue, @ResourcePath and @OSGiService annotations:


6. SlingObject: Supports sling based Objects like request,response, ResourceResolver, Resource and Sling ScriptHelper.

@Model(adaptables = SlingHttpServletRequest.class)
public class TestModel {
 
   @SlingObject
   Resource resource;

   @SlingObject
   ResourceResolver resourceResolver;
}

7.Self:
Injects the adaptable object itself.
An object that can be adapted from it if self annotation is present.

The only attribute in Self annotation is injectionStrategy.

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

   @Self
  Node node;

   public String getNodePath() throws RepositoryException
  {
      return node.getPath();
  }
}

8. Request Attributes: When there are input parameters while initializing the sling model , and you want to get these parameters in the sling model, you can use this annotation.

The attributes of RequestAttribute annotation are:
  • name
  • injectionStrategy

@Model(adaptables = SlingHttpServletRequest.class)
public class TestModel {
  
   //Injects all the input parameters from sightly  injects as RequestAttribute in Sling Models
   @RequestAttribute(name = "color")
   String param;

public String getParam() {
      return param;
  }
}

The sightly script calls the sling Model using input parameter :
<div data-sly-use.example="${'com.sling.models.core.models.TestModel ’ @ color='red'}">
       ${example.param}<br/>
</div>
The Demonstration video on @SlingObject, @Self and @RequestAttribute annotations:




If you have any query or suggestion then kindly comment or mail us at sgaem.blog02@gmail.com

Hope it will help you guys !!
Thanks and Happy Learning.

17 comments:

  1. Wow.. didnt know so many different flavors in sling model. Always used to experiment first time and simply copy paste for following years. This helps to explore and try out other options. Thanks for sharing.

    ReplyDelete
  2. Great information. Thanks for your great work.

    ReplyDelete
  3. Nicely explained.. Thanks for sharing this.. :)

    ReplyDelete
  4. Congratulations, the article explains all different options in a simple way, provides examples and also demonstrates in video 10/10

    ReplyDelete
  5. Thanks to all for your lovely comments. These comments are my motivation to write more and better.

    ReplyDelete
  6. Well articulated. Thanks for your innovative thinking & contributions here. All the Best!

    ReplyDelete
  7. Best article and content that I have ever read very well explained.

    ReplyDelete
  8. Hi Shivani,

    Are you aware of any probable reason for sling model class not showing in sling adapters.

    ReplyDelete
    Replies
    1. Only one reason, you didn't follow the step 2 from blog of "How to create sling models".

      Delete
  9. Hi shivani

    Is it possible to share the package for this code?

    ReplyDelete
  10. Thanks a ton Shivani !

    ReplyDelete
  11. Thankyou Shivani for a wonderful article.

    ReplyDelete
  12. Your Article is help me a lot and tried with osgiservice annotation. but
    @osgiservice class return null object.Any probable reason behind this.

    ReplyDelete
  13. very short explanation like for @self annotation, didnt understand the use of that.

    ReplyDelete
  14. This is exactly I need.. thanks to clear my concept

    ReplyDelete
  15. Can you please share the package for the code?

    ReplyDelete