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


7 comments:

  1. Hi,
    I tried this code but got 404 error.All the bundles are active and AEM version is 6.2

    ReplyDelete
    Replies
    1. I hope you are using the correct URL to access the servlet - localhost:4502/services/categoryTest/Sampletitle/p/12345 (services should be pre-appended)

      Delete
    2. Yes ,used correct url.Bundle is active state.From error.log ,I got
      22.11.2017 12:12:01.906 *INFO* [127.0.0.1 [1511374321901] GET /services/categoryTest/Sampletitle/p/12345 HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Resource /services/categoryTest/Sampletitle/p/12345 not found

      Delete
  2. Hello, thank you for your tutorial.

    I also tried to follow the steps in AEM 6.3 and met the same issues as described by the first comment to this article.
    The bundles which I have installed in Apache Felix OSGI are the ones mentioned here in the article:
    - jersey-all
    - publisher
    - provider-security
    - provider-gson

    Additionally I faced some issues even with the "javax.ws.rs-api" dependency. Even though the "jersey-all" dependency has all the resource annotations like @Path and @GET which are in the sample code, my bundle could not resolve the dependency. I actually had to include the "javax.ws.rs-api" in the "Embed-Dependency" configuration of the "maven-bundle-plugin" to resolve it.

    It would also be great if you could provide a sample code using the OSGI service annotations instead of the Apache Felix annotations. You can find more about that topic here:
    http://blogs.adobe.com/experiencedelivers/experience-management/osgi/using-osgi-annotations-aem6-2/

    ReplyDelete
  3. Regarding the 404 issue there are some *DEBUG* log entry in the log files of AEM:

    15.12.2017 14:28:59.538 *DEBUG* [qtp2021446402-1235] org.glassfish.jersey.server.ServerRuntime$Responder Starting mapping of the exception.
    javax.ws.rs.NotFoundException: HTTP 404 Not Found
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:323)
    ...

    15.12.2017 14:28:59.538 *DEBUG* [qtp2021446402-1235] org.glassfish.jersey.server.ServerRuntime$Responder WebApplicationException (WAE) with no entity thrown and no ExceptionMappers have been found for this WAE. Response with status 404 is directly generated from the WAE.
    javax.ws.rs.NotFoundException: HTTP 404 Not Found
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:323)
    ...
    15.12.2017 14:28:59.539 *TRACE* [qtp2021446402-1235] org.glassfish.jersey.process.internal.RequestScope [DEBUG] Released scope instance Instance{id=4d39bb2b-cbc5-4e38-bdfd-9f9ec32ab005, referenceCounter=0, store size=0} on thread qtp2021446402-1235


    ReplyDelete
  4. Updated the post with additional details and sample code.

    ReplyDelete
  5. Thank you, the sample project you provided worked for me now. I think what I was missing was the "javax.inject" dependency.

    ReplyDelete