/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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.apereo.portal.portlet.registry; import java.util.regex.Pattern; import org.apache.commons.lang3.ArrayUtils; /** * Utility class for defining methods to be used for dealing with portlet window ID strings. * * <p>A portlet window ID string is a portlet entity ID string that may contain a period separator * and a portlet window instance ID. Formats: <portlet-entity-id> * <portlet-entity-id>.<portlet-window-instance-id> * * <p>Examples: 88_n149_52 71_u54_12.2 10_ctf2_32.tw // the 'ctf' and 'tw' here are specific to * transient portlets * * @see PortletEntityIdStringUtils * @see TransientUserLayoutManagerWrapper#SUBSCRIBE_PREFIX * @see PortletWindowRegistryImpl#STATELESS_PORTLET_WINDOW_ID */ public class PortletWindowIdStringUtils { private static final char ID_PART_SEPARATOR = '.'; private static final Pattern ID_PART_SEPARATOR_PATTERN = Pattern.compile(Pattern.quote(String.valueOf(ID_PART_SEPARATOR))); public static String format( final String portletEntityId, final String portletWindowInstanceId) { return (portletWindowInstanceId == null) ? portletEntityId : portletEntityId + ID_PART_SEPARATOR + portletWindowInstanceId; } public static String convertToDelegateLayoutNodeId(final String portletWindowIdString) { final String portletEntityIdString = parsePortletEntityId(portletWindowIdString); final String portletWindowInstanceIdString = parsePortletWindowInstanceId(portletWindowIdString); final String converted = PortletEntityIdStringUtils.convertToDelegateLayoutNodeId(portletEntityIdString); return (portletWindowInstanceIdString == null) ? converted : converted + ID_PART_SEPARATOR + portletWindowInstanceIdString; } public static String parsePortletEntityId(final String portletWindowIdString) { return parseParts(portletWindowIdString)[0]; } public static String parsePortletWindowInstanceId(final String portletWindowIdString) { final String[] parts = parseParts(portletWindowIdString); return parts.length > 1 ? parts[1] : null; } public static boolean hasPortletWindowInstanceId(final String portletWindowIdString) { return parseParts(portletWindowIdString).length > 1; } public static boolean hasCorrectNumberOfParts(final String portletWindowIdString) { int length = parseParts(portletWindowIdString).length; return length == 1 || length == 2; } /** * Parses parts of the portlet window ID string. For input "88_n149_52", should return: { * "88_n149_52" } For input "88_n149_52.tw", should return: { "88_n149_52", "tw" } For input * "88_n149_52.1.2", should return: { "88_n149_52", "1", "2" } // note that the input here is * invalid due to having too many parts For input "146_dlg-5-ctf1-18.tw_18", should return: { * "146_dlg-5-ctf1-18.tw_18" } For input "146_dlg-5-ctf1-18.tw_18.1", should return: { * "146_dlg-5-ctf1-18.tw_18", "1" } */ private static String[] parseParts(final String portletWindowIdString) { // Note that we cannot simply use the ID_PART_SEPARATOR_PATTERN on 'portletWindowIdString' because it may have a // 'delegate' layout node id that itself has a portlet window instance id, and thus the period in the layout node ID part // will mess up the parsing. // Example: "146_dlg-5-ctf1-18.tw_18.1" would parse into { "146_dlg-5-ctf1-18", "tw_18", "1"} instead of { "146_dlg-5-ctf1-18.tw_18", "1" } final UserIdAndOtherParts userIdAndOtherParts = parseUserIdAndOtherParts(portletWindowIdString); if (userIdAndOtherParts.portletWindowInstanceId == null) { return new String[] {portletWindowIdString}; } else { final String portletDefinitionId = PortletEntityIdStringUtils.parsePortletDefinitionId(portletWindowIdString); final String layoutNodeId = PortletEntityIdStringUtils.parseLayoutNodeId(portletWindowIdString); final String portletEntityId = PortletEntityIdStringUtils.format( portletDefinitionId, layoutNodeId, userIdAndOtherParts.userId); return createPartsArray( portletEntityId, userIdAndOtherParts.portletWindowInstanceId, userIdAndOtherParts.extraParts); } } private static String[] createPartsArray( final String portletEntityId, final String portletWindowInstanceId, final String[] extraParts) { final String[] results = new String[2 + ((extraParts == null) ? 0 : extraParts.length)]; results[0] = portletEntityId; results[1] = portletWindowInstanceId; if (extraParts != null) { for (int i = 0; i < extraParts.length; i++) { results[i + 2] = extraParts[i]; } } return results; } private static UserIdAndOtherParts parseUserIdAndOtherParts( final String portletWindowIdString) { final UserIdAndOtherParts result = new UserIdAndOtherParts(); final String userId = PortletEntityIdStringUtils.parseUserIdAsString(portletWindowIdString); final String[] parts = ID_PART_SEPARATOR_PATTERN.split(userId); if (parts.length > 0) { result.userId = parts[0]; if (parts.length > 1) { result.portletWindowInstanceId = parts[1]; if (parts.length > 2) { result.extraParts = ArrayUtils.subarray(parts, 2, parts.length); } } } return result; } static class UserIdAndOtherParts { public UserIdAndOtherParts() {} public String userId; public String portletWindowInstanceId; public String[] extraParts; public int getPartsCount() { return (userId == null) ? 0 : (portletWindowInstanceId == null) ? 1 : (extraParts == null) ? 2 : 2 + extraParts.length; } } }