Monday, January 16, 2023

How are Sling Models resolved to a specific implementation?

 

Sling Models are annotation-driven Java "POJO's" (Plain Old Java Objects) that facilitate the mapping of data from the JCR to Java variables and provide several other niceties when developing in the context of AEM. When you adapt to a sling model, the model factory returns the specific model implementation; the returned model implementation is selected through the model pickers.

Photo by Clément Hélardot on Unsplash

In this post, let us dive deep into how this model picking works internally.

The Sling Model Framework has the Implementation Picker to select the specific model implementation.

The Implementation Picker interface can be referred to here — ImplementationPicker (Apache Sling 8 API); the picker interface is enabled with a picker method responsible for selecting a specific model implementation.

The Sling Framework, by default, has the below picker implementations.

First Implementation Picker:

This is the default picker implementation; it picks the first implementation from the list alphabetically ordered by class name. If there are multiple implementations of the specific models, this one selects the first one and returns it to the requestor. First Implementation Picker will be used if no other implementations support picking the model implementation.

The service ranking is set to the highest (Integer.MAX_VALUE) to support more custom picker implementations.

Resource Type-Based Resource Picker:

This picks the specific model implementation based on the resource type. This picker's ranking is 0 to ensure this comes before First Implementation Picker.

The AEM core components have their picker implementation to pick the latest version of a model implementation for a specific model.

Latest Version Implementation Picker:

This picks the specific model implementation based on the resource type and the model version —Picks the latest model version of a core component model based on the version information in the package name. The ranking for this picker is specified as 1 to ensure this comes after the Resource Type Based Resource Picker.

All the core components reference the model interface directly — com.adobe.cq.wcm.core.components.models.Carousel; the model implementations are always enabled with a specific version, so the Resource Type Based Resource Picker will not pick any model implementation, and the picking is delegated to the Latest Version Implementation Picker, and this always returns the latest model implementation based on the version number — e.g., com.adobe.cq.wcm.core.components.internal.models.v1.CarouselImpl).

The External models that implement Core Component interfaces have precedence over internal models, allowing us to enable model delegation for the core components.

The custom picker implementation can be enabled by implementing the org.apache.sling.models.spi.ImplementationPicker interface and picker method with your custom model picker logic; the ranking should be enabled accordingly to ensure the default implementations are not impacted.



Friday, November 24, 2017

Rewrite Rules with PT(Pass Through) Flag is not working in AEM Dispatchers - Adobe Experience Manager(AEM)

Rewrite Rules with PT(Pass Through) Flag is not working in AEM Dispatchers - Adobe Experience Manager(AEM)

How to define SEO/User friendly URL's in Adobe Experience Manager(AEM)


The Rewrite Rules with PT Flag helps us to define the SEO/User friendly URL's by hiding the internal URL's.

Let consider a scenario - The product URL should be rewritten to SEO/User friendly URL.

The internal product URL is - /en/test/pdp/book.html?id=123, this URL is not SEO/User friendly as the title of the the product is not part of the URL

The URL should be rewritten to /en/test/Sample_Book/book/pdp.html?id=123 internally without changing the Browser URL

Rewrite_Rule_with_PT_flag



Sunday, November 5, 2017

java.lang.ClassCastException for the same class com.sample.test.Test cannot be cast to com.sample.test.Test - Adobe Experience Manager(AEM)

java.lang.ClassCastException for the same class com.sample.test.Test cannot be cast to com.sample.test.Test - Adobe Experience Manager(AEM)

We were facing a strange ClassCastException - ClassCastException pointing to the same class in Adobe Experience Manager(AEM)

java.lang.ClassCastException: com.sample.test.Test cannot be cast to com.sample.test.Test

While analyzing through depfinder - http://localhost:4502/system/console/depfinder, there is two version of the same class available from two different packages.

But this class is only defined in one of the package and referred in the other package, after analyzing the Sling class loading is little different - If one of the class com.sample.test.Test is referred from different package, Sling copies the classes locally to the target package and if the target package export the same package(<Export-Package>) -  com.sample.* then Sling export the classes copied from other package that matches the export pattern, in this case our target package is already exporting com.sample.* so two version of same class is available now. This will lead to the ClassCastException specified above.

To fix this issue, we can change the target package pom.xml file to restrict the export of referred classes from other package.

<Export-Package>com.sample.*,!com.sample.test</Export-Package>

Please make sure the restricted package - !com.sample.test is kept after the wider package - com.sample.*

Now only one version of the class from source package is available for reference.


Wednesday, July 5, 2017

Exposing the AEM resources through OAuth - Adobe Experience Manager(AEM)

Exposing the AEM resources through OAuth - Adobe Experience Manager(AEM)

This post will explain the approach to expose the resources through OAuth in Adobe Experience Manager(AEM).

Refer https://www.albinsblog.com/2017/05/how-to-get-basic-profile-details-of-user-through-oauth.html for the basic configurations to expose the the resources thorough OAuth.

Exposing /etc/designs/geometrixx/static.css through OAuth

Configure the "Allowed Scope" as "/etc/designs/geometrixx"(based on the resource that should be exposed) in "Adobe Granite OAuth Resource Server"


The OAuth Authentication handler is not enabled by default and it looks to be an product defect.




Monday, May 29, 2017

How to expose Regex based rest service in Adobe Experience Manager( AEM)

How to expose Regex based rest service in Adobe Experience Manager(AEM)

This post will explain the approach to expose the regex based rest service in Adobe Experience Manager(AEM). By default OSGI will not support exposing regex based rest services and it will only support the services based on the specified Path or Resource Type.

Install OSGI JAX-RS connector:

Install(/system/console/bundles) jersey-all, publisher, provider-security and other required bundles e.g. provider-gson for JSON support and make sure the bundles are in Active state.

The bundles(jar) can be downloaded from following URL - http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.eclipsesource.jaxrs%22

com.eclipsesource.jaxrs-bundles

Develop the Servlet with required path mapping:

>=AEM 6.2

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.osgi.service.component.annotations.Component;

@Component(service = RegexServlet.class)
@Path("/{catagroy}/{title}/p/{code : \\d{5}}")
public class RegexServlet {

  @GET
  @Produces({MediaType.TEXT_PLAIN})
  public String getProductDetails(@Context HttpServletRequest request, @Context HttpServletResponse response,@PathParam("catagroy") String catagroy,@PathParam("title") String title,@PathParam("code") String code) {

    return "code="+code+";catagroy="+catagroy+";title="+title;

    }
}

< AEM 6.2

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import javax.ws.rs.Path;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Service(RegexServlet.class)
@Component(metatype = false)
@Path("/{catagroy}/{title}/p/{code : \\d{5}}")
public class RegexServlet {

 @GET
 @Produces({MediaType.TEXT_PLAIN})
public String getProductDetails(@Context HttpServletRequest request, @Context HttpServletResponse response,@PathParam("catagroy") String catagroy,@PathParam("title") String title,@PathParam("code") String code) {

   return "code="+code+";catagroy="+catagroy+";title="+title;

    }
}

Add the following dependency in POM.xml

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.0</version>
</dependency>

Install the package and make sure the core bundle status is active.

Verify whether the RegexServlet service is registered in system console

JAX-RS_Servlet

The servlet will accept the request with matching pattern - the servlet path should be starting with /services

The Path Regex pattern specified in the servlet will match for the following URL  - localhost:4502/services/categoryTest/Sampletitle/p/12345 (Code should be 5 digit)

Download the sample code -https://gitlab.com/albinsblog-data/RegexServlet/tree/master (Refer com.regex.servlet.core.RegexServlet.java in core module)
The sample code is tested in AEM 6.3 but it should be working in 6.2