There might be a use case when we would want to handle errors at the component level. We would not want a single component throwing errors breaking the entire page. To handle such a situation in AEM, we can write a filter that does not let the component render on the page when it has errors.
Here is a sample example:
Here is a sample example:
@Component( label = "Component Level Error Handler", description = "Handles errors at the component level. Allows blank HTML renditions to display for erring in publish mode", metatype = true ) @Service public class ComponentErrorHandlerImpl implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(ComponentErrorHandlerImpl.class); static final String BLANK_HTML = ""; private static final boolean DEFAULT_PUBLISH_ENABLED = true; private boolean publishModeEnabled = DEFAULT_PUBLISH_ENABLED; @Property(label = "Publish Error Handling", description = "Enable handling of Edit-mode errors (PREVIEW and READONLY)", boolValue = DEFAULT_PUBLISH_ENABLED) public static final String PROP_PUBLISH_ENABLED = "publish.enabled"; static final String REQ_ATTR_PREVIOUSLY_PROCESSED = ComponentErrorHandlerImpl.class.getName() + "_previouslyProcessed"; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { { final SlingHttpServletRequest request = (SlingHttpServletRequest) servletRequest; final SlingHttpServletResponse response = (SlingHttpServletResponse) servletResponse; if (!this.accepts(request, response)) { chain.doFilter(request, response); return; } final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request; final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response; if (publishModeEnabled && WCMMode.DISABLED.equals(WCMMode.fromRequest(slingRequest)) && !this.isFirstInChain(slingRequest)) { // Publish Modes; Requires special handling in Published Modes - do not process first filter chain this.doFilterWithErrorHandling(slingRequest, slingResponse, chain, BLANK_HTML); } else { // Normal Behavior chain.doFilter(request, response); } } } private boolean isFirstInChain(final SlingHttpServletRequest request) { if (request.getAttribute(REQ_ATTR_PREVIOUSLY_PROCESSED) != null) { return false; } else { request.setAttribute(REQ_ATTR_PREVIOUSLY_PROCESSED, true); return true; } } private void doFilterWithErrorHandling(final SlingHttpServletRequest slingRequest, final SlingHttpServletResponse slingResponse, final FilterChain chain, final String pathToHTML) throws ServletException, IOException { try { chain.doFilter(slingRequest, slingResponse); } catch (final Exception ex) { // Handle error using the Component Error Handler HTML this.handleError(slingResponse, slingRequest.getResource(), pathToHTML, ex); } } private void handleError(final SlingHttpServletResponse slingResponse, final Resource resource, final String pathToHTML, final Throwable ex) throws IOException { // Log the error to the log files, so the exception is not lost LOGGER.error(ex.getMessage(), ex); // Write the html out to the response this.writeErrorHTML(slingResponse, resource, pathToHTML); } private void writeErrorHTML(final SlingHttpServletResponse slingResponse, final Resource resource, final String pathToHTML) throws IOException { LOGGER.info("Component-Level Error Handling trapped error for: {}", resource.getPath()); //print blank HTML slingResponse.getWriter().print(pathToHTML); } protected final boolean accepts(final SlingHttpServletRequest request, final SlingHttpServletResponse response) { try { if (!(request.getRequestURI().endsWith(".html")) || !(response.getContentType().contains("html"))) { // Do not inject around non-HTML requests return false; } } catch (NullPointerException e) { return false; } final ComponentContext componentContext = WCMUtils.getComponentContext(request); if (componentContext == null) { // ComponentContext is null return false; } else if (componentContext.getComponent() == null) { // Component is null return false; } else if (componentContext.isRoot()) { // Suppress on root context return false; } return true; } @Override public void destroy() { } @Activate public final void activate(final Map<String, String> config) { final String legacyPrefix = "prop."; publishModeEnabled = PropertiesUtil.toBoolean(config.get(PROP_PUBLISH_ENABLED), PropertiesUtil.toBoolean(config.get(legacyPrefix + PROP_PUBLISH_ENABLED), DEFAULT_PUBLISH_ENABLED)); } }
Hope this helps!
No comments:
Post a Comment