}
final IUrlNodeSyntaxHelper urlNodeSyntaxHelper = this.urlNodeSyntaxHelperRegistry.getCurrentUrlNodeSyntaxHelper(request);
final PortalRequestInfoImpl portalRequestInfo = new PortalRequestInfoImpl();
IPortletWindowId targetedPortletWindowId = null;
PortletRequestInfoImpl targetedPortletRequestInfo = null;
final String[] requestPathParts = SLASH_PATTERN.split(requestPath);
UrlState requestedUrlState = null;
ParseStep parseStep = ParseStep.FOLDER;
for (int pathPartIndex = 0; pathPartIndex < requestPathParts.length; pathPartIndex++) {
String pathPart = requestPathParts[pathPartIndex];
logger.trace("In parseStep {} considering pathPart [{}].", parseStep, pathPart);
if (StringUtils.isEmpty(pathPart)) {
continue;
}
switch (parseStep) {
case FOLDER: {
parseStep = ParseStep.PORTLET;
if (FOLDER_PATH_PREFIX.equals(pathPart)) {
logger.trace("Skipping adding {} to the folders deque " +
"because it is simply the folder path prefix.", pathPart);
pathPartIndex++;
final LinkedList<String> folders = new LinkedList<String>();
for (;pathPartIndex < requestPathParts.length; pathPartIndex++) {
pathPart = requestPathParts[pathPartIndex];
if (PORTLET_PATH_PREFIX.equals(pathPart)) {
logger.trace("Found the portlet part of the path " +
"demarked by portlet path prefix [{}]; " +
"stepping back one path part to finish folder processing", pathPart);
pathPartIndex--;
break;
} else {
if (pathPart.endsWith(REQUEST_TYPE_SUFFIX)) {
logger.trace("Found the end of the folder path with pathPart [{}];" +
" stepping back one, checking for state, " +
"and finishing folder parsing", pathPart);
pathPartIndex--;
pathPart = requestPathParts[pathPartIndex];
// If a state was added to the folder list remove it and step back one so
// other code can handle it
if (UrlState.valueOfIngoreCase(pathPart, null) != null) {
logger.trace("A state was added to the end of folder list {};" +
" removing it.", folders);
folders.removeLast();
pathPartIndex--;
}
break;
}
}
logger.trace("Adding pathPart [{}] to folders.", pathPart);
folders.add(pathPart);
}
logger.trace("Folders is [{}]", folders);
if (folders.size() > 0) {
final String targetedLayoutNodeId = urlNodeSyntaxHelper.getLayoutNodeForFolderNames(request, folders);
portalRequestInfo.setTargetedLayoutNodeId(targetedLayoutNodeId);
}
break;
}
}
case PORTLET: {
parseStep = ParseStep.STATE;
final String targetedLayoutNodeId = portalRequestInfo.getTargetedLayoutNodeId();
if (PORTLET_PATH_PREFIX.equals(pathPart)) {
if (++pathPartIndex < requestPathParts.length) {
pathPart = requestPathParts[pathPartIndex];
targetedPortletWindowId = urlNodeSyntaxHelper.getPortletForFolderName(request, targetedLayoutNodeId, pathPart);
}
break;
}
//See if a portlet was targeted by parameter
final String[] targetedPortletIds = parameterMap.remove(PARAM_TARGET_PORTLET);
if (targetedPortletIds != null && targetedPortletIds.length > 0) {
final String targetedPortletString = targetedPortletIds[0];
targetedPortletWindowId = urlNodeSyntaxHelper.getPortletForFolderName(request, targetedLayoutNodeId, targetedPortletString);
}
}
case STATE: {
parseStep = ParseStep.TYPE;
//States other than the default only make sense if a portlet is being targeted
if (targetedPortletWindowId == null) {
break;
}
requestedUrlState = UrlState.valueOfIngoreCase(pathPart, null);
//Set the URL state
if (requestedUrlState != null) {
portalRequestInfo.setUrlState(requestedUrlState);
//If the request is stateless
if (statelessUrlStates.contains(requestedUrlState)) {
final IPortletWindow statelessPortletWindow = this.portletWindowRegistry.getOrCreateStatelessPortletWindow(request, targetedPortletWindowId);
targetedPortletWindowId = statelessPortletWindow.getPortletWindowId();
}
//Create the portlet request info
targetedPortletRequestInfo = portalRequestInfo.getPortletRequestInfo(targetedPortletWindowId);
portalRequestInfo.setTargetedPortletWindowId(targetedPortletWindowId);
//Set window state based on URL State first then look for the window state parameter
switch (requestedUrlState) {
case MAX: {
targetedPortletRequestInfo.setWindowState(WindowState.MAXIMIZED);
}
break;
case DETACHED: {
targetedPortletRequestInfo.setWindowState(IPortletRenderer.DETACHED);
}
break;
case EXCLUSIVE: {
targetedPortletRequestInfo.setWindowState(IPortletRenderer.EXCLUSIVE);
}
break;
}
break;
}
}
case TYPE: {
parseStep = ParseStep.COMPLETE;
if (pathPartIndex == requestPathParts.length - 1 && pathPart.endsWith(REQUEST_TYPE_SUFFIX) && pathPart.length() > REQUEST_TYPE_SUFFIX.length()) {
final String urlTypePart = pathPart.substring(0, pathPart.length() - REQUEST_TYPE_SUFFIX.length());
final UrlType urlType;
//Handle inline resourceIds, look for a . in the request type string and use the suffix as the urlType
final int lastPeriod = urlTypePart.lastIndexOf('.');
if (lastPeriod >= 0 && lastPeriod < urlTypePart.length()) {
final String urlTypePartSuffix = urlTypePart.substring(lastPeriod + 1);
urlType = UrlType.valueOfIngoreCase(urlTypePartSuffix, null);
if (urlType == UrlType.RESOURCE && targetedPortletRequestInfo != null) {
final String resourceId = urlTypePart.substring(0, lastPeriod);
targetedPortletRequestInfo.setResourceId(resourceId);
}
}
else {
urlType = UrlType.valueOfIngoreCase(urlTypePart, null);
}
if (urlType != null) {
portalRequestInfo.setUrlType(urlType);
break;
}
}
}
}
}
//If a targeted portlet window ID is found but no targeted portlet request info has been retrieved yet, set it up
if (targetedPortletWindowId != null && targetedPortletRequestInfo == null) {
targetedPortletRequestInfo = portalRequestInfo.getPortletRequestInfo(targetedPortletWindowId);
portalRequestInfo.setTargetedPortletWindowId(targetedPortletWindowId);
}
//Get the set of portlet window ids that also have parameters on the url
final String[] additionalPortletIdArray = parameterMap.remove(PARAM_ADDITIONAL_PORTLET);
final Set<String> additionalPortletIds = Sets.newHashSet(additionalPortletIdArray != null ? additionalPortletIdArray : new String[0]);
//Used if there is delegation to capture form-submit and other non-prefixed parameters
//Map of parent id to delegate id
final Map<IPortletWindowId, IPortletWindowId> delegateIdMappings = new LinkedHashMap<IPortletWindowId, IPortletWindowId>(0);
//Parse all remaining parameters from the request
final Set<Entry<String, String[]>> parameterEntrySet = parameterMap.entrySet();
for (final Iterator<Entry<String, String[]>> parameterEntryItr = parameterEntrySet.iterator(); parameterEntryItr.hasNext(); ) {
final Entry<String, String[]> parameterEntry = parameterEntryItr.next();
final String name = parameterEntry.getKey();
final List<String> values = Arrays.asList(parameterEntry.getValue());
/* NOTE: continues are being used to allow fall-through behavior like a switch statement would provide */
//Portal Parameters, just need to remove the prefix
if (name.startsWith(PORTAL_PARAM_PREFIX)) {
final Map<String, List<String>> portalParameters = portalRequestInfo.getPortalParameters();
portalParameters.put(this.safeSubstringAfter(PORTAL_PARAM_PREFIX, name), values);
parameterEntryItr.remove();
continue;
}
//Generic portlet parameters, have to remove the prefix and see if there was a portlet windowId between the prefix and parameter name
if (name.startsWith(PORTLET_PARAM_PREFIX)) {
final Tuple<String, IPortletWindowId> portletParameterParts = this.parsePortletParameterName(request, name, additionalPortletIds);
final IPortletWindowId portletWindowId = portletParameterParts.second;
final String paramName = portletParameterParts.first;
//Get the portlet parameter map to add the parameter to
final Map<String, List<String>> portletParameters;
if (portletWindowId == null) {
if (targetedPortletRequestInfo == null) {
this.logger.warn("Parameter " + name + " is for the targeted portlet but no portlet is targeted by the request. The parameter will be ignored. Value: " + values);
parameterEntryItr.remove();
break;
}
portletParameters = targetedPortletRequestInfo.getPortletParameters();
}
else {
final PortletRequestInfoImpl portletRequestInfoImpl = portalRequestInfo.getPortletRequestInfo(portletWindowId);
portletParameters = portletRequestInfoImpl.getPortletParameters();
}
portletParameters.put(paramName, values);
parameterEntryItr.remove();
continue;
}
//Portlet control parameters are either used directly or as a prefix to a windowId. Use the SuffixedPortletParameter to simplify their parsing
for (final SuffixedPortletParameter suffixedPortletParameter : SuffixedPortletParameter.values()) {
final String parameterPrefix = suffixedPortletParameter.getParameterPrefix();
//Skip to the next parameter prefix if the current doesn't match
if (!name.startsWith(parameterPrefix)) {
continue;
}
//All of these parameters require at least one value
if (values.isEmpty()) {
this.logger.warn("Ignoring parameter " + name + " as it must have a value. Value: " + values);
break;
}
//Verify the parameter is being used on the correct type of URL
final Set<UrlType> validUrlTypes = suffixedPortletParameter.getValidUrlTypes();
if (!validUrlTypes.contains(portalRequestInfo.getUrlType())) {
this.logger.warn("Ignoring parameter " + name + " as it is only valid for " + validUrlTypes + " requests and this is a " + portalRequestInfo.getUrlType() + " request. Value: " + values);
break;
}
//Determine the portlet window and request info the parameter targets
final IPortletWindowId portletWindowId = this.parsePortletWindowIdSuffix(request, parameterPrefix, additionalPortletIds, name);
final PortletRequestInfoImpl portletRequestInfo = getTargetedPortletRequestInfo(portalRequestInfo, targetedPortletRequestInfo, portletWindowId);
if (portletRequestInfo == null) {
this.logger.warn("Parameter " + name + " is for the targeted portlet but no portlet is targeted by the request. The parameter will be ignored. Value: " + values);
break;
}