ch.entwine.weblounge.common.impl.content.page.AbstractRenderer.java Source code

Java tutorial

Introduction

Here is the source code for ch.entwine.weblounge.common.impl.content.page.AbstractRenderer.java

Source

/*
 *  Weblounge: Web Content Management System
 *  Copyright (c) 2003 - 2011 The Weblounge Team
 *  http://entwinemedia.com/weblounge
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software Foundation
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

package ch.entwine.weblounge.common.impl.content.page;

import ch.entwine.weblounge.common.Times;
import ch.entwine.weblounge.common.content.RenderException;
import ch.entwine.weblounge.common.content.Renderer;
import ch.entwine.weblounge.common.impl.content.GeneralComposeable;
import ch.entwine.weblounge.common.impl.language.LanguageUtils;
import ch.entwine.weblounge.common.impl.request.SiteRequestWrapper;
import ch.entwine.weblounge.common.language.Language;
import ch.entwine.weblounge.common.request.RequestFlavor;
import ch.entwine.weblounge.common.request.WebloungeRequest;
import ch.entwine.weblounge.common.request.WebloungeResponse;
import ch.entwine.weblounge.common.site.Site;
import ch.entwine.weblounge.common.url.UrlUtils;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletResponse;

/**
 * Thread safe base implementation for <code>PageTemplate</code>s and
 * <code>PageletRenderer</code>s.
 */
public abstract class AbstractRenderer extends GeneralComposeable implements Renderer {

    /** The logging facility */
    private static final Logger logger = LoggerFactory.getLogger(AbstractRenderer.class);

    /** Renderer URLs by type */
    protected Map<String, URL> renderers = new HashMap<String, URL>(5);

    /** The supported flavors */
    protected Set<RequestFlavor> flavors = new HashSet<RequestFlavor>();

    /**
     * Creates a renderer with a recheck time of one day and a valid time of one
     * week.
     */
    public AbstractRenderer() {
        super(Times.MS_PER_HOUR, Times.MS_PER_WEEK);
    }

    /**
     * Creates a renderer with a recheck time of one day and a valid time of one
     * week.
     * 
     * @param identifier
     *          the renderer identifier
     */
    public AbstractRenderer(String identifier) {
        this(identifier, null);
    }

    /**
     * Creates a renderer with a recheck time of one day and a valid time of one
     * week.
     * 
     * @param identifier
     *          the renderer identifier
     * @param renderer
     *          url of the renderer
     */
    public AbstractRenderer(String identifier, URL renderer) {
        super(identifier, Times.MS_PER_HOUR, Times.MS_PER_WEEK);
        this.renderers.put(RendererType.Page.toString().toLowerCase(), renderer);
    }

    /**
     * Adds the given flavor to the list of supported flavors.
     * 
     * @param flavor
     *          the supported flavor
     * @see RequestFlavor
     */
    public void addFlavor(RequestFlavor flavor) {
        if (flavor == null)
            throw new IllegalArgumentException("Flavor must not be null");
        flavors.add(flavor);
    }

    /**
     * Removes the specified flavor from the list of supported flavors.
     * 
     * @param flavor
     *          the flavor
     */
    public void removeFlavor(RequestFlavor flavor) {
        if (flavor == null)
            throw new IllegalArgumentException("Flavor must not be null");
        flavors.remove(flavor);
    }

    /**
     * {@inheritDoc}
     * 
     * @see ch.entwine.weblounge.common.content.Renderer#getFlavors()
     */
    public RequestFlavor[] getFlavors() {
        return flavors.toArray(new RequestFlavor[flavors.size()]);
    }

    /**
     * {@inheritDoc}
     * 
     * @see ch.entwine.weblounge.common.content.Composeable#supportsFlavor(java.lang.String)
     */
    public boolean supportsFlavor(RequestFlavor flavor) {
        return flavors.contains(flavor);
    }

    /**
     * {@inheritDoc}
     * 
     * @see ch.entwine.weblounge.common.content.Renderer#setRenderer(java.net.URL)
     */
    public void setRenderer(URL renderer) {
        addRenderer(renderer, RendererType.Page.toString());
    }

    /**
     * {@inheritDoc}
     * 
     * @see ch.entwine.weblounge.common.content.Renderer#addRenderer(java.net.URL,
     *      java.lang.String)
     */
    public void addRenderer(URL renderer, String type) {
        if (renderer == null)
            throw new IllegalArgumentException("Renderer must not be null");
        if (StringUtils.isBlank(type))
            throw new IllegalArgumentException("Type must not be blank");
        this.renderers.put(type.toLowerCase(), renderer);
    }

    /**
     * {@inheritDoc}
     * 
     * @see ch.entwine.weblounge.common.content.Renderer#getRenderer()
     */
    public URL getRenderer() {
        return getRenderer(RendererType.Page.toString());
    }

    /**
     * {@inheritDoc}
     *
     * @see ch.entwine.weblounge.common.content.Renderer#getRenderer(java.lang.String)
     */
    public URL getRenderer(String type) {
        if (StringUtils.isBlank(type))
            throw new IllegalArgumentException("Type must not be blank");
        return renderers.get(type.toLowerCase());
    }

    /**
     * Convenience implementation for JSP renderer. The <code>renderer</code> url
     * is first looked up using the available language information from request
     * and site. Then it is included in the response.
     * 
     * @param request
     *          the request
     * @param response
     *          the response
     * @param renderer
     *          the renderer
     * @throws RenderException
     *           if an error occurs while rendering
     */
    protected void includeJSP(WebloungeRequest request, WebloungeResponse response, URL renderer)
            throws RenderException {

        Site site = request.getSite();
        Language language = request.getLanguage();
        File jsp = null;

        try {
            if ("file".equals(renderer.getProtocol())) {
                // Find the best match for the template
                String[] filePaths = LanguageUtils.getLanguageVariants(renderer.toExternalForm(), language,
                        site.getDefaultLanguage());
                for (String path : filePaths) {
                    logger.trace("Looking for jsp {}", path);
                    File f = new File(path);
                    if (f.exists()) {
                        logger.debug("Found jsp at {}", path);
                        jsp = f;
                        break;
                    }
                }

                // Did we find a suitable JSP?
                if (jsp == null) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    throw new RenderException(this, "No suitable java server page found for " + renderer
                            + " and language '" + language.getIdentifier() + "'");
                }

                // Check readability
                if (!jsp.canRead()) {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN);
                    throw new RenderException(this, "Java server page at " + jsp + " cannot be read");
                }

                // No directory listings allowed
                if (!jsp.isFile()) {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN);
                    throw new RenderException(this, "Java server page at " + jsp + " is not a file");
                }

                renderer = jsp.toURI().toURL();
            }

            // Prepare a request to site resources
            String servletPath = "/weblounge-sites/" + site.getIdentifier();
            String requestPath = renderer.getPath();
            requestPath = requestPath.substring(servletPath.length());
            requestPath = UrlUtils.concat(Site.BUNDLE_PATH, requestPath);
            SiteRequestWrapper siteRequest = new SiteRequestWrapper(request, requestPath, false);

            RequestDispatcher dispatcher = request.getRequestDispatcher(servletPath);
            if (dispatcher == null)
                throw new IllegalStateException("No dispatcher found for site '" + site + "'");

            // Finally serve the JSP
            logger.debug("Including jsp {}", renderer);
            dispatcher.include(siteRequest, response);

            response.getWriter().flush();
        } catch (IOException e) {
            logger.error("Exception while including jsp {}", renderer, e);
        } catch (Throwable t) {
            throw new RenderException(this, t);
        }
    }

}