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 ErrorHandlerRequestModel.java 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 com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;

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 = "/";

    @Self
    private SlingHttpServletRequest slingRequest;

    @Inject
    @Default(values = ERROR_CODE_404)
    private String errorCode;

    private String pagePath;
 
    @PostConstruct
    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

<Sling-Model-Packages>com.errorhandler.core.models</Sling-Model-Packages>


<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>                   
<Import-Package>javax.inject;version=0.0.0,*</Import-Package>
<Sling-Model-Packages>com.errorhandler.core.models</Sling-Model-Packages>
</instructions>
</configuration>
</plugin>

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

aem-error-handler-scripts


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

403.html

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

404.html

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

Exception.html

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


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

package apps.sling.servlet.errorhandler;

import com.adobe.cq.sightly.WCMUse;

public class ResponseStatus extends WCMUse {
 
    @Override
    public void activate() throws Exception {
        getResponse().setStatus(404);
    }
}


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.

aem-site-specific-error-pages


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.


2 comments:

  1. How to test 500 and 403 error page ?

    ReplyDelete
  2. 403 - Remove access to specific page for your user ID
    500 - Any uncathed exceltion from service/model etc

    ReplyDelete