April 1, 2020
Estimated Post Reading Time ~

How to use Sling Models in CQ5.6

Use Case: Use Sling Model in CQ5.6
Background: Sling model http://sling.apache.org/documentation/bundles/models.html brings powerful way of mapping your resources to Java Objects (Beans) . It is supported OOTB in CQ6 however we can use it in CQ5.6 as well.

Solution:
First add sling models as dependency in your code (In Parent pom using dependency manager is preferred)

<dependency>
    <groupId>org.apache.sling</groupId>
    <artifactId>org.apache.sling.models.api</artifactId>    <version>1.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.sling</groupId>    <artifactId>org.apache.sling.models.impl</artifactId>    
<version>1.1.0</version>
</dependency>

Then update your reactor pom (Which actually creates your CQ package using content-package-maven-plugin) you need to add the following as dependency and then embed them into your project (If install path for the system is not present you can use any other path you want)

<!--Add sling Model dependencies -->
<!-- All your existing dependencies -->
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apa
che.sling.models.impl</artifactId>
</dependency>

<!-- Your all build config using content-package-maven-plugin and then this -->
<embedded>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
<target>/apps/system/install</target>
</embedded>
<embedded>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.impl</artifactId>
<target>/apps/system/install</target>
</embedded>
<!-- All other things -->


Thats it .. Models are available as service in your OSGI environment.


To use model go ahead and create your own bundle and them add these as dependency. You should be able to write, deploy and run code against model. Note that you might have to make these model available to osgi using Sling-Model-Packages

<!-- All other configuration in your bundle pom -->

<plugin>
    <groupId>org.apache.felix</groupId>    <artifactId>maven-bundle-plugin</artifactId>    <extensions>true</extensions>    <configuration>    <instructions>    <Export-Package>com.myotherpackages</Export-Package>    <Sling-Model-Packages>com.allmymodelpackage</Sling-Model-Packages>    <Bundle-Category>sling-model-demo</Bundle-Category>    </instructions>    </configuration>
</plugin>


<!-- All other dependecies -->
<dependency>
    <groupId>org.apache.sling</groupId>    <artifactId>org.apache.sling.models.api</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.sling</groupId>    <artifactId>org.apache.sling.models.impl</artifactId>
</dependency>

Once model is deployed correctly you should be able to see them under sling-model tab in status in felix console or by going to HOST:PORT/system/console/status-slingmodels


Some example code using models
import javax.inject.Inject;
import javax.inject.Named;
import javax.jcr.Session;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;

/**
*
* @author Yogesh Upadhyay
*
*/
@Model(adaptables = { SlingHttpServletRequest.class, Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class CustomModel {

// If the field or method name doesn't exactly match the property name, @Named
// can be used:
@Inject
@Named("author")
private String authorPath;

// Can use default value
@Inject
@Default(values = "")
private String bodyText;

// Can inject Custom Sling Object which exactly match sling object name
// http://adobe-consulting-services.github.io/acs-aem-commons/features/aem-sling-models-injectors.html
@SlingObject
private Resource currentResource;

// Can inject custom Object
@Inject
private ResourceResolver resourceResolver;

//Inject a custom osgi service all available injector https://sling.apache.org/documentation/bundles/models.html#available-injectors
@Inject @Source("osgi-services")
private YourService yourService;

// This will return author property from current resource
// same as properties.get("author") from jsp
public String getAuthorPath() {
return this.authorPath;
}

// return body text property
public String getBodytext() {
return this.bodyText;
}

// Example of how you can use sling Injector
public String getResourcePath() {
return currentResource.getPath();
}

// Example of how you can use custom injector
public Session getSession() {
return this.resourceResolver.adaptTo(Session.class);
}

// There are many other cool things you can do with the sling model.
// more example http://sling.apache.org/documentation/bundles/models.html

}


Some common How to
How can I inject services in Sling Model by using annotation @OSGIService Or Using Injector @Inject @Source("osgi-service")

Example:
@OSGIService
MyService myService

@Inject @Source("osgi-service")
MyService myService

How Can I Inject Sling Object in Sling Model? 
by using annotation @SlingObject Or Using Injector @Inject @Source("sling-object")

Example:
@SlingObject
ResourceResolver resourceResolver

@Inject @Source("sling-object")
ResourceResolver resourceResolver

How Can I get access to property if adapting through Sling Request?
If you are adapting your model to sling request you might not have access to property by just doing @Inject. You have to use @Via in that case. Note that you can use all other annotation here like @Named and all. Here is example

@Model(adaptables=SlingHttpServletRequest.class) public interface MyModel {

@Inject @Via("resource") String propertyName; }


How Can I use Sling Tag Library with Sling Model?
You can use <sling:adaptTo ... /> or ${sling:adaptTo ...} as mentioned in https://sling.apache.org/documentation/bundles/models.html and https://sling.apache.org/documentation/bundles/sling-scripting-jsp-taglib.html .In 5.6 you might have to change global.jsp to use
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling" %>
instead of
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0" %>

How Can I provide default value to property in Sling ModelBy using @Default Annotation? 

Here is example
A default value can be provided (for Strings & primitives) and Array:

@Model(adaptables=Resource.class) public class MyModel { @Inject @Default(values="defaultValue") private String name;
@Inject @Default(intValues={1,2,3,4}) private int[] integers;
}

How Can I inject child resources as Model in Sling Model? 
This can be done by Injecting a model in other model class. Here is example

@Model(adaptables=Resource.class) public interface MyModel { @Inject ImageModel getImage(); } @Model(adaptables=Resource.class) public interface ImageModel { @Inject String getPath(); }

When a resource is adapted to MyModel, a child resource named image is automatically adapted to an instance of ImageModel

Note: Sling model version number can change as it evolves in the future. Make sure that you update the model dependencies version accordingly. You can also use the Sling testing framework to test the sling model which is pretty cool as well. There is also an example of a deployable Model package https://github.com/Adobe-Consulting-Services/com.adobe.acs.bundles.sling-models which you can use.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.