com.concursive.connect.web.portal.PortalURLParserImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.concursive.connect.web.portal.PortalURLParserImpl.java

Source

/*
 * ConcourseConnect
 * Copyright 2009 Concursive Corporation
 * http://www.concursive.com
 *
 * This file is part of ConcourseConnect, an open source social business
 * software and community platform.
 *
 * Concursive ConcourseConnect is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, version 3 of the License.
 *
 * Under the terms of the GNU Affero General Public License you must release the
 * complete source code for any application that uses any part of ConcourseConnect
 * (system header files and libraries used by the operating system are excluded).
 * These terms must be included in any work that has ConcourseConnect components.
 * If you are developing and distributing open source applications under the
 * GNU Affero General Public License, then you are free to use ConcourseConnect
 * under the GNU Affero General Public License.
 *
 * If you are deploying a web site in which users interact with any portion of
 * ConcourseConnect over a network, the complete source code changes must be made
 * available.  For example, include a link to the source archive directly from
 * your web site.
 *
 * For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their
 * products, and do not license and distribute their source code under the GNU
 * Affero General Public License, Concursive provides a flexible commercial
 * license.
 *
 * To anyone in doubt, we recommend the commercial license. Our commercial license
 * is competitively priced and will eliminate any confusion about how
 * ConcourseConnect can be used and distributed.
 *
 * ConcourseConnect 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 Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ConcourseConnect.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Attribution Notice: ConcourseConnect is an Original Work of software created
 * by Concursive Corporation
 */
package com.concursive.connect.web.portal;

import com.concursive.commons.text.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pluto.driver.url.PortalURL;
import org.apache.pluto.driver.url.PortalURLParameter;
import org.apache.pluto.driver.url.PortalURLParser;
import org.apache.pluto.driver.url.impl.RelativePortalURLImpl;

import javax.portlet.PortletMode;
import javax.portlet.WindowState;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

/**
 * The replacement portal url parser used by the embedded portal
 *
 * @author matt rajkowski
 * @created October 24, 2008
 */
public class PortalURLParserImpl implements PortalURLParser {

    private static final Log LOG = LogFactory.getLog(PortalURLParserImpl.class);

    /**
     * The singleton parser instance.
     */
    private static final PortalURLParser PARSER = new PortalURLParserImpl();

    // Constants used for Encoding/Decoding ------------------------------------

    public static final String ALLOWED_PORTAL_PARAMETERS = "plutoAllowedPortalParameters";

    private static final String PREFIX = "__";
    private static final String DELIM = "_";
    private static final String PORTLET_ID = "pd";
    private static final String ACTION = "ac";
    private static final String RENDER_PARAM = "rp";
    private static final String WINDOW_STATE = "ws";
    private static final String PORTLET_MODE = "pm";
    private static final String VALUE_DELIM = "0x0";

    private static final String[][] ENCODINGS = new String[][] {
            //new String[]{"_", "0x1"},
            new String[] { ".", "0x2" }, new String[] { "/", "0x3" }, new String[] { "\r", "0x4" },
            new String[] { "\n", "0x5" }, new String[] { "<", "0x6" }, new String[] { ">", "0x7" },
            new String[] { " ", "0x8" }, new String[] { "#", "0x9" }, };

    // Constructor -------------------------------------------------------------

    /**
     * Private constructor that prevents external instantiation.
     */
    private PortalURLParserImpl() {
        // Do nothing.
    }

    /**
     * Returns the singleton parser instance.
     *
     * @return the singleton parser instance.
     */
    public static PortalURLParser getParser() {
        return PARSER;
    }

    // Public Methods ----------------------------------------------------------

    /**
     * Parse a servlet request to a portal URL.
     *
     * @param request the servlet request to parse.
     * @return the portal URL.
     */
    public PortalURL parse(HttpServletRequest request) {

        LOG.debug("Parsing URL: " + request.getRequestURI());

        if (LOG.isDebugEnabled()) {
            Enumeration params = request.getParameterNames();
            while (params.hasMoreElements()) {
                String param = (String) params.nextElement();
                LOG.debug("  parameter: " + param + "=" + request.getParameter(param));
            }
        }

        StringBuffer url = new StringBuffer();
        if (request.getParameterMap() != null) {
            // To construct the base URL for the portal, append the allowed portal URL
            // parameters that are specified by the portal manager
            ArrayList allowedPortalParams = (ArrayList) request.getAttribute(ALLOWED_PORTAL_PARAMETERS);
            if (allowedPortalParams != null) {
                Iterator i = allowedPortalParams.iterator();
                while (i.hasNext()) {
                    String paramName = (String) i.next();
                    String paramValue = request.getParameter(paramName);
                    if (paramValue != null) {
                        // @note TEST TEST TEST
                        //appendParameter(url, paramName + "=" + paramValue);
                        appendParameter(url, paramName + "=" + StringUtils.encodeUrl(paramValue));
                    }
                }
            }
        }

        String servletName = request.getServletPath() + url.toString();

        // Construct portal URL using info retrieved from servlet request
        String contextPath = request.getContextPath();
        LOG.debug("contextPath: " + contextPath);
        PortalURL portalURL = new RelativePortalURLImpl(contextPath, servletName, getParser());

        // Action window definition: portalURL.setActionWindow()
        String portletAction = request.getParameter("portletAction");
        if (portletAction != null && portletAction.startsWith(PREFIX + ACTION)) {
            LOG.debug("found action");
            portalURL.setActionWindow(decodeControlParameter(portletAction)[0]);
            portalURL.setRenderPath(contextPath + ".");
        }

        // Window state definition: portalURL.setWindowState()
        String portletWindowState = null;
        int windowStateCount = 0;
        while ((portletWindowState = request.getParameter("portletWindowState" + (++windowStateCount))) != null) {
            String[] decoded = decodeControlParameter(portletWindowState);
            portalURL.setWindowState(decoded[0], new WindowState(decoded[1]));
        }

        // Portlet mode definition: portalURL.setPortletMode()
        String portletMode = request.getParameter("portletMode");
        if (portletMode != null) {
            String[] decoded = decodeControlParameter(portletMode);
            portalURL.setPortletMode(decoded[0], new PortletMode(decoded[1]));
        }

        // Portal URL parameter: portalURL.addParameter()
        Enumeration params = request.getParameterNames();
        while (params.hasMoreElements()) {
            String parameter = (String) params.nextElement();
            if (parameter.startsWith(PREFIX + RENDER_PARAM)) {
                String value = request.getParameter(parameter);
                LOG.debug("parameter: " + parameter);
                // @note TEST TEST TEST
                //portalURL.addParameter(decodeParameter(parameter, value));
                portalURL.addParameter(decodeParameter(parameter, StringUtils.encodeUrl(value)));
            }
        }

        // Return the portal URL.
        return portalURL;
    }

    private static void appendParameter(StringBuffer url, String parameter) {
        if (url.length() == 0 || !url.toString().contains("?")) {
            url.append("?");
        } else {
            url.append("&");
        }
        LOG.debug("appendParameter: " + parameter);
        url.append(parameter);
    }

    /**
     * Converts a portal URL to a URL string.
     *
     * @param portalURL the portal URL to convert.
     * @return a URL string representing the portal URL.
     */
    public String toString(PortalURL portalURL) {

        //servletPath: /context/page
        LOG.debug("servletPath: " + portalURL.getServletPath());
        //renderPath: /context.SomePortlet!T3
        LOG.debug("renderPath: " + portalURL.getRenderPath());

        // Decode the current url
        StringBuffer buffer = new StringBuffer();

        // Append the server URI and the servlet path
        buffer.append(portalURL.getServletPath().startsWith("/") ? "" : "/").append(portalURL.getServletPath());

        // Append action and render parameters
        for (Iterator it = portalURL.getParameters().iterator(); it.hasNext();) {

            PortalURLParameter param = (PortalURLParameter) it.next();

            LOG.debug("Checking: " + param.getName());

            if ("out".equals(param.getName())) {
                if (StringUtils.hasText(param.getValues()[0])) {
                    appendParameter(buffer, param.getName() + "=" + param.getValues()[0]);
                }
                continue;
            } else if ("popup".equals(param.getName())) {
                if (StringUtils.hasText(param.getValues()[0])) {
                    appendParameter(buffer, param.getName() + "=" + param.getValues()[0]);
                }
                continue;
            }

            // Encode action params in the query appended at the end of the URL.
            if (portalURL.getActionWindow() != null && portalURL.getActionWindow().equals(param.getWindowId())) {
                for (int i = 0; i < param.getValues().length; i++) {
                    if (StringUtils.hasText(param.getValues()[i])) {
                        appendParameter(buffer, param.getName() + "=" + param.getValues()[i]);
                    }
                }
            } else if (param.getValues() != null && param.getValues().length > 0) {
                LOG.debug("Appending parameters...");
                // Encode the parameter ONLY if it targets the currently being rendered portlet
                //        if (param.getWindowId().equals(portalURL.getRenderPath())) {
                String valueString = encodeMultiValues(param.getValues());
                if (valueString.length() > 0) {
                    appendParameter(buffer,
                            encodeControlParameter(RENDER_PARAM, param.getWindowId(), param.getName()) + "="
                                    + valueString);
                }
                //        }
            }
        }

        // Append the action window definition, if it exists
        if (portalURL.getActionWindow() != null) {
            appendParameter(buffer,
                    "portletAction=" + PREFIX + ACTION + encodeCharacters(portalURL.getActionWindow()));
        }

        // Append portlet mode definitions
        for (Iterator it = portalURL.getPortletModes().entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            // If the portlet mode is "view" then no need to show the portlet mode in the url because that is the default
            if (!"view".equals(entry.getValue().toString())) {
                appendParameter(buffer, "portletMode=" + encodeControlParameter(PORTLET_MODE,
                        entry.getKey().toString(), entry.getValue().toString()));
            }
        }

        // Append window state definitions
        int windowStateCount = 0;
        for (Iterator it = portalURL.getWindowStates().entrySet().iterator(); it.hasNext();) {
            ++windowStateCount;
            Map.Entry entry = (Map.Entry) it.next();
            // If the portlet window state is "normal" then no need to show it in the url because that is the default
            if (!"normal".equals(entry.getValue().toString())) {
                appendParameter(buffer,
                        "portletWindowState" + windowStateCount + "=" + encodeControlParameter(WINDOW_STATE,
                                entry.getKey().toString(), entry.getValue().toString()));
            }
        }

        // Construct the string representing the portal URL.
        return buffer.toString();
    }

    // Private Encoding/Decoding Methods ---------------------------------------

    /**
     * Encode a control parameter.
     *
     * @param type     the type of the control parameter, which may be:
     *                 portlet mode, window state, or render parameter.
     * @param windowId the portlet window ID.
     * @param name     the name to encode.
     * @return encoded control parameter
     */
    private static String encodeControlParameter(String type, String windowId, String name) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(PREFIX).append(type).append(encodeCharacters(windowId)).append(DELIM).append(name);
        return buffer.toString();
    }

    /**
     * Encode a string array containing multiple values into a single string.
     * This method is used to encode multiple render parameter values.
     *
     * @param values the string array to encode.
     * @return a single string containing all the values.
     */
    private String encodeMultiValues(String[] values) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
            buffer.append(values[i] != null ? values[i] : "");
            if (i + 1 < values.length) {
                buffer.append(VALUE_DELIM);
            }
        }
        return encodeCharacters(buffer.toString());
    }

    /**
     * Encode special characters contained in the string value.
     *
     * @param string the string value to encode.
     * @return the encoded string.
     */
    public static String encodeCharacters(String string) {
        for (int i = 0; i < ENCODINGS.length; i++) {
            string = StringUtils.replace(string, ENCODINGS[i][0], ENCODINGS[i][1]);
        }
        return string;
    }

    /**
     * Decode a control parameter.
     *
     * @param control the control parameter to decode.
     * @return values  a pair of decoded values.
     */
    private String[] decodeControlParameter(String control) {
        String[] valuePair = new String[2];
        control = control.substring((PREFIX + PORTLET_ID).length());
        int index = control.indexOf(DELIM);
        if (index >= 0) {
            valuePair[0] = control.substring(0, index);
            valuePair[0] = decodeCharacters(valuePair[0]);
            if (index + 1 <= control.length()) {
                valuePair[1] = control.substring(index + 1);
                valuePair[1] = decodeCharacters(valuePair[1]);
            } else {
                valuePair[1] = "";
            }
        } else {
            valuePair[0] = decodeCharacters(control);
        }
        return valuePair;
    }

    /**
     * Decode a name-value pair into a portal URL parameter.
     *
     * @param name  the parameter name.
     * @param value the parameter value.
     * @return the decoded portal URL parameter.
     */
    private PortalURLParameter decodeParameter(String name, String value) {

        LOG.debug("Decoding parameter: name=" + name + ", value=" + value);

        // Defect PLUTO-361
        // ADDED: if the length is less than this, there is no parameter...
        if (name.length() < (PREFIX + PORTLET_ID).length()) {
            return null;
        }

        // Decode the name into window ID and parameter name.
        String noPrefix = name.substring((PREFIX + PORTLET_ID).length());
        String windowId = noPrefix.substring(0, noPrefix.indexOf(DELIM));
        String paramName = noPrefix.substring(noPrefix.indexOf(DELIM) + 1);

        // Decode special characters in window ID and parameter value.
        windowId = decodeCharacters(windowId);
        if (value != null) {
            value = decodeCharacters(value);
        }

        // Split multiple values into a value array.
        String[] paramValues = value.split(VALUE_DELIM);

        if (paramValues.length == 1) {
            LOG.debug(windowId + " - parameter: " + paramName + "=" + paramValues[0]);
        }

        // Construct portal URL parameter and return.
        return new PortalURLParameter(windowId, paramName, paramValues);
    }

    /**
     * Decode special characters contained in the string value.
     *
     * @param string the string value to decode.
     * @return the decoded string.
     */
    private static String decodeCharacters(String string) {
        for (int i = 0; i < ENCODINGS.length; i++) {
            string = StringUtils.replace(string, ENCODINGS[i][1], ENCODINGS[i][0]);
        }
        return string;
    }

}