Thursday, September 6, 2018

Adobe Experience Manager(AEM) On-Premises to Adobe Managed Service(AMS) Cloud Migration

Adobe Experience Manager(AEM) On-Premises to Adobe Managed Service(AMS) Cloud Migration

This post explains the different things that should be considered while migrating On-Premises Adobe Experience Manager(AEM) platform to the AWS cloud managed through AMS.

AMS cloud migration provides lot of benefits -

  • Extend the server capacity based on the demand
  • Quick spinning up of new servers
  • Less management and initial setup cost
  • Better security and monitoring of platform
  • Streamlined process
  • Higher availability

We have to consider this option based on the how much control we require on the production environment - AMS environments will be restricted for client access.


Below are some of the important items need attention while migrating the On-Premises AEM platform to AMS Cloud.

Deployment options:

There is different deployment options available based on the SLA


Tuesday, September 4, 2018

How to use Luke(Lucene Index Toolbox) to analyze Lucene Index in AEM(Adobe Experience manager)

How to use Luke(Lucene Index Toolbox) to analyze Lucene Index in AEM(Adobe Experience manager)

This post will explain the details on analyzing the created Lucene index in AEM(Adobe Experience Manager)

Retrieve the Lucene Index:

By default in Oak the Lucene Index files are stored in NodeStore and will not be accessible directly but if the following configurations("Enable CopyOnRead" or "Enable CopyOnWrite" ) are enabled in "Apache Jackrabbit Oak LuceneIndexProvider" the Lucene Index will be copied to Local files system path, If the "Local index storage path" not specified then indexes would be stored under 'index' dir under Repository Home (localIndexDir)




If the index is copied to loacl file system this can be directly accessed,the index is stored in the file name starts with segments

The mapping between local path and the index can be found here - localhost:4502/system/console/jmx/org.apache.jackrabbit.oak%3Aname%3DIndexCopier+support+statistics%2Ctype%3DIndexCopierStats(this URL will available only if the above mentioned properties are enabled)


The below steps can be be followed to retrieve the indexing files if the index files are not stored in local.

Download oak-run-x.x.x.jar that corresponds to AEM Oak version, the AEM Oak version can be identified from CRXDE(the oak-run version 1.4.1 was not working and i downloaded 1.8.0 version -

Execute java -jar oak-run-1.8.0.jar index <Node Store Path> e.g. java -jar oak-run-1.8.0.jar index C:\Albin\Development\AEM\6.2\crx-quickstart\repository\segmentstore to identify the available indexes, the index stats and index definitions under the folder from where the command is executed

The index is stored in the file name starts with segments


The indexing status and the definitions can be accessed from the following URL also - http://localhost:4502/system/console/jmx/org.apache.jackrabbit.oak%3Aname%3DLucene+Index+statistics%2Ctype%3DLuceneIndex

Friday, August 17, 2018

How to Enable Cross Origin Resource Sharing(CORS) support in AEM(Adobe Experience Manager)

How to Enable Cross Origin Resource Sharing(CORS) support in AEM(Adobe Experience Manager)

Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served.

Sometimes we may have scenarios to expose the AEM services to be invoked from cross origins, this post explains the different approaches to enable the Cross Origin Resource Sharing Supports.

The CORS support is introduced OOB in AEM 6.3 version, refer for more details.

Enabling CORS for older AEM versions(<6.3)

The request is failed with below exception in browser console while trying to invoke cross origin(service hosted in different domains) services through Ajax.

"Failed to load http://localhost:4503/bin/sampleJSONPService: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access".

There are two approaches to enable the Cross Origin Requests

  • CORS Headers


JSONP stands for JSON with Padding, JSONP is a method for sending JSON data without worrying about cross-domain issues.
JSONP supports only the GET request method, JSONP works on legacy browsers.

Enable the service to rerun the JSON response with Padding

   selectors = "json",
   paths = "/bin/sampleJSONPService",
   methods = "GET")
public class SimpleServlet extends SlingSafeMethodsServlet {

    protected void doGet(final SlingHttpServletRequest req,
            final SlingHttpServletResponse resp) throws ServletException, IOException {
    resp.setHeader("Content-Type", "application/json");
    resp.setHeader("X-Content-Type-Options", "");
    String callback=req.getParameter("callback");
    JSONObject response = new JSONObject();
    try {
response.put("test1", "testvalue1");
response.put("test2", "testvalue2");
response.put("test3", "testvalue3");
response.put("test4", "testvalue4");
} catch (JSONException e) {
    if(callback!=null && !callback.trim().equals("")) {
    resp.getWriter().write( callback + "("+response.toString()+ ")");

The above service return the JSON response with padding

Invoke the JSONP service from Ajax

  src=""  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="  crossorigin="anonymous">

Test Data (<span class="testData">Default</span>)

var dataUrl = 'http://localhost:4503/bin/sampleJSONPService.json?callback=?';

url: dataUrl,
dataType: 'jsonp',
success: function(data) {

This will provide the response without any issue


CORS Headers

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin. CORS also supports other types(other than GET) of HTTP requests, CORS is supported by most modern web browsers.

The Access-Control-Allow-Origin response header indicates whether the response can be shared with resources with the given origin.

Access-Control-Allow-Origin "*"   supports the Cross Origin requests from all domains
Access-Control-Allow-Origin "" supports Cross Origin requests only from

Enabling Access-Control-Allow-Origin header

The header can be enabled directly in the service response or thorough apache configuration

Though Service response - Add Access-Control-Allow-Origin header with required value in the service response

   selectors = "json",
   paths = "/bin/sampleJSONPService",
   methods = "GET")
public class SimpleServlet extends SlingSafeMethodsServlet {
    protected void doGet(final SlingHttpServletRequest req,
            final SlingHttpServletResponse resp) throws ServletException, IOException {

Monday, July 9, 2018

How to display custom site specific error(404,403 and 500) pages in multi site Adobe Experience Manager(AEM) setup?

How to display custom site specific error(404,403 and 500) pages in multi site Adobe Experience Manager(AEM) setup?

This post explains the approach to handle custom site specific error handling for Adobe Experience Manager(AEM) sites in a multi site environment

Sling Model to identify the error page:

Create a Sling model in core module withe the below code - This will help to identify the site specific error page path specific to the error code.

package com.errorhandler.core.models;


import javax.annotation.PostConstruct;
import javax.inject.Inject;

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

    private static final String DEFAULT_ERROR_PAGE = "/content/geometrixx-outdoors";
    private static final String ERROR_CODE_404 = "404";
    private static final int MAX_DEPTH = 2;
    private static final String PATH_SEPERATOR = "/";

    private SlingHttpServletRequest slingRequest;

    @Default(values = ERROR_CODE_404)
    private String errorCode;

    private String pagePath;
    protected void init() {
    pagePath = DEFAULT_ERROR_PAGE + errorCode;
        final String requestURI = slingRequest.getRequestPathInfo().getResourcePath();
        if (requestURI!=null && !requestURI.equals("")) {
          pagePath = getErrorPageFromRequestedUrl(errorCode, requestURI);

    private String getErrorPageFromRequestedUrl(final String errorCode, final String requestURI) {
        final Page resolvedPage = getPageFromPath(requestURI);
        if (resolvedPage != null) {
            return getErrorPathFromPage(errorCode, resolvedPage);
        return null;

    private Page getPageFromPath(String requestURI) {
        final PageManager pageManager = slingRequest.getResourceResolver().adaptTo(PageManager.class);
        while (requestURI.contains(PATH_SEPERATOR)) {
            Page page = pageManager.getContainingPage(requestURI);
            if (page != null) {
                return page;
            } else {
                requestURI = requestURI.substring(0, requestURI.lastIndexOf(PATH_SEPERATOR));
        return null;

    private String getErrorPathFromPage(final String errorCode, final Page resolvedPage) {
    if (resolvedPage.hasChild(errorCode)) {
        return resolvedPage.getPath() + PATH_SEPERATOR + errorCode;
        if (resolvedPage.getParent() != null && resolvedPage.getDepth() >= MAX_DEPTH) {
            return getErrorPathFromPage(errorCode, resolvedPage.getParent());
        return null;

    public String getPagePath() {
        return pagePath;

Configure the DEFAULT_ERROR_PAGE(the content folder in which the default 404, 403 and 500 error pages are available) in the above code  - the error pages that will be displayed if the the site specific 404, 403 and 500 pages are missing.
Add the below instruction into core module pom.xml - to notify the package in which the sling models are available for registration



Configure Error Handlers:

Create 403.html, 404.html and Exception.html(error handler to handle all the Internal Server Exceptions) under /apps/sling/servlet/errorhandler


Add the below contents to 403.html, 404.html and Exception.html respectively


<sly data-sly-use.errorPage="${'com.errorhandler.core.models.ErrorHandlerRequestModel'@ errorCode='403'}"/>
<sly data-sly-resource="${errorPage.pagePath}.html"/>


<sly data-sly-use.responseStatus="">
    <sly data-sly-use.errorPage="${'com.errorhandler.core.models.ErrorHandlerRequestModel'@ errorCode='404'}"/>
    <sly data-sly-resource="${errorPage.pagePath}.html"/>


<sly data-sly-use.errorPage="${'com.errorhandler.core.models.ErrorHandlerRequestModel'@ errorCode='500'}"/>
<sly data-sly-resource="${errorPage.pagePath}.html"/>

Create under /apps/sling/servlet/errorhandler and add the below content


import com.adobe.cq.sightly.WCMUse;

public class ResponseStatus extends WCMUse {
    public void activate() throws Exception {

Configure Error Pages:

Create site specific error files 403, 404 and 500(the files can be created in any level - the minimum depth should be 2 i.e under /content/sitename), the files will be taken based on the level where the exception occurred.


Exception directly under /content/geometrixx-outdoors consider the error pages under /content/geometrixx-outdoors
Exception under /content/geometrixx-outdoors/en consider the error pages under /content/geometrixx-outdoors/en

Configure the local error pages - 404, 403 and 500 for all the required sites.

Now the user will be displayed the corresponding error file content based on the error code.

This implementation has been tested in AEM 6.2 version.

Monday, July 2, 2018

HTTPS URL is resulting with 404 - Adobe Experience Manager

HTTPS URL is resulting with 404 - Adobe Experience Manager

Recently, we have faced the issue with https URL's, the URL's with masked path (/en/test.html) is not working with https protocol.

However, the unmasked (/content/site/en/test.html) URL is working, also http URL is working without any issues.

Based on our analysis, it looks to be the system is not honoring the /etc/map.publish/https mapping for https request and due to that the content path(without full path - /en/test.html) is not accessible and 404 is displayed

Our case the request is https from browser and the Load Balancer terminate the SSL and forward the request to dispatcher - Load Balancer notify the dispatcher that the initial request is https via header X-Forwarded-Proto (this header value differs based on the load balancer)

The dispatcher send the request to publisher with required headers and publisher consider the request as https based on the above header and match the Resource Mapping accordingly - /etc/map.publish/https

The 404 will be displayed for masked URL's if publisher not able to match the /etc/map.publish/https for incoming request.

How to resolve?


  • Match the SSL Filter settings to those expected from the entity where SSL is terminated (Load Balancer). You can check these values forwarded in the dispatcher.log file and make sure they match to those of the SSL Filter. Configure the SSL Filter (Apache Felix Http Service SSL Filter) in Publisher with SSL forward header and value

  • Allow the following headers in dispatcher farm file /clientheaders section, if /clientheaders section is not set to allow all

          X-Forwarded-Proto (this header value change based on the Load balancer)
               - other known values X-FORWARDED-SSL, X-Forwarded-Protocol and Front-End-Https
  • White list the SSL headers mentioned above in CDN, if CDN is enabled in the flow.


Disallow the SSL forward headers in dispatcher farm file /clientheaders section; disallow the following header - X-Forwarded-Proto in /clientheaders section, review the "Apache Felix Http Service SSL Filter" in publisher to identify the exact header value used to identify the forwarded SSL request.

This allow the publisher to consider the request as http and match the /etc/map.publish/http node for incoming requests. 

In cases the SSL is terminated at the Web server, follow the below steps:

At the bottom of the httpd.conf add the following configuration: RequestHeader set X-Forwarded-Port "-1"

Allow the X-Forwarded-Port header in dispatcher farm file if /clientheaders section is not set to allow all