org.apache.roller.planet.ui.rendering.MultiPlanetRequestMapper.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.roller.planet.ui.rendering.MultiPlanetRequestMapper.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  The ASF licenses this file to You
 * under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.  For additional information regarding
 * copyright in this work, please see the NOTICE file in the top level
 * directory of this distribution.
 */

package org.apache.roller.planet.ui.rendering;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.planet.business.PlanetFactory;
import org.apache.roller.planet.business.PlanetManager;
import org.apache.roller.planet.config.PlanetConfig;
import org.apache.roller.planet.pojos.Planet;
import org.apache.roller.planet.pojos.PlanetGroup;

/**
 * Multi-planet request mapper.
 *
 * This request mapper is used to map all planet specific urls of the form
 * /<planet handle>/* to the appropriate servlet for handling the actual
 * request.
 */
public class MultiPlanetRequestMapper implements RequestMapper {

    private static Log log = LogFactory.getLog(MultiPlanetRequestMapper.class);

    private static final String PAGE_SERVLET = "/planet-ui/rendering/page";
    private static final String FEED_SERVLET = "/planet-ui/rendering/feed";
    private static final String OPML_SERVLET = "/planet-ui/rendering/opml";

    // url patterns that are not allowed to be considered planet handles
    Set restricted = null;

    public MultiPlanetRequestMapper() {

        this.restricted = new HashSet();

        // build roller restricted list
        String restrictList = PlanetConfig.getProperty("rendering.multiPlanetMapper.rollerProtectedUrls");
        if (restrictList != null && restrictList.trim().length() > 0) {
            String[] restrict = restrictList.split(",");
            for (int i = 0; i < restrict.length; i++) {
                this.restricted.add(restrict[i]);
            }
        }

        // add user restricted list
        restrictList = PlanetConfig.getProperty("rendering.multiPlanetMapper.userProtectedUrls");
        if (restrictList != null && restrictList.trim().length() > 0) {
            String[] restrict = restrictList.split(",");
            for (int i = 0; i < restrict.length; i++) {
                this.restricted.add(restrict[i]);
            }
        }
    }

    public boolean handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // kinda silly, but we need to keep track of whether or not the url had
        // a trailing slash so that we can act accordingly
        boolean trailingSlash = false;

        String planetHandle = null;
        String planetContext = null;
        String groupHandle = null;
        String groupContext = null;
        String extraRequestData = null;

        log.debug("evaluating [" + request.getRequestURI() + "]");

        // figure out potential planet handle
        String uri = request.getRequestURI();
        String pathInfo = null;

        if (uri != null && uri.trim().length() > 1) {

            if (request.getContextPath() != null)
                uri = uri.substring(request.getContextPath().length());

            // strip off the leading slash
            uri = uri.substring(1);

            // strip off trailing slash if needed
            if (uri.endsWith("/")) {
                uri = uri.substring(0, uri.length() - 1);
                trailingSlash = true;
            }

            if (uri.indexOf("/") != -1) {
                planetHandle = uri.substring(0, uri.indexOf("/"));
                pathInfo = uri.substring(uri.indexOf("/") + 1);
            } else {
                planetHandle = uri;
            }
        }

        log.debug("potential planet handle = " + planetHandle);

        // check if it's a valid planet handle
        if (restricted.contains(planetHandle) || !this.isPlanet(planetHandle)) {
            log.debug("SKIPPED " + planetHandle);
            return false;
        }

        log.debug("PLANET_URL " + request.getServletPath());

        // parse the rest of the url
        if (pathInfo != null) {

            // parse the next portion of the url
            // we expect <context>/<groupHandle>/<groupContext>/<extra>/<info>
            String[] urlPath = pathInfo.split("/", 4);
            planetContext = urlPath[0];

            if (urlPath.length == 2) {
                groupHandle = urlPath[1];
            } else if (urlPath.length == 3) {
                groupHandle = urlPath[1];
                groupContext = urlPath[2];
            } else if (urlPath.length == 4) {
                groupHandle = urlPath[1];
                groupContext = urlPath[2];
                extraRequestData = urlPath[3];
            }
        }

        // special handling for trailing slash issue
        // we need this because by http standards the urls /foo and /foo/ are
        // supposed to be considered different, so we must enforce that
        if ((planetContext == null && !trailingSlash)
                || (groupHandle != null && groupContext == null && !trailingSlash)) {

            // this means someone referred to a planet or group index page 
            // with the shortest form of url /<planet> or /<planet>/group/<group>
            // and we need to add a slash to the url and redirect
            String redirectUrl = request.getRequestURI() + "/";
            if (request.getQueryString() != null) {
                redirectUrl += "?" + request.getQueryString();
            }

            response.sendRedirect(redirectUrl);
            return true;

        } else if (groupContext != null && trailingSlash) {
            // this means that someone has accessed a url and included a 
            // trailing slash, like /<planet>/group/<group>/feed/atom/ which is
            // not supported, so we need to offer up a 404 Not Found
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return true;
        }

        // calculate forward url
        String forwardUrl = calculateForwardUrl(request, planetHandle, planetContext, groupHandle, groupContext,
                extraRequestData);

        // if we don't have a forward url then the request was invalid somehow
        if (forwardUrl == null) {
            return false;
        }

        // dispatch to forward url
        log.debug("forwarding to " + forwardUrl);
        RequestDispatcher dispatch = request.getRequestDispatcher(forwardUrl);
        dispatch.forward(request, response);

        // we dealt with this request ourselves, so return "true"
        return true;
    }

    /**
     * Convenience method for caculating the servlet forward url given a set
     * of information to make the decision with.
     *
     * handle is always assumed valid, all other params may be null.
     */
    private String calculateForwardUrl(HttpServletRequest request, String planetHandle, String planetContext,
            String groupHandle, String groupContext, String data) {

        log.debug(planetHandle + "," + planetContext + "," + groupHandle + "," + groupContext + "," + data);

        StringBuffer forwardUrl = new StringBuffer();

        // no context means planet homepage
        if (planetContext == null) {
            forwardUrl.append(PAGE_SERVLET);
            forwardUrl.append("/").append(planetHandle);

            // requests for a specific planet group
        } else if (planetContext.equals("group") && groupHandle != null) {

            // no group context means group homepage
            if (groupContext == null) {
                forwardUrl.append(PAGE_SERVLET);
                forwardUrl.append("/").append(planetHandle);
                forwardUrl.append("/").append(groupHandle);

                // request for planet group feed
            } else if ("feed".equals(groupContext)) {
                forwardUrl.append(FEED_SERVLET);
                forwardUrl.append("/").append(planetHandle);
                forwardUrl.append("/").append(groupHandle);
                if (data != null) {
                    forwardUrl.append("/").append(data);
                }

                // request for planet group opml descriptor
            } else if ("opml".equals(groupContext)) {
                forwardUrl.append(OPML_SERVLET);
                forwardUrl.append("/").append(planetHandle);
                forwardUrl.append("/").append(groupHandle);
                if (data != null) {
                    forwardUrl.append("/").append(data);
                }

                // unsupported planet group url
            } else {
                return null;
            }

            // unsupported planet url
        } else {
            return null;
        }

        log.debug("FORWARD_URL " + forwardUrl.toString());

        return forwardUrl.toString();
    }

    /**
     * convenience method which determines if the given string is a valid
     * planet handle.
     */
    private boolean isPlanet(String planetHandle) {

        log.debug("checking planet handle " + planetHandle);

        boolean isPlanet = false;

        try {
            PlanetManager mgr = PlanetFactory.getPlanet().getPlanetManager();
            Planet planet = mgr.getPlanet(planetHandle);

            if (planet != null) {
                isPlanet = true;
            }
        } catch (Exception ex) {
            // doesn't really matter to us why it's not a valid planet
        }

        return isPlanet;
    }

}