Java tutorial
/* * 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 com.concursive.connect.web.modules.profile.dao.Project; import com.concursive.connect.web.modules.profile.utils.ProjectUtils; 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.Enumeration; import java.util.Iterator; import java.util.Map; /** * A replacement portal url parser which implements simple URLs for the * project module portlets * * @author matt rajkowski * @created October 24, 2008 */ public class ProjectPortalURLParserImpl implements PortalURLParser { private static final Log LOG = LogFactory.getLog(ProjectPortalURLParserImpl.class); /** * The singleton parser instance. */ private static final PortalURLParser PARSER = new ProjectPortalURLParserImpl(); // 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 ProjectPortalURLParserImpl() { // 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()); StringBuffer url = new StringBuffer(); // Build the URL from various items... if (request.getParameterMap() != null) { String action = request.getParameter("portlet-action"); String projectValue = request.getParameter("portlet-pid"); String object = request.getParameter("portlet-object"); String value = request.getParameter("portlet-value"); String params = request.getParameter("portlet-params"); // Append the portlet action // @note TEST TEST TEST //url.append("/").append(action); url.append("/").append(StringUtils.encodeUrl(action)); // Append the targeted profile Project project = ProjectUtils.loadProject(Integer.parseInt(projectValue)); url.append("/").append(project.getUniqueId()); // Append the object in the profile // @note TEST TEST TEST //url.append("/").append(object); url.append("/").append(StringUtils.encodeUrl(object)); // Append any object value, like object id if (StringUtils.hasText(value)) { url.append("/").append(StringUtils.encodeUrl(value)); } // Append any parameters if (StringUtils.hasText(params)) { // @note TEST TEST TEST //url.append("/").append(params); url.append("/").append(StringUtils.encodeUrl(params)); } LOG.debug("reconstructed url: " + url.toString()); } String servletName = 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); portalURL.addParameter(decodeParameter(parameter, 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/show/project/module LOG.debug("servletPath: " + portalURL.getServletPath()); //renderPath: /context.SomePortlet!T3 LOG.debug("renderPath: " + portalURL.getRenderPath()); // Decode the current url StringBuffer buffer = new StringBuffer(); // Detect if pointing to a new url based on passed parameters String action = null; String object = null; String value = null; String params = null; for (Object paramObject : portalURL.getParameters()) { PortalURLParameter param = (PortalURLParameter) paramObject; if ("portlet-action".equals(param.getName())) { action = param.getValues()[0]; } else if ("portlet-object".equals(param.getName())) { object = param.getValues()[0]; } else if ("portlet-value".equals(param.getName())) { value = param.getValues()[0]; } else if ("portlet-params".equals(param.getName())) { params = param.getValues()[0]; } } if (action != null || object != null || value != null || params != null) { // Strip off the context for determining the components of the url String url = portalURL.getServletPath(); if (portalURL.getRenderPath() != null) { String ctx = portalURL.getRenderPath().substring(0, portalURL.getRenderPath().indexOf(".")); if (ctx.length() > 1) { url = url.substring(ctx.length()); buffer.append(ctx); } } LOG.debug("Base url: " + url); // Split apart the url items String[] currentURL = url.split("/"); int level = 0; if (url.startsWith("/")) { level = 1; } // Add the action if (action != null) { buffer.append("/").append(action); } else { buffer.append("/").append(currentURL[level]); } // Add the project uniqueId buffer.append("/"); buffer.append(currentURL[level + 1]); // Add the object if (object != null) { buffer.append("/").append(object); } else { if (currentURL.length > level + 2) { buffer.append("/").append(currentURL[level + 2]); } } // Add the value if (value != null) { buffer.append("/").append(value); } // Add the params if (params != null) { buffer.append("/").append(params); } } else { // Use the current path if (!portalURL.getServletPath().startsWith("/")) { buffer.append("/"); } buffer.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 ("portlet-action".equals(param.getName())) { continue; } else if ("portlet-object".equals(param.getName())) { continue; } else if ("portlet-value".equals(param.getName())) { continue; } else if ("portlet-params".equals(param.getName())) { continue; } else 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())) { LOG.debug("Appending actionWindow parameters"); 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... " + param.getWindowId()); // Encode the parameter ONLY if it targets the currently being rendered portlet if (param.getWindowId().equals(portalURL.getRenderPath())) { // The Project Portal uses clean URLs, so portlet window targeting is not used if (!buffer.toString().contains("?" + param.getName() + "=") && !buffer.toString().contains("&" + param.getName() + "=")) { String valueString = encodeMultiValues(param.getValues()); // @note TEST TEST TEST //appendParameter(buffer, param.getName() + "=" + valueString); appendParameter(buffer, param.getName() + "=" + StringUtils.encodeUrl(valueString)); } else { // If param already exists, replace the value } } } } // 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; } public static void addAllParameters(HttpServletRequest request, PortalURL portalURL) { Enumeration params = request.getParameterNames(); while (params.hasMoreElements()) { String parameter = (String) params.nextElement(); String value = request.getParameter(parameter); if (StringUtils.hasText(value)) { if (!parameter.startsWith(PREFIX + RENDER_PARAM) && !parameter.equals("portletWindowState1") && !parameter.startsWith("portlet-") && !(parameter.equals("command") && "ProjectCenter".equals(value))) { if (StringUtils.hasText(value)) { LOG.debug("Made a parameter available to the portlet: " + parameter); portalURL.addParameter(new PortalURLParameter(portalURL.getRenderPath(), parameter, value)); } } else { if ("portlet-command".equals(parameter)) { LOG.debug("Made a parameter available to the portlet: " + parameter); portalURL.addParameter(new PortalURLParameter(portalURL.getRenderPath(), parameter, value)); } } } } } }