Package org.jasig.portal.portlet.url

Source Code of org.jasig.portal.portlet.url.PortletUrlSyntaxProviderImpl$UrlTarget

/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig 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.
*/

package org.jasig.portal.portlet.url;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.portlet.PortletMode;
import javax.portlet.WindowState;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pluto.Constants;
import org.jasig.portal.ChannelRuntimeData;
import org.jasig.portal.IUserPreferencesManager;
import org.jasig.portal.UPFileSpec;
import org.jasig.portal.channels.portlet.IPortletAdaptor;
import org.jasig.portal.layout.IUserLayout;
import org.jasig.portal.layout.IUserLayoutManager;
import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
import org.jasig.portal.portlet.delegation.IPortletDelegationManager;
import org.jasig.portal.portlet.om.IPortletDefinition;
import org.jasig.portal.portlet.om.IPortletEntity;
import org.jasig.portal.portlet.om.IPortletEntityId;
import org.jasig.portal.portlet.om.IPortletWindow;
import org.jasig.portal.portlet.om.IPortletWindowId;
import org.jasig.portal.portlet.registry.IPortletDefinitionRegistry;
import org.jasig.portal.portlet.registry.IPortletEntityRegistry;
import org.jasig.portal.portlet.registry.IPortletWindowRegistry;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.url.IPortalRequestUtils;
import org.jasig.portal.user.IUserInstance;
import org.jasig.portal.user.IUserInstanceManager;
import org.springframework.beans.factory.annotation.Required;

/**
* Contains the logic and string constants for generating and parsing portlet URL parameters.
*
* @author Eric Dalquist
* @version $Revision$
*/
public class PortletUrlSyntaxProviderImpl implements IPortletUrlSyntaxProvider {
    private static final String SEPERATOR = "_";
    private static final String PORTLET_CONTROL_PREFIX = "pltc" + SEPERATOR;
    private static final String PORTLET_PARAM_PREFIX = "pltp" + SEPERATOR;

    private static final String PARAM_REQUEST_TARGET = PORTLET_CONTROL_PREFIX + "target";
    private static final String PARAM_REQUEST_TYPE_PREFIX = PORTLET_CONTROL_PREFIX + "type";
    private static final String PARAM_WINDOW_STATE_PREFIX = PORTLET_CONTROL_PREFIX + "state";
    private static final String PARAM_PORTLET_MODE_PREFIX = PORTLET_CONTROL_PREFIX + "mode";
    private static final String PARAM_DELEGATE_PREFIX = PORTLET_CONTROL_PREFIX + "delegate";
   
    private static final Pattern URL_PARAM_NAME = Pattern.compile("&([^&?=\n]*)");
  
    protected final Log logger = LogFactory.getLog(this.getClass());
   
    private String defaultEncoding = "UTF-8";
    private int bufferLength = 512;
    private IPortletWindowRegistry portletWindowRegistry;
    private IPortalRequestUtils portalRequestUtils;
    private IPortletDefinitionRegistry portletDefinitionRegistry;
    private IPortletEntityRegistry portletEntityRegistry;
    private IUserInstanceManager userInstanceManager;
    private IPortletDelegationManager portletDelegationManager;
    private boolean useAnchors = true;
    private Set<WindowState> transientWindowStates = new HashSet<WindowState>(Arrays.asList(IPortletAdaptor.EXCLUSIVE, IPortletAdaptor.DETACHED));
    private Set<WindowState> anchoringWindowStates = new HashSet<WindowState>(Arrays.asList(WindowState.MINIMIZED, WindowState.NORMAL));
   
   
    /**
     * @return the useAnchors
     */
    public boolean isUseAnchors() {
        return this.useAnchors;
    }
    /**
     * If anchors should be added to generated URLs
     */
    public void setUseAnchors(boolean useAnchors) {
        this.useAnchors = useAnchors;
    }
    /**
     * @return the portalRequestUtils
     */
    public IPortalRequestUtils getPortalRequestUtils() {
        return portalRequestUtils;
    }
    /**
     * @param portalRequestUtils the portalRequestUtils to set
     */
    @Required
    public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) {
        Validate.notNull(portalRequestUtils);
        this.portalRequestUtils = portalRequestUtils;
    }
   
    /**
     * @return the defaultEncoding
     */
    public String getDefaultEncoding() {
        return defaultEncoding;
    }
    /**
     * @param defaultEncoding the defaultEncoding to set
     */
    public void setDefaultEncoding(String defaultEncoding) {
        Validate.notNull(defaultEncoding, "defaultEncoding can not be null");
        this.defaultEncoding = defaultEncoding;
    }

    /**
     * @return the bufferLength
     */
    public int getBufferLength() {
        return bufferLength;
    }
    /**
     * @param bufferLength the bufferLength to set
     */
    public void setBufferLength(int bufferLength) {
        if (bufferLength < 1) {
            throw new IllegalArgumentException("bufferLength must be at least 1");
        }

        this.bufferLength = bufferLength;
    }

    /**
     * @return the portletWindowRegistry
     */
    public IPortletWindowRegistry getPortletWindowRegistry() {
        return portletWindowRegistry;
    }
    /**
     * @param portletWindowRegistry the portletWindowRegistry to set
     */
    @Required
    public void setPortletWindowRegistry(IPortletWindowRegistry portletWindowRegistry) {
        Validate.notNull(portletWindowRegistry, "portletWindowRegistry can not be null");
        this.portletWindowRegistry = portletWindowRegistry;
    }
   
    public IPortletDefinitionRegistry getPortletDefinitionRegistry() {
        return portletDefinitionRegistry;
    }
    /**
     * @param portletDefinitionRegistry the portletDefinitionRegistry to set
     */
    @Required
    public void setPortletDefinitionRegistry(IPortletDefinitionRegistry portletDefinitionRegistry) {
        this.portletDefinitionRegistry = portletDefinitionRegistry;
    }

    public IPortletEntityRegistry getPortletEntityRegistry() {
        return portletEntityRegistry;
    }
    /**
     * @param portletEntityRegistry the portletEntityRegistry to set
     */
    @Required
    public void setPortletEntityRegistry(IPortletEntityRegistry portletEntityRegistry) {
        this.portletEntityRegistry = portletEntityRegistry;
    }

    public IUserInstanceManager getUserInstanceManager() {
        return userInstanceManager;
    }
    /**
     * @param userInstanceManager the userInstanceManager to set
     */
    @Required
    public void setUserInstanceManager(IUserInstanceManager userInstanceManager) {
        this.userInstanceManager = userInstanceManager;
    }

    public Set<WindowState> getTransientWindowStates() {
        return this.transientWindowStates;
    }
    /**
     * {@link WindowState}s that have transient {@link IPortletWindow}s. These states must be the ONLY
     * content rendering links on the page. Defaults to EXCLUSIVE and DETACHED.
     */
    public void setTransientWindowStates(Set<WindowState> transientWindowStates) {
        if (transientWindowStates == null) {
            this.transientWindowStates = Collections.emptySet();
        }
        else {
            this.transientWindowStates = new LinkedHashSet<WindowState>(transientWindowStates);
        }
    }

    public Set<WindowState> getAnchoringWindowStates() {
        return this.anchoringWindowStates;
    }
    /**
     * {@link WindowState}s where anchors should be added to the ends of the generated URLS, only if
     * {@link #setUseAnchors(boolean)} is true. Defaults to MINIMIZED and NORMAL
     */
    public void setAnchoringWindowStates(Set<WindowState> anchoringWindowStates) {
        if (anchoringWindowStates == null) {
            this.anchoringWindowStates = Collections.emptySet();
        }
        else {
            this.anchoringWindowStates = new LinkedHashSet<WindowState>(anchoringWindowStates);
        }
    }
   
    public IPortletDelegationManager getPortletDelegationManager() {
        return this.portletDelegationManager;
    }
    public void setPortletDelegationManager(IPortletDelegationManager portletDelegationManager) {
        this.portletDelegationManager = portletDelegationManager;
    }
   
   
    /* (non-Javadoc)
     * @see org.jasig.portal.portlet.url.IPortletUrlSyntaxProvider#parsePortletParameters(javax.servlet.http.HttpServletRequest)
     */
    public PortletUrl parsePortletUrl(HttpServletRequest request) {
        Validate.notNull(request, "request can not be null");
       
        final UrlTarget urlTarget = resolveTargetWindowId(request);
        if (urlTarget == null) {
            return null;
        }
       
        final PortletUrl portletUrl = new PortletUrl(urlTarget.portletWindowId);
       
        this.parsePortletParameters(request, portletUrl, urlTarget);
   
        return portletUrl;
    }
   
    @SuppressWarnings("unchecked")
    protected void parsePortletParameters(HttpServletRequest request, PortletUrl portletUrl, UrlTarget urlTarget) {
        final IPortletWindowId portletWindowId = portletUrl.getTargetWindowId();

        //Setup the namespace string used for parsing parameters, fname targets won't have namespaced parameters
        final String controlNamespace;
        final String parameterNamespace;
        if (urlTarget != null && urlTarget.fnameTarget) {
            controlNamespace = "";
            parameterNamespace = "";
        }
        else {
            controlNamespace = SEPERATOR + portletWindowId.toString();
            parameterNamespace = portletWindowId.toString() + SEPERATOR;
        }
       
        final String requestTypeStr = request.getParameter(PARAM_REQUEST_TYPE_PREFIX + controlNamespace);
        if (requestTypeStr != null) {
            final RequestType requestType = RequestType.valueOf(requestTypeStr);
            portletUrl.setRequestType(requestType);
        }
        else {
            //Default to RENDER request if no request type was specified
            portletUrl.setRequestType(RequestType.RENDER);
        }
       
        final String windowStateStr = request.getParameter(PARAM_WINDOW_STATE_PREFIX + controlNamespace);
        if (windowStateStr != null) {
            final WindowState windowState = new WindowState(windowStateStr);
            portletUrl.setWindowState(windowState);
        }
       
        final String portletModeStr = request.getParameter(PARAM_PORTLET_MODE_PREFIX + controlNamespace);
        if (portletModeStr != null) {
            final PortletMode portletMode = new PortletMode(portletModeStr);
            portletUrl.setPortletMode(portletMode);
        }
       
        final Map<String, String[]> requestParameters = request.getParameterMap();
        final Set<String> urlParameterNames = this.getUrlParameterNames(request);
       
        final Map<String, List<String>> portletParameters = new LinkedHashMap<String, List<String>>(requestParameters.size());
        final String fqParameterName = PORTLET_PARAM_PREFIX + parameterNamespace;
        for (final Map.Entry<String, String[]> parameterEntry : requestParameters.entrySet()) {
            final String parameterName = parameterEntry.getKey();
           
            //If the parameter starts with the param prefix add it to the Map
            if (parameterName.startsWith(fqParameterName)) {
                final String portletParameterName = parameterName.substring(fqParameterName.length());
                final String[] portletParameterValues = parameterEntry.getValue();

                if (portletParameterValues == null) {
                    portletParameters.put(portletParameterName, null);
                }
                else {
                    portletParameters.put(portletParameterName, Arrays.asList(portletParameterValues));
                }
            }
            //If it did not appear on the URL it must be a submit parameter so add it to the Map
            else if (urlParameterNames != null && !urlParameterNames.contains(parameterName)) {
                final String[] portletParameterValues = parameterEntry.getValue();

                if (portletParameterValues == null) {
                    portletParameters.put(parameterName, null);
                }
                else {
                    portletParameters.put(parameterName, Arrays.asList(portletParameterValues));
                }
            }
        }
        portletUrl.setParameters(portletParameters);
       
        portletUrl.setSecure(request.isSecure());

        //If delegating recurse
        final String delegateWindowIdStr = request.getParameter(PARAM_DELEGATE_PREFIX + controlNamespace);
        if (delegateWindowIdStr != null) {
            final IPortletWindowId delegateWindowId = this.portletWindowRegistry.getPortletWindowId(delegateWindowIdStr);
           
            //Verify delegation change
            final IPortletWindow delegateWindow = this.portletWindowRegistry.getPortletWindow(request, delegateWindowId);
            final IPortletWindowId delegationParentId = delegateWindow.getDelegationParent();
            if (delegationParentId == null) {
                throw new IllegalArgumentException("Delegate window '" + delegateWindowId + "' has no parent. Parent specified in the URL is '" + portletWindowId + "'");
            }
            else if (!portletWindowId.equals(delegationParentId)) {
                throw new IllegalArgumentException("Parent '" + delegationParentId + "' of delegate window '" + delegateWindowId + "' is not the parent specified in the URL: '" + portletWindowId + "'");
            }
           
            final PortletUrl delegatePortletUrl = new PortletUrl(delegateWindowId);
            portletUrl.setDelegatePortletUrl(delegatePortletUrl);
           
            this.parsePortletParameters(request, delegatePortletUrl, null);
        }
    }
   
    protected UrlTarget resolveTargetWindowId(HttpServletRequest request) {
        final String targetedPortletWindowIdStr = request.getParameter(PARAM_REQUEST_TARGET);
        if (targetedPortletWindowIdStr != null) {
            return new UrlTarget(
                    this.portletWindowRegistry.getPortletWindowId(targetedPortletWindowIdStr),
                    false);
        }
       
        //Fail over to looking for a fname
        final String targetedFname = request.getParameter("uP_fname");
        if (targetedFname == null) {
            return null;
        }
       
        //Found an FName lookup the appropriate portlet window id
       
        //Get the user's layout manager
        final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
        final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager();
        final IUserLayoutManager userLayoutManager = preferencesManager.getUserLayoutManager();
       
        //Determine the subscribe ID
        final String channelSubscribeId = userLayoutManager.getSubscribeId(targetedFname);
        if (channelSubscribeId == null) {
            this.logger.info("No channel subscribe ID found for fname '" + targetedFname + "'. skipping portlet parameter processing");
            return null;
        }
       
        //Find the channel and portlet definitions
        final IUserLayoutChannelDescription channelNode = (IUserLayoutChannelDescription)userLayoutManager.getNode(channelSubscribeId);
        final String channelPublishId = channelNode.getChannelPublishId();
        final IPortletDefinition portletDefinition = this.portletDefinitionRegistry.getPortletDefinition(Integer.parseInt(channelPublishId));
        if (!portletDefinition.getChannelDefinition().isPortlet()) {
            this.logger.info("No portlet defintion found for channel definition '" + channelPublishId + "' with fname '" + targetedFname + "'. skipping portlet parameter processing");
            return null;
        }
       
        //Determine the appropriate portlet window ID
        final IPerson person = userInstance.getPerson();
        final IPortletEntity portletEntity = this.portletEntityRegistry.getOrCreatePortletEntity(portletDefinition.getPortletDefinitionId(), channelSubscribeId, person.getID());
        final IPortletWindow defaultPortletWindow = this.portletWindowRegistry.createDefaultPortletWindow(request, portletEntity.getPortletEntityId());

        return new UrlTarget(
                this.portletWindowRegistry.createTransientPortletWindowId(request, defaultPortletWindow.getPortletWindowId()),
                true);
    }
   


    /**
     * Parses the request URL to return a Set of the parameter names that appeared on the URL string.
     *
     * @param request The request to look at.
     * @return The Set of parameter names from the URL.
     */
    protected Set<String> getUrlParameterNames(HttpServletRequest request) {
        // Only posts can have parameters not in the URL, ignore non-post requests.
        final String method = request.getMethod();
        if (!"POST".equals(method)) {
            return null;
        }
       
        final Set<String> urlParameterNames = new HashSet<String>();
       
        final String queryString = request.getQueryString();
        final Matcher paramNameMatcher = URL_PARAM_NAME.matcher("&" + queryString);

        final String encoding = this.getEncoding(request);
       
        while (paramNameMatcher.find()) {
            final String paramName = paramNameMatcher.group(1);
            String decParamName;
            try {
                decParamName = URLDecoder.decode(paramName, encoding);
            }
            catch (UnsupportedEncodingException uee) {
                decParamName = paramName;
            }
           
            urlParameterNames.add(decParamName);
        }
       
        return urlParameterNames;
    }

    /* (non-Javadoc)
     * @see org.jasig.portal.portlet.url.IPortletUrlSyntaxProvider#generatePortletUrl(javax.servlet.http.HttpServletRequest, org.jasig.portal.portlet.om.IPortletWindow, org.jasig.portal.portlet.url.PortletUrl)
     */
    public String generatePortletUrl(HttpServletRequest request, IPortletWindow portletWindow, PortletUrl portletUrl) {
        Validate.notNull(request, "request can not be null");
        Validate.notNull(portletWindow, "portletWindow can not be null");
        Validate.notNull(portletUrl, "portletUrl can not be null");
       
        //Convert the callback request to the portal request
        request = this.portalRequestUtils.getOriginalPortletAdaptorRequest(request);
       
        //If this portlet is a delegate and this is an action request it must be for the redirect URL
        //Store the PortletUrl as a request attribute so the dispatcher can get to it
        //Return a marker redirect URL string so the delegate dispatcher knows to ignore the redirect
        if (Constants.METHOD_ACTION.equals(request.getAttribute(Constants.METHOD_ID))) {
            if (portletWindow.getDelegationParent() != null) {
                this.portletDelegationManager.setDelegatePortletActionRedirectUrl(request, portletUrl);
                return IPortletDelegationManager.DELEGATE_ACTION_REDIRECT_TOKEN;
            }

            final PortletUrl delegatePortletUrl = this.portletDelegationManager.getDelegatePortletActionRedirectUrl(request);
            portletUrl.setDelegatePortletUrl(delegatePortletUrl);
        }
       
        //Build the base of the URL with the context path
        final StringBuilder url = new StringBuilder(this.bufferLength);
        final String contextPath = request.getContextPath();
        url.append(contextPath).append("/");
       
        this.generatePortletUrl(request, portletWindow, null, portletUrl, url);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Generated portlet URL '" + url + "' for IPortletWindow='" + portletWindow + "' and PortletUrl='" + portletUrl + "'. StringBuilder started with length " + this.bufferLength + " and ended with length " + url.capacity() + ".");
        }
       
        return url.toString();
    }
   
    protected void generatePortletUrl(HttpServletRequest request, IPortletWindow portletWindow, IPortletWindowId delegationChildId, PortletUrl portletUrl, StringBuilder url) {
        //Get the encoding to use for the URL
        final String encoding = this.getEncoding(request);
       
        //Look to see if the window is being delegated to, if so recurse to the parent for URL generation first
        final IPortletWindowId delegationParentId = portletWindow.getDelegationParent();
        if (delegationParentId != null) {
            final IPortletWindow delegateParent = this.portletWindowRegistry.getPortletWindow(request, delegationParentId);
           
            PortletUrl parentUrl = this.portletDelegationManager.getParentPortletUrl(request, delegationParentId);
            if (parentUrl == null) {
                parentUrl = new PortletUrl(delegationParentId);
                parentUrl.setWindowState(delegateParent.getWindowState());
                parentUrl.setPortletMode(delegateParent.getPortletMode());
                parentUrl.setParameters(delegateParent.getRequestParameters());
            }
           
            //Parent URLs MUST be in the same type as the child
            parentUrl.setRequestType(portletUrl.getRequestType());
           
            this.generatePortletUrl(request, delegateParent, portletWindow.getPortletWindowId(), parentUrl, url);
        }
       
        // TODO Need to decide how to deal with 'secure' URL requests

        final IPortletWindowId portletWindowId = portletWindow.getPortletWindowId();
        final IPortletEntity parentPortletEntity = this.portletWindowRegistry.getParentPortletEntity(request, portletWindowId);
        final String channelSubscribeId = parentPortletEntity.getChannelSubscribeId();

        WindowState windowState = portletUrl.getWindowState();
        PortletMode portletMode = portletUrl.getPortletMode();
       
        final WindowState previousWindowState = portletWindow.getWindowState();
        final PortletMode previousPortletMode = portletWindow.getPortletMode();
       
        //Only do this stuff for the top level window
        if (delegationParentId == null) {
            //Get the channel runtime data from the request attributes, it should have been set there by the portlet adapter
            final ChannelRuntimeData channelRuntimeData = (ChannelRuntimeData)request.getAttribute(IPortletAdaptor.ATTRIBUTE__RUNTIME_DATA);
            if (channelRuntimeData == null) {
                throw new IllegalStateException("No ChannelRuntimeData was found as a request attribute for key '" + IPortletAdaptor.ATTRIBUTE__RUNTIME_DATA + "' on request '" + request + "'");
            }
           
            // Determine the base path for the URL
            // If the next state is EXCLUSIVE or there is no state change and the current state is EXCLUSIVE use the worker URL base
            if (IPortletAdaptor.EXCLUSIVE.equals(windowState) || (windowState == null && IPortletAdaptor.EXCLUSIVE.equals(previousWindowState))) {
                final String urlBase = channelRuntimeData.getBaseWorkerURL(UPFileSpec.FILE_DOWNLOAD_WORKER);
                url.append(urlBase);
            }
            //In detached, need to make sure the URL is right
            else if (IPortletAdaptor.DETACHED.equals(windowState) || (windowState == null && IPortletAdaptor.DETACHED.equals(previousWindowState))) {
                final UPFileSpec upFileSpec = new UPFileSpec(channelRuntimeData.getUPFile());
                upFileSpec.setMethodNodeId(channelSubscribeId);
                upFileSpec.setTargetNodeId(channelSubscribeId);
                final String urlBase = upFileSpec.getUPFile();
                url.append(urlBase);
            }
            //Switching back from detached to a normal state
            else if (IPortletAdaptor.DETACHED.equals(previousWindowState) && windowState != null && !previousWindowState.equals(windowState)) {
                final UPFileSpec upFileSpec = new UPFileSpec(channelRuntimeData.getUPFile());
                upFileSpec.setMethodNodeId(UPFileSpec.USER_LAYOUT_ROOT_NODE);
                final String urlBase = upFileSpec.getUPFile();
                url.append(urlBase);
            }
            //No special handling, just use the base action URL
            else {
                final String urlBase = channelRuntimeData.getBaseActionURL();
                url.append(urlBase);
            }
           
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using root url base '" + url + "' for " + portletUrl);
            }
        }
       
        //Set the request target, creating a transient window ID if needed
        boolean forceWindowState = false;
        final String portletWindowIdString;
        //If rendering as a delegate just reuse the id (it will always be transient)
        if (delegationParentId != null) {
            portletWindowIdString = portletWindowId.toString();
        }
        //If switching from a non-transient state to a transient state generate a new transient window id
        else if (this.transientWindowStates.contains(windowState) && !this.transientWindowStates.contains(previousWindowState)) {
            final IPortletWindowId transientPortletWindowId = this.portletWindowRegistry.createTransientPortletWindowId(request, portletWindowId);
            portletWindowIdString = transientPortletWindowId.toString();
        }
        //If the window is transient, it is in a transient state and it is switching from a non-transient state
        else if (this.portletWindowRegistry.isTransient(request, portletWindowId) &&
                !this.transientWindowStates.contains(windowState) &&
                (windowState != null || !this.transientWindowStates.contains(previousWindowState))) {
            //Get non-transient version of id
            final IPortletEntityId portletEntityId = portletWindow.getPortletEntityId();
            final IPortletWindowId defaultPortletWindowId = this.portletWindowRegistry.getDefaultPortletWindowId(portletEntityId);
            portletWindowIdString = defaultPortletWindowId.getStringId();
           
            if (windowState == null) {
                final IPortletWindow defaultPortletWindow = this.portletWindowRegistry.getPortletWindow(request, defaultPortletWindowId);
                if (!previousWindowState.equals(defaultPortletWindow.getWindowState())) {
                    forceWindowState = true;
                    windowState = previousWindowState;
                }
                if (!previousPortletMode.equals(defaultPortletWindow.getPortletMode())) {
                    portletMode = previousPortletMode;
                }
            }
        }
        else {
            portletWindowIdString = portletWindowId.getStringId();
        }
       
        //Only one target per url
        if (delegationParentId == null) {
            this.encodeAndAppend(url.append("?"), encoding, PARAM_REQUEST_TARGET, portletWindowIdString);
        }
       
        //Only if actually delegating rendering
        if (delegationChildId != null) {
            this.encodeAndAppend(url.append("&"), encoding, PARAM_DELEGATE_PREFIX + SEPERATOR + portletWindowIdString, delegationChildId.toString());
        }
       
        //Set the request type
        final RequestType requestType = portletUrl.getRequestType();
        final String requestTypeString = requestType != null ? requestType.toString() : RequestType.RENDER.toString();
        this.encodeAndAppend(url.append("&"), encoding, PARAM_REQUEST_TYPE_PREFIX + SEPERATOR + portletWindowIdString, requestTypeString);
       
        // If set add the window state
        if (windowState != null && (forceWindowState || !previousWindowState.equals(windowState))) {
            this.encodeAndAppend(url.append("&"), encoding, PARAM_WINDOW_STATE_PREFIX + SEPERATOR + portletWindowIdString, windowState.toString());
           
            //uPortal specific parameters are only needed the top most parent portlet window
            if (delegationParentId == null) {
                //Add the parameters needed by the portal structure & theme to render the correct window state
                if (WindowState.MAXIMIZED.equals(windowState)) {
                    this.encodeAndAppend(url.append("&"), encoding, "uP_root", channelSubscribeId);
                }
                else if (WindowState.NORMAL.equals(windowState)) {
                    this.encodeAndAppend(url.append("&"), encoding, "uP_root", IUserLayout.ROOT_NODE_NAME);
                    this.encodeAndAppend(url.append("&"), encoding, "uP_tcattr", "minimized");
                    this.encodeAndAppend(url.append("&"), encoding, "minimized_channelId", channelSubscribeId);
                    this.encodeAndAppend(url.append("&"), encoding, "minimized_" + channelSubscribeId + "_value", "false");
                    this.encodeAndAppend(url.append("&"), encoding, "uP_save", "all");
                }
                else if (WindowState.MINIMIZED.equals(windowState)) {
                    this.encodeAndAppend(url.append("&"), encoding, "uP_root", IUserLayout.ROOT_NODE_NAME);
                    this.encodeAndAppend(url.append("&"), encoding, "uP_tcattr", "minimized");
                    this.encodeAndAppend(url.append("&"), encoding, "minimized_channelId", channelSubscribeId);
                    this.encodeAndAppend(url.append("&"), encoding, "minimized_" + channelSubscribeId + "_value", "true");
                    this.encodeAndAppend(url.append("&"), encoding, "uP_save", "all");
                }
                else if (IPortletAdaptor.DETACHED.equals(windowState)) {
                    this.encodeAndAppend(url.append("&"), encoding, "uP_detach_target", channelSubscribeId);
                }
            }
        }
        //Or for any transient state always add the window state
        else if (this.transientWindowStates.contains(windowState) || this.transientWindowStates.contains(previousWindowState)) {
            this.encodeAndAppend(url.append("&"), encoding, PARAM_WINDOW_STATE_PREFIX + SEPERATOR + portletWindowIdString, previousWindowState.toString());
        }
       
        //If set add the portlet mode
        if (portletMode != null) {
            this.encodeAndAppend(url.append("&"), encoding, PARAM_PORTLET_MODE_PREFIX + SEPERATOR + portletWindowIdString, portletMode.toString());
        }
        //Or for any transient state always add the portlet mode
        else if (this.transientWindowStates.contains(windowState) || this.transientWindowStates.contains(previousWindowState)) {
            this.encodeAndAppend(url.append("&"), encoding, PARAM_PORTLET_MODE_PREFIX + SEPERATOR + portletWindowIdString, portletWindow.getPortletMode().toString());
        }
       
        //Add the parameters to the URL
        final Map<String, List<String>> parameters = portletUrl.getParameters();
        if (parameters != null) {
            for (final Map.Entry<String, List<String>> parameterEntry : parameters.entrySet()) {
                final String name = parameterEntry.getKey();
                final List<String> values = parameterEntry.getValue();

                this.encodeAndAppend(url.append("&"), encoding, PORTLET_PARAM_PREFIX + portletWindowIdString + SEPERATOR + name, values);
            }
        }
      
        //Add the anchor if anchoring is enabled
        if (this.useAnchors && delegationParentId == null && !RequestType.ACTION.equals(requestType) && ((windowState != null && this.anchoringWindowStates.contains(windowState)) || (windowState == null && this.anchoringWindowStates.contains(previousWindowState)))) {
            url.append("#").append(channelSubscribeId);
        }
    }
   
    /**
     * Tries to determine the encoded from the request, if not available falls back to configured default.
     *
     * @param request The current request.
     * @return The encoding to use.
     */
    protected String getEncoding(HttpServletRequest request) {
        final String encoding = request.getCharacterEncoding();
        if (encoding != null) {
            return encoding;
        }
       
        return this.defaultEncoding;
    }
   
    protected void encodeAndAppend(StringBuilder url, String encoding, String name, String... values) {
        this.encodeAndAppend(url, encoding, name, Arrays.asList(values));
    }
   
    /**
     * Encodes parameter name and value(s) on to the url using the specified encoding. The option to pass more than one
     * value is provided to avoid encoding the same name multiple times. 
     *
     * @param url The URL StringBuilder to append the parameters to
     * @param encoding The encoding to use.
     * @param name The name of the parameter
     * @param values The values for the parameter, a & will be appeneded between each name/value pair added when multiple values are passed.
     */
    protected void encodeAndAppend(StringBuilder url, String encoding, String name, List<String> values) {
        try {
            name = URLEncoder.encode(name, encoding);
        }
        catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Failed to encode portlet URL parameter name '" + name + "' for encoding '" + encoding + "'");
        }
       
        if (values.size() == 0) {
            url.append(name).append("=");
        }
        else {
            boolean first = true;
            for (final Iterator<String> valuesItr = values.iterator(); valuesItr.hasNext(); ) {
                String value = valuesItr.next();
               
                if (value == null) {
                    value = "";
                }
               
                try {
                    value = URLEncoder.encode(value, encoding);
                }
                catch (UnsupportedEncodingException e) {
                    throw new RuntimeException("Failed to encode portlet URL parameter value '" + value + "' for encoding '" + encoding + "'");
                }
               
                if (!first) {
                    url.append("&");
                }
               
                url.append(name).append("=").append(value);
                first = false;
            }
        }
    }
   

   
    /**
     * Wrapper for determining the targeted URL
     */
    private static class UrlTarget {
        public final IPortletWindowId portletWindowId;
        public final boolean fnameTarget;
       
        private UrlTarget(IPortletWindowId portletWindowId, boolean fnameTarget) {
            this.portletWindowId = portletWindowId;
            this.fnameTarget = fnameTarget;
        }
    }
}
TOP

Related Classes of org.jasig.portal.portlet.url.PortletUrlSyntaxProviderImpl$UrlTarget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.