April 26, 2020
Estimated Post Reading Time ~

Sling Models in AEM

We used to develop back-end login to components either by using WCMUse or WCMUsePojo or even JSP. With the release of AEM 6.3 and AEM Core WCM Components, we see that using Sling Models have been advocated by Adobe as the best practice. Now let’s take a look how we can use Sling Models.

You can work with Sling Models when developing with Adobe Experience Manager (AEM). That is, when developing an AEM project, you can define a model object (a Java object) and map that object to Sling resources. For more information, see Sling Models.

A Sling Model is implemented as an OSGi bundle. A Java class located in the OSGi bundle is annotated with @Model and the adaptable class (for example, @Model(adaptables = Resource.class). The data members (Fields) use @Inject annotations. These data members map to node properties.

Create UserDetails.java POJO class
package com.test.core.sling.model;

/*
 * Author: Kishore Polsani
 * Date: 02-JUN-2017
 */
import javax.inject.Inject;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model; 

@Model(adaptables = Resource.class)
public class UserDetails {
    @Inject
    private String firstName;
    
    @Inject
    private String lastName;
    
    public String getFirstName(){
        return firstName;
    }
    public String getLastName(){
        return lastName;
    }
}

SlingModel class
Add a Java file to the com.kishore.core.sling.model package named SlingModels. The Java class that you create in this section extends the Java class named org.apache.sling.api.servlets.SlingAllMethodsServlet. This class is required to define an AEM Sling Servlet. For information, see Class SlingAllMethodsServlet.

The SlingModels class uses the following Sling Servlet annotation:
@SlingServlet(paths="/services/kishore/slingModel", methods="GET")
Notice that this servlet is defined as a GET. Later in this development article, an AJAX GET operation is used to invoke this operation. 

package com.test.core.sling.model;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;

import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SlingServlet(paths="/services/kishore/slingModel",methods="GET")
public class SlingModels extends SlingAllMethodsServlet{
    private static final long serialVersionUID =1L;
    Logger logger = LoggerFactory.getLogger(SlingModels.class);
    @Reference
    ResourceResolverFactory resourceResolverFactory;
    
    public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException{
        logger.info("inside sling model test servlet");
        response.setContentType("text/html");
        Map<String, Object> param = new HashMap<String, Object>();
        param.put(ResourceResolverFactory.SUBSERVICE,"datawrite");
        ResourceResolver resolver = null;
        
        try {
            //resourceResolver = resourceResolverFactory.getAdministrativeResourceResolver(null);
            resolver = resourceResolverFactory.getServiceResourceResolver(param);
            
            Resource resource = resolver.getResource("/content/testsling/slingmodel");
            
            ValueMap valueMap=resource.adaptTo(ValueMap.class);
            
            response.getWriter().write("Output from ValueMap is First Name: "+valueMap.get("firstName").toString()+" Last Name: "+valueMap.get("lastName").toString());
            com.kishore.core.sling.model.UserDetails userObj= resource.adaptTo(com.kishore.core.sling.model.UserDetails.class);
            response.getWriter().write("\n Output from ValueMap is First Name: "+userObj.getFirstName()+" Last Name: "+userObj.getLastName());
            
            logger.info("First Name: "+userObj.getFirstName());
            logger.info("Last Name: "+userObj.getLastName());
        } catch (LoginException e) {
            e.printStackTrace();
        }
        
    }

}

In the previous code example, notice that a Resource instance is created by referencing an AEM node:
Resource resource = resourceResolver.getResource("/content/testsling/slingmodel");
Then the Resource object's adaptTo method is used to create an com.kishore.core.sling.model.UserDetails object:
com.kishore.core.sling.model.UserDetails userObj= resource.adaptTo(com.kishore.core.sling.model.UserDetails.class);
This is possible because Sling Model annotations are used in the UserDetails class. Finally this servlet returns the value of the UserInfo object.
response.getWriter().write("Output from Sling Model is First Name: "+userObj.getFirstName()+" Last Name: "+userObj.getLastName());

Note:
The return value of this servlet is displayed within an AEM page.
Add below code in bundle pom.xml
<configuration>
    <instructions>
        <Bundle-SymbolicName>com.kishore.com.kishore</Bundle-SymbolicName>
         <Sling-Model-Packages>
         com.lazybones.sling.models,
         com.kishore.core.sling.model
        </Sling-Model-Packages>
    </instructions>
</configuration>

Add below dependencies in pom.xml
<dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.models.api</artifactId>
            <version>1.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
    <groupId>org.apache.sling</groupId>
    <artifactId>org.apache.sling.api</artifactId>
    <version>2.7.0</version>
    <scope>provided</scope>
</dependency>

Create a component and add below code
<%@include file="/libs/foundation/global.jsp" %>
     <html>
    <head>
        <meta charset="UTF-8">
        <title>Kishore AEM Sling Model Page</title>
        <style>
            body {
                background-color: lightgray
            }
            h1 {
                color: red
            }
            p {
                color: green
            }
        </style>
        </style>
        <script>
            $(document).ready(function() {

                $('body').hide().fadeIn(5000);

                $('#submit').click(function() {
                    var failure = function(err) {
                        alert("Unable to retrive data " + err);
                    };

                    //Use JQuery AJAX to perform a GET to the AEM Sling Servlet that uses Sling Models
                    $.ajax({
                        type: 'GET',
                        url: '/services/kishore/slingModel',
                        success: function(msg) {
                            $('#json').val(msg);
                        }
                    });
                });

            }); // end ready
        </script>
    </head>

    <body>
        <
        </div>
        <form method="#">
            <table border="1" align="left">
                <tr>
                    <td></td>
                    <td>
                        <textarea id="json" rows="15" cols="50">
                        </textarea>
                    </td>
                </tr>
                <tr>
                    <td></td>
                    <td>
                        <input type="button" value="Get Sling Model Data" name="submit" id="submit">
                    </td>
                </tr>
            </table>
        </form>
    </body>
    </html>


References:
https://sling.apache.org/documentation/bundles/models.html


By aem4beginner

No comments:

Post a Comment

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