info.magnolia.cms.servlets.ResourceDispatcher.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.cms.servlets.ResourceDispatcher.java

Source

/**
 *
 * Magnolia and its source-code is licensed under the LGPL.
 * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
 * When copying, adapting, or redistributing this document in keeping with the guidelines above,
 * you are required to provide proper attribution to obinary.
 * If you reproduce or distribute the document without making any substantive modifications to its content,
 * please use the following attribution line:
 *
 * Copyright 1993-2006 obinary Ltd. (http://www.obinary.com) All rights reserved.
 *
 */
package info.magnolia.cms.servlets;

import info.magnolia.cms.Aggregator;
import info.magnolia.cms.core.HierarchyManager;
import info.magnolia.cms.core.NodeData;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

/**
 * Class ResourceDispatcher is responsible to gather data from the <strong>HttpServletRequest </strong> and write back
 * the requested resource on the <strong>ServletOutputStream </strong>.
 *
 * @author Sameer Charles
 * @version 1.0
 */
public class ResourceDispatcher extends HttpServlet {

    /**
     * Stable serialVersionUID.
     */
    private static final long serialVersionUID = 222L;

    /**
     * Logger.
     */
    private static Logger log = LoggerFactory.getLogger(ResourceDispatcher.class);

    /**
     * @param req HttpServletRequest as given by the servlet container
     * @param res HttpServletResponse as given by the servlet container
     * @throws IOException standard servlet exception
     */
    public void service(HttpServletRequest req, HttpServletResponse res) throws IOException {
        handleResourceRequest(req, res);
    }

    /**
     * Get the requested resource and copy it to the ServletOutputStream, bit by bit.
     *
     * @param req HttpServletRequest as given by the servlet container
     * @param res HttpServletResponse as given by the servlet container
     * @throws IOException standard servlet exception
     */
    private void handleResourceRequest(HttpServletRequest req, HttpServletResponse res) throws IOException {

        String resourceHandle = (String) req.getAttribute(Aggregator.HANDLE);
        if (log.isDebugEnabled()) {
            log.debug("handleResourceRequest, resourceHandle=\"" + resourceHandle + "\""); //$NON-NLS-1$ //$NON-NLS-2$
        }
        if (StringUtils.isNotEmpty(resourceHandle)) {
            HierarchyManager hm = (HierarchyManager) req.getAttribute(Aggregator.HIERARCHY_MANAGER);
            InputStream is = null;
            try {
                is = getNodedataAstream(resourceHandle, hm, res);
                if (null != is) {
                    // todo find better way to discover if resource could be compressed, implement as in "cache"
                    // browsers will always send header saying either it can decompress or not, but
                    // resources like jpeg which is already compressed should be not be written on
                    // zipped stream otherwise some browsers takes a long time to render
                    sendUnCompressed(is, res);
                    IOUtils.closeQuietly(is);
                    return;
                }
            } catch (IOException e) {
                // don't log at error level since tomcat tipically throws a
                // org.apache.catalina.connector.ClientAbortException if the user stops loading the page
                if (log.isDebugEnabled())
                    log.debug("Exception while dispatching resource  " + e.getClass().getName() + ": " //$NON-NLS-1$//$NON-NLS-2$
                            + e.getMessage(), e);
            } catch (Exception e) {
                log.error("Exception while dispatching resource  " + e.getClass().getName() + ": " + e.getMessage(), //$NON-NLS-1$//$NON-NLS-2$
                        e);
            } finally {
                IOUtils.closeQuietly(is);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("Resource not found, redirecting request for [" + req.getRequestURI() + "] to 404 URI"); //$NON-NLS-1$
        }

        if (!res.isCommitted()) {
            res.sendError(HttpServletResponse.SC_NOT_FOUND);
        } else {
            log.info("Unable to redirect to 404 page, response is already committed"); //$NON-NLS-1$
        }

    }

    /**
     * Send data as is.
     *
     * @param is  Input stream for the resource
     * @param res HttpServletResponse as received by the service method
     * @throws IOException standard servlet exception
     */
    private void sendUnCompressed(InputStream is, HttpServletResponse res) throws IOException {
        ServletOutputStream os = res.getOutputStream();
        byte[] buffer = new byte[8192];
        int read = 0;
        while ((read = is.read(buffer)) > 0) {
            os.write(buffer, 0, read);
        }
        os.flush();
        IOUtils.closeQuietly(os);
    }

    /**
     * @param path path for nodedata in jcr repository
     * @param hm   Hierarchy manager
     * @param res  HttpServletResponse
     * @return InputStream or <code>null</code> if nodeData is not found
     */
    private InputStream getNodedataAstream(String path, HierarchyManager hm, HttpServletResponse res) {
        if (log.isDebugEnabled()) {
            log.debug("getAtomAsStream for path \"" + path + "\""); //$NON-NLS-1$ //$NON-NLS-2$
        }
        try {
            NodeData atom = hm.getNodeData(path);
            if (atom != null) {
                if (atom.getType() == PropertyType.BINARY) {

                    String sizeString = atom.getAttribute("size"); //$NON-NLS-1$
                    if (NumberUtils.isNumber(sizeString)) {
                        res.setContentLength(Integer.parseInt(sizeString));
                    }
                }

                Value value = atom.getValue();
                if (value != null) {
                    return value.getStream();
                }
            }

            log.warn("Resource not found: [" + path + "]"); //$NON-NLS-1$ //$NON-NLS-2$

        } catch (PathNotFoundException e) {
            log.warn("Resource not found: [" + path + "]"); //$NON-NLS-1$ //$NON-NLS-2$
        } catch (RepositoryException e) {
            log.error("RepositoryException while reading Resource [" + path + "]", e); //$NON-NLS-1$ //$NON-NLS-2$
        }
        return null;
    }
}