diff --git a/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/rest/PagsRESTController.java b/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/rest/PagsRESTController.java index 43b76bab935..64d5f637a8f 100644 --- a/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/rest/PagsRESTController.java +++ b/uPortal-api/uPortal-api-rest/src/main/java/org/apereo/portal/rest/PagsRESTController.java @@ -75,9 +75,9 @@ public class PagsRESTController { * This step is necessary; the incoming URLs will sometimes have '+' * characters for spaces, and the @PathVariable magic doesn't convert them. */ - String name; + String decodedPagsGroupName; try { - name = URLDecoder.decode(pagsGroupName, "UTF-8"); + decodedPagsGroupName = URLDecoder.decode(pagsGroupName, "UTF-8"); } catch (UnsupportedEncodingException e) { res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return "{ 'error': '" + e.toString() + "' }"; @@ -85,7 +85,7 @@ public class PagsRESTController { IPerson person = personManager.getPerson(request); IPersonAttributesGroupDefinition pagsGroup = - this.pagsService.getPagsDefinitionByName(person, name); + this.pagsService.getPagsDefinitionByName(person, decodedPagsGroupName); return respondPagsGroupJson(res, pagsGroup, person, HttpServletResponse.SC_FOUND); } @@ -106,9 +106,9 @@ public class PagsRESTController { * This step is necessary; the incoming URLs will sometimes have '+' * characters for spaces, and the @PathVariable magic doesn't convert them. */ - String name; + String decodedParentGroupName; try { - name = URLDecoder.decode(parentGroupName, "UTF-8"); + decodedParentGroupName = URLDecoder.decode(parentGroupName, "UTF-8"); } catch (UnsupportedEncodingException e) { res.setStatus(HttpServletResponse.SC_BAD_REQUEST); return "{ 'error': '" + e.getMessage() + "' }"; @@ -125,10 +125,12 @@ public class PagsRESTController { // Obtain a real reference to the parent group EntityIdentifier[] eids = GroupService.searchForGroups( - name, IGroupConstants.SearchMethod.DISCRETE, IPerson.class); + decodedParentGroupName, + IGroupConstants.SearchMethod.DISCRETE, + IPerson.class); if (eids.length == 0) { res.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return "{ 'error': 'Parent group does not exist: " + name + "' }"; + return "{ 'error': 'Parent group does not exist: " + decodedParentGroupName + "' }"; } IEntityGroup parentGroup = (IEntityGroup) GroupService.getGroupMember(eids[0]); // Names must be unique diff --git a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/EntityPersonAttributesGroupStore.java b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/EntityPersonAttributesGroupStore.java index d5a30e79213..b3b1c65a98a 100644 --- a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/EntityPersonAttributesGroupStore.java +++ b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/EntityPersonAttributesGroupStore.java @@ -38,6 +38,7 @@ import org.apereo.portal.groups.pags.IPersonTester; import org.apereo.portal.groups.pags.PagsGroup; import org.apereo.portal.groups.pags.TestGroup; +import org.apereo.portal.groups.pags.dao.jpa.PagsGroupService; import org.apereo.portal.security.IPerson; import org.apereo.portal.security.PersonFactory; import org.apereo.portal.security.provider.RestrictedPerson; @@ -111,7 +112,7 @@ public boolean contains(IEntityGroup group, IGroupMember member) { if (member.isGroup()) { // PAGS groups may only contain other PAGS groups (and people, of course) final IEntityGroup ieg = (IEntityGroup) member; - if (!PagsService.SERVICE_NAME_PAGS.equals(ieg.getServiceName().toString())) { + if (!PagsGroupService.SERVICE_NAME_PAGS.equals(ieg.getServiceName().toString())) { return false; } } @@ -233,7 +234,7 @@ public Iterator findParentGroups(IGroupMember member) throws Group if (member.isGroup()) { // PAGS groups may only contain other PAGS groups (and people, of course) final IEntityGroup ieg = (IEntityGroup) member; - if (PagsService.SERVICE_NAME_PAGS.equals(ieg.getServiceName().toString())) { + if (PagsGroupService.SERVICE_NAME_PAGS.equals(ieg.getServiceName().toString())) { result = findParentGroupsForGroup((IEntityGroup) member); } } else { diff --git a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/PagsService.java b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/PagsService.java index ef767c3ad5e..b3e98d4ac7b 100644 --- a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/PagsService.java +++ b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/PagsService.java @@ -14,6 +14,9 @@ */ package org.apereo.portal.groups.pags.dao; +import static org.apereo.portal.groups.pags.dao.jpa.LocalGroupService.SERVICE_NAME_LOCAL; +import static org.apereo.portal.groups.pags.dao.jpa.PagsGroupService.SERVICE_NAME_PAGS; + import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; @@ -21,6 +24,8 @@ import org.apereo.portal.EntityIdentifier; import org.apereo.portal.groups.IEntityGroup; import org.apereo.portal.groups.IGroupConstants; +import org.apereo.portal.groups.pags.dao.jpa.LocalGroupService; +import org.apereo.portal.groups.pags.dao.jpa.PagsGroupService; import org.apereo.portal.portlet.om.IPortletDefinition; import org.apereo.portal.security.IAuthorizationPrincipal; import org.apereo.portal.security.IPermission; @@ -42,9 +47,8 @@ @Service public final class PagsService { - // These 2 should be (public) constants on their respective service classes, not here - private static final String SERVICE_NAME_LOCAL = "local"; - public static final String SERVICE_NAME_PAGS = "pags"; + @Autowired private PagsGroupService pagsGroupService; + @Autowired private LocalGroupService localGroupService; private static final String GROUP_NAME_VALIDATOR_REGEX = "^[\\w ]{5,500}$"; // 5-500 characters private static final Pattern GROUP_NAME_VALIDATOR_PATTERN = @@ -152,29 +156,15 @@ public IPersonAttributesGroupDefinition createPagsDefinition( IPersonAttributesGroupDefinition result = pagsGroupDefDao.createPersonAttributesGroupDefinition(groupName, description); if (parent != null) { - // Should refactor this switch to instead choose a service and invoke a method on it + switch (parent.getServiceName().toString()) { case SERVICE_NAME_LOCAL: - IEntityGroup member = - GroupService.findGroup( - result.getCompositeEntityIdentifierForGroup().getKey()); - if (member == null) { - String msg = - "The specified group was created, but is not present in the store: " - + result.getName(); - throw new RuntimeException(msg); - } - parent.addChild(member); - parent.updateMembers(); + localGroupService.addMember(parent, result); break; case SERVICE_NAME_PAGS: IPersonAttributesGroupDefinition parentDef = getPagsGroupDefByName(parent.getName()); - Set members = - new HashSet<>(parentDef.getMembers()); - members.add(result); - parentDef.setMembers(members); - pagsGroupDefDao.updatePersonAttributesGroupDefinition(parentDef); + pagsGroupService.addMember(parentDef, result); break; default: String msg = diff --git a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/LocalGroupService.java b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/LocalGroupService.java new file mode 100644 index 00000000000..30d34757a75 --- /dev/null +++ b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/LocalGroupService.java @@ -0,0 +1,24 @@ +package org.apereo.portal.groups.pags.dao.jpa; + +import org.apereo.portal.groups.IEntityGroup; +import org.apereo.portal.groups.pags.dao.IPersonAttributesGroupDefinition; +import org.springframework.stereotype.Service; + +@Service +public class LocalGroupService { + public static final String SERVICE_NAME_LOCAL = "local"; + + public void addMember(IEntityGroup parent, IPersonAttributesGroupDefinition result) { + IEntityGroup member = + org.apereo.portal.services.GroupService.findGroup( + result.getCompositeEntityIdentifierForGroup().getKey()); + if (member == null) { + String msg = + "The specified group was created, but is not present in the store: " + + result.getName(); + throw new RuntimeException(msg); + } + parent.addChild(member); + parent.updateMembers(); + } +} diff --git a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PagsGroupService.java b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PagsGroupService.java new file mode 100644 index 00000000000..02a6ad1a280 --- /dev/null +++ b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PagsGroupService.java @@ -0,0 +1,26 @@ +package org.apereo.portal.groups.pags.dao.jpa; + +import java.util.HashSet; +import java.util.Set; +import org.apereo.portal.groups.pags.dao.IPersonAttributesGroupDefinition; +import org.apereo.portal.groups.pags.dao.IPersonAttributesGroupDefinitionDao; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PagsGroupService { + public static final String SERVICE_NAME_PAGS = "pags"; + @Autowired private IPersonAttributesGroupDefinitionDao pagsGroupDefDao; + private final Logger logger = LoggerFactory.getLogger(getClass()); + + public void addMember( + IPersonAttributesGroupDefinition parentDef, IPersonAttributesGroupDefinition result) { + + Set members = new HashSet<>(parentDef.getMembers()); + members.add(result); + parentDef.setMembers(members); + pagsGroupDefDao.updatePersonAttributesGroupDefinition(parentDef); + } +} diff --git a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PersonAttributesGroupDefinitionImpl.java b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PersonAttributesGroupDefinitionImpl.java index 8222ecc37f1..bb1d09b0707 100644 --- a/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PersonAttributesGroupDefinitionImpl.java +++ b/uPortal-groups/uPortal-groups-pags/src/main/java/org/apereo/portal/groups/pags/dao/jpa/PersonAttributesGroupDefinitionImpl.java @@ -41,7 +41,6 @@ import org.apereo.portal.EntityIdentifier; import org.apereo.portal.groups.pags.dao.IPersonAttributesGroupDefinition; import org.apereo.portal.groups.pags.dao.IPersonAttributesGroupTestGroupDefinition; -import org.apereo.portal.groups.pags.dao.PagsService; import org.apereo.portal.security.IPerson; import org.dom4j.DocumentHelper; import org.dom4j.QName; @@ -135,7 +134,7 @@ public long getId() { @JsonIgnore public EntityIdentifier getCompositeEntityIdentifierForGroup() { return new EntityIdentifier( - PagsService.SERVICE_NAME_PAGS + "." + this.getName(), IPerson.class); + PagsGroupService.SERVICE_NAME_PAGS + "." + this.getName(), IPerson.class); } @Override diff --git a/uPortal-layout/uPortal-layout-core/src/main/java/org/apereo/portal/layout/IUserLayoutStore.java b/uPortal-layout/uPortal-layout-core/src/main/java/org/apereo/portal/layout/IUserLayoutStore.java index 653a86ab0f4..861d754833f 100644 --- a/uPortal-layout/uPortal-layout-core/src/main/java/org/apereo/portal/layout/IUserLayoutStore.java +++ b/uPortal-layout/uPortal-layout-core/src/main/java/org/apereo/portal/layout/IUserLayoutStore.java @@ -199,4 +199,19 @@ void setUserLayout( * with greater precedence come before those with lower precedence. */ double getFragmentPrecedence(long id); + + /** + * Provides a {@link Tuple} containing the "fragmentized" version of a DLM fragment + * owner's layout, together with the username. This version of the layout consistent with what + * DLM uses internally for fragments, and is created by FragmentActivator.fragmentizeLayout. + * It's important that the version returned by this method matches what DLM uses internally + * because it will be used to establish relationships between fragment layout nodes and user + * customizations of DLM fragments. + * + * @param userName The username of the user for whom the layout is retrieved. + * @param userId The unique identifier of the user. + * @return A {@link Tuple} containing the username and the "fragmentized" version of the DLM + * fragment owner's layout. + */ + Tuple getUserLayoutTuple(String userName, int userId); } diff --git a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/NodeReferenceFactory.java b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/NodeReferenceFactory.java index 1a5b58a0355..794bd29b32a 100644 --- a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/NodeReferenceFactory.java +++ b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/NodeReferenceFactory.java @@ -22,11 +22,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apereo.portal.IUserIdentityStore; -import org.apereo.portal.IUserProfile; -import org.apereo.portal.UserProfile; import org.apereo.portal.layout.IUserLayoutStore; -import org.apereo.portal.security.provider.BrokenSecurityContext; -import org.apereo.portal.security.provider.PersonImpl; import org.apereo.portal.utils.Tuple; import org.apereo.portal.xml.XmlUtilities; import org.apereo.portal.xml.xpath.XPathOperations; @@ -47,7 +43,7 @@ public final class NodeReferenceFactory { private static final Pattern DLM_PATH_REF_DELIM = Pattern.compile("\\:"); private static final Pattern USER_NODE_PATTERN = Pattern.compile("\\A([a-zA-Z]\\d*)\\z"); private static final Pattern DLM_NODE_PATTERN = Pattern.compile("u(\\d+)l\\d+([ns]\\d+)"); - + private static final int LAYOUT_ID_FIRST_NODE = 1; private final Log log = LogFactory.getLog(getClass()); @Autowired private IUserLayoutStore layoutStore; @@ -142,7 +138,7 @@ public Noderef getNoderefFromPathref( } final Tuple userLayoutInfo = - getUserLayoutTuple(layoutOwnerName, layoutOwnerUserId); + layoutStore.getUserLayoutTuple(layoutOwnerName, layoutOwnerUserId); final Document userLayout = userLayoutInfo.second.getLayout(); final Node targetNode = @@ -178,21 +174,14 @@ public Noderef getNoderefFromPathref( final String structId = structIdAttr.getTextContent(); if (isStructRef) { - return new Noderef( - layoutOwnerUserId, - 1 /* TODO: remove hard-coded layoutId=1 */, - "s" + structId); + return new Noderef(layoutOwnerUserId, LAYOUT_ID_FIRST_NODE, "s" + structId); } - return new Noderef( - layoutOwnerUserId, 1 /* TODO: remove hard-coded layoutId=1 */, "n" + structId); + return new Noderef(layoutOwnerUserId, LAYOUT_ID_FIRST_NODE, "n" + structId); } final Node idAttr = attributes.getNamedItem("ID"); - return new Noderef( - layoutOwnerUserId, - 1 /* TODO: remove hard-coded layoutId=1 */, - idAttr.getTextContent()); + return new Noderef(layoutOwnerUserId, LAYOUT_ID_FIRST_NODE, idAttr.getTextContent()); } /** @@ -229,7 +218,7 @@ public Pathref getPathrefFromNoderef( final String userName = this.userIdentityStore.getPortalUserName(userId); final Tuple userLayoutInfo = - getUserLayoutTuple(userName, userId); + layoutStore.getUserLayoutTuple(userName, userId); if (userLayoutInfo.second == null) { this.log.warn( @@ -291,35 +280,4 @@ public Pathref getPathrefFromNoderef( return result; } - - /* - * Implementation. - */ - - /** - * Provides a {@link Tuple} containing the "fragmentized" version of a DLM fragment - * owner's layout, together with the username. This version of the layout consistent with what - * DLM uses internally for fragments, and is created by FragmentActivator.fragmentizeLayout. - * It's important that the version returned by this method matches what DLM uses internally - * because it will be used to establish relationships between fragment layout nodes and user - * customizations of DLM fragments. - * - * @param userId - * @return - */ - /* TODO: make private */ Tuple getUserLayoutTuple( - String userName, int userId) { - - final PersonImpl person = new PersonImpl(); - person.setUserName(userName); - person.setID(userId); - person.setSecurityContext(new BrokenSecurityContext()); - - final IUserProfile profile = - layoutStore.getUserProfileByFname(person, UserProfile.DEFAULT_PROFILE_FNAME); - final DistributedUserLayout userLayout = - layoutStore.getUserLayout(person, (UserProfile) profile); - - return new Tuple(userName, userLayout); - } } diff --git a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java index 7e9cd739b0e..954fcfc24c2 100644 --- a/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java +++ b/uPortal-layout/uPortal-layout-impl/src/main/java/org/apereo/portal/layout/dlm/RDBMDistributedLayoutStore.java @@ -33,10 +33,7 @@ import java.util.regex.Pattern; import net.sf.ehcache.Ehcache; import org.apache.commons.lang.StringUtils; -import org.apereo.portal.AuthorizationException; -import org.apereo.portal.IUserIdentityStore; -import org.apereo.portal.IUserProfile; -import org.apereo.portal.PortalException; +import org.apereo.portal.*; import org.apereo.portal.io.xml.IPortalDataHandlerService; import org.apereo.portal.jdbc.RDBMServices; import org.apereo.portal.layout.LayoutStructure; @@ -1873,6 +1870,33 @@ private interface FormOfLayoutCorruption { String getMessage(); } + /** + * Provides a {@link Tuple} containing the "fragmentized" version of a DLM fragment + * owner's layout, together with the username. This version of the layout consistent with what + * DLM uses internally for fragments, and is created by FragmentActivator.fragmentizeLayout. + * It's important that the version returned by this method matches what DLM uses internally + * because it will be used to establish relationships between fragment layout nodes and user + * customizations of DLM fragments. + * + * @param userName The username of the user for whom the layout is retrieved. + * @param userId The unique identifier of the user. + * @return A {@link Tuple} containing the username and the "fragmentized" version of the DLM + * fragment owner's layout. + */ + @Override + public Tuple getUserLayoutTuple(String userName, int userId) { + final PersonImpl person = new PersonImpl(); + person.setUserName(userName); + person.setID(userId); + person.setSecurityContext(new BrokenSecurityContext()); + + final IUserProfile profile = + this.getUserProfileByFname(person, UserProfile.DEFAULT_PROFILE_FNAME); + final DistributedUserLayout userLayout = this.getUserLayout(person, profile); + + return new Tuple<>(userName, userLayout); + } + private static final List KNOWN_FORMS_OF_LAYOUT_CORRUPTION = Collections.unmodifiableList( Arrays.asList( diff --git a/uPortal-rendering/src/main/java/org/apereo/portal/url/UrlSyntaxProviderImpl.java b/uPortal-rendering/src/main/java/org/apereo/portal/url/UrlSyntaxProviderImpl.java index 8943c8d1442..5f2ee4a6628 100644 --- a/uPortal-rendering/src/main/java/org/apereo/portal/url/UrlSyntaxProviderImpl.java +++ b/uPortal-rendering/src/main/java/org/apereo/portal/url/UrlSyntaxProviderImpl.java @@ -14,23 +14,15 @@ */ package org.apereo.portal.url; +import static org.apereo.portal.url.PortalConstants.*; + import com.google.common.base.Function; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.portlet.PortletMode; @@ -66,39 +58,11 @@ */ @Component("portalUrlProvider") public class UrlSyntaxProviderImpl implements IUrlSyntaxProvider { - static final String SEPARATOR = "_"; - static final String PORTAL_PARAM_PREFIX = "u" + SEPARATOR; - - static final String PORTLET_CONTROL_PREFIX = "pC"; - static final String PORTLET_PARAM_PREFIX = "pP" + SEPARATOR; - static final String PORTLET_PUBLIC_RENDER_PARAM_PREFIX = "pG" + SEPARATOR; - static final String PARAM_TARGET_PORTLET = PORTLET_CONTROL_PREFIX + "t"; - static final String PARAM_ADDITIONAL_PORTLET = PORTLET_CONTROL_PREFIX + "a"; - static final String PARAM_DELEGATE_PARENT = PORTLET_CONTROL_PREFIX + "d"; - static final String PARAM_RESOURCE_ID = PORTLET_CONTROL_PREFIX + "r"; - static final String PARAM_CACHEABILITY = PORTLET_CONTROL_PREFIX + "c"; - static final String PARAM_WINDOW_STATE = PORTLET_CONTROL_PREFIX + "s"; - static final String PARAM_PORTLET_MODE = PORTLET_CONTROL_PREFIX + "m"; - static final String PARAM_COPY_PARAMETERS = PORTLET_CONTROL_PREFIX + "p"; static final Set LEGACY_URL_PATHS = ImmutableSet.of( "/render.userLayoutRootNode.uP", "/tag.idempotent.render.userLayoutRootNode.uP"); - static final String LEGACY_PARAM_PORTLET_FNAME = "uP_fname"; - static final String LEGACY_PARAM_PORTLET_REQUEST_TYPE = "pltc_type"; - static final String LEGACY_PARAM_PORTLET_STATE = "pltc_state"; - static final String LEGACY_PARAM_PORTLET_MODE = "pltc_mode"; - static final String LEGACY_PARAM_PORTLET_PARAM_PREFX = "pltp_"; - static final String LEGACY_PARAM_LAYOUT_ROOT = "root"; - static final String LEGACY_PARAM_LAYOUT_ROOT_VALUE = "uP_root"; - static final String LEGACY_PARAM_LAYOUT_STRUCT_PARAM = "uP_sparam"; - static final String LEGACY_PARAM_LAYOUT_TAB_ID = "activeTab"; - - static final String SLASH = "/"; - static final String PORTLET_PATH_PREFIX = "p"; - static final String FOLDER_PATH_PREFIX = "f"; - static final String REQUEST_TYPE_SUFFIX = ".uP"; private static final Pattern SLASH_PATTERN = Pattern.compile(SLASH); private static final String PORTAL_CANONICAL_URL = @@ -115,7 +79,7 @@ public class UrlSyntaxProviderImpl implements IUrlSyntaxProvider { * may not be suffixed with the portlet's window id */ private enum SuffixedPortletParameter { - RESOURCE_ID(UrlSyntaxProviderImpl.PARAM_RESOURCE_ID, UrlType.RESOURCE) { + RESOURCE_ID(PortalConstants.PARAM_RESOURCE_ID, UrlType.RESOURCE) { @Override public void updateRequestInfo( HttpServletRequest request, @@ -126,7 +90,7 @@ public void updateRequestInfo( portletRequestInfo.setResourceId(values.get(0)); } }, - CACHEABILITY(UrlSyntaxProviderImpl.PARAM_CACHEABILITY, UrlType.RESOURCE) { + CACHEABILITY(PortalConstants.PARAM_CACHEABILITY, UrlType.RESOURCE) { @Override public void updateRequestInfo( HttpServletRequest request, @@ -138,7 +102,7 @@ public void updateRequestInfo( } }, DELEGATE_PARENT( - UrlSyntaxProviderImpl.PARAM_DELEGATE_PARENT, + PortalConstants.PARAM_DELEGATE_PARENT, UrlType.RENDER, UrlType.ACTION, UrlType.RESOURCE) { @@ -165,7 +129,7 @@ public void updateRequestInfo( } } }, - WINDOW_STATE(UrlSyntaxProviderImpl.PARAM_WINDOW_STATE, UrlType.RENDER, UrlType.ACTION) { + WINDOW_STATE(PortalConstants.PARAM_WINDOW_STATE, UrlType.RENDER, UrlType.ACTION) { @Override public void updateRequestInfo( HttpServletRequest request, @@ -176,7 +140,7 @@ public void updateRequestInfo( portletRequestInfo.setWindowState(PortletUtils.getWindowState(values.get(0))); } }, - PORTLET_MODE(UrlSyntaxProviderImpl.PARAM_PORTLET_MODE, UrlType.RENDER, UrlType.ACTION) { + PORTLET_MODE(PortalConstants.PARAM_PORTLET_MODE, UrlType.RENDER, UrlType.ACTION) { @Override public void updateRequestInfo( HttpServletRequest request, @@ -187,7 +151,7 @@ public void updateRequestInfo( portletRequestInfo.setPortletMode(PortletUtils.getPortletMode(values.get(0))); } }, - COPY_PARAMETERS(UrlSyntaxProviderImpl.PARAM_COPY_PARAMETERS, UrlType.RENDER) { + COPY_PARAMETERS(PortalConstants.PARAM_COPY_PARAMETERS, UrlType.RENDER) { @Override public void updateRequestInfo( HttpServletRequest request, diff --git a/uPortal-url/src/main/java/org/apereo/portal/url/PortalConstants.java b/uPortal-url/src/main/java/org/apereo/portal/url/PortalConstants.java new file mode 100644 index 00000000000..e96bf834eb3 --- /dev/null +++ b/uPortal-url/src/main/java/org/apereo/portal/url/PortalConstants.java @@ -0,0 +1,32 @@ +package org.apereo.portal.url; + +public class PortalConstants { + static final String SEPARATOR = "_"; + static final String PORTAL_PARAM_PREFIX = "u" + SEPARATOR; + + static final String PORTLET_CONTROL_PREFIX = "pC"; + static final String PORTLET_PARAM_PREFIX = "pP" + SEPARATOR; + static final String PORTLET_PUBLIC_RENDER_PARAM_PREFIX = "pG" + SEPARATOR; + static final String PARAM_TARGET_PORTLET = PORTLET_CONTROL_PREFIX + "t"; + static final String PARAM_ADDITIONAL_PORTLET = PORTLET_CONTROL_PREFIX + "a"; + static final String PARAM_DELEGATE_PARENT = PORTLET_CONTROL_PREFIX + "d"; + static final String PARAM_RESOURCE_ID = PORTLET_CONTROL_PREFIX + "r"; + static final String PARAM_CACHEABILITY = PORTLET_CONTROL_PREFIX + "c"; + static final String PARAM_WINDOW_STATE = PORTLET_CONTROL_PREFIX + "s"; + static final String PARAM_PORTLET_MODE = PORTLET_CONTROL_PREFIX + "m"; + static final String PARAM_COPY_PARAMETERS = PORTLET_CONTROL_PREFIX + "p"; + static final String LEGACY_PARAM_PORTLET_FNAME = "uP_fname"; + static final String LEGACY_PARAM_PORTLET_REQUEST_TYPE = "pltc_type"; + static final String LEGACY_PARAM_PORTLET_STATE = "pltc_state"; + static final String LEGACY_PARAM_PORTLET_MODE = "pltc_mode"; + static final String LEGACY_PARAM_PORTLET_PARAM_PREFX = "pltp_"; + static final String LEGACY_PARAM_LAYOUT_ROOT = "root"; + static final String LEGACY_PARAM_LAYOUT_ROOT_VALUE = "uP_root"; + static final String LEGACY_PARAM_LAYOUT_STRUCT_PARAM = "uP_sparam"; + static final String LEGACY_PARAM_LAYOUT_TAB_ID = "activeTab"; + + static final String SLASH = "/"; + static final String PORTLET_PATH_PREFIX = "p"; + static final String FOLDER_PATH_PREFIX = "f"; + static final String REQUEST_TYPE_SUFFIX = ".uP"; +} diff --git a/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationService.java b/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationService.java index 602cf709073..3871ec8c34e 100644 --- a/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationService.java +++ b/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationService.java @@ -16,50 +16,20 @@ import com.google.common.base.Function; import com.google.common.collect.Lists; -import java.io.Serializable; -import java.io.StringReader; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; +import java.util.*; import javax.portlet.Event; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import javax.xml.namespace.QName; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; import net.sf.ehcache.Ehcache; -import net.sf.ehcache.Element; -import org.apache.commons.lang.StringUtils; import org.apache.pluto.container.PortletContainer; -import org.apache.pluto.container.PortletContainerException; import org.apache.pluto.container.PortletWindow; import org.apache.pluto.container.driver.PortletContextService; -import org.apache.pluto.container.om.portlet.ContainerRuntimeOption; -import org.apache.pluto.container.om.portlet.EventDefinition; import org.apache.pluto.container.om.portlet.EventDefinitionReference; -import org.apache.pluto.container.om.portlet.PortletApplicationDefinition; import org.apache.pluto.container.om.portlet.PortletDefinition; import org.apereo.portal.EntityIdentifier; import org.apereo.portal.IUserPreferencesManager; import org.apereo.portal.layout.IUserLayoutManager; -import org.apereo.portal.portlet.container.EventImpl; -import org.apereo.portal.portlet.om.IPortletDefinition; -import org.apereo.portal.portlet.om.IPortletDefinitionId; -import org.apereo.portal.portlet.om.IPortletDefinitionParameter; -import org.apereo.portal.portlet.om.IPortletEntity; -import org.apereo.portal.portlet.om.IPortletEntityId; -import org.apereo.portal.portlet.om.IPortletWindow; -import org.apereo.portal.portlet.om.IPortletWindowId; +import org.apereo.portal.portlet.om.*; import org.apereo.portal.portlet.registry.IPortletDefinitionRegistry; import org.apereo.portal.portlet.registry.IPortletEntityRegistry; import org.apereo.portal.portlet.registry.IPortletWindowRegistry; @@ -69,7 +39,6 @@ import org.apereo.portal.url.IPortalRequestUtils; import org.apereo.portal.user.IUserInstance; import org.apereo.portal.user.IUserInstanceManager; -import org.apereo.portal.utils.Tuple; import org.apereo.portal.utils.web.PortalWebUtils; import org.apereo.portal.xml.XmlUtilities; import org.slf4j.Logger; @@ -90,8 +59,6 @@ @Service("eventCoordinationService") public class PortletEventCoordinatationService implements IPortletEventCoordinationService { - public static final String GLOBAL_EVENT__CONTAINER_OPTION = "org.apereo.portal.globalEvent"; - private static final String PORTLET_EVENT_QUEUE = PortletEventCoordinatationService.class.getName() + ".PORTLET_EVENT_QUEUE"; @@ -148,6 +115,14 @@ public void setPortletEntityRegistry(IPortletEntityRegistry portletEntityRegistr this.portletEntityRegistry = portletEntityRegistry; } + protected final PortletEventCoordinationHelper portletEventCoordinationHelper = + new PortletEventCoordinationHelper( + this.xmlUtilities, + this.portletContextService, + this.portletWindowRegistry, + this.supportedEventCache, + this.portletDefinitionRegistry); + /** * Returns a request scoped PortletEventQueue used to track events to process and events to * dispatch @@ -230,7 +205,9 @@ public void resolvePortletEvents( final IPortletWindowId sourceWindowId = queuedEvent.getPortletWindowId(); final Event event = queuedEvent.getEvent(); - final boolean globalEvent = isGlobalEvent(request, sourceWindowId, event); + final boolean globalEvent = + this.portletEventCoordinationHelper.isGlobalEvent( + request, sourceWindowId, event); final Set portletDefinitions = new LinkedHashSet(); @@ -285,7 +262,7 @@ public void resolvePortletEvents( final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition(); final IPortletDefinitionId portletDefinitionId = portletDefinition.getPortletDefinitionId(); - if (this.supportsEvent(event, portletDefinitionId)) { + if (portletEventCoordinationHelper.supportsEvent(event, portletDefinitionId)) { this.logger.debug("{} supports event {}", portletDefinition, event); // If this is the default portlet entity remove the definition from the all defs @@ -318,7 +295,8 @@ public void resolvePortletEvents( for (final IPortletWindow portletWindow : portletWindows) { this.logger.debug("{} resolved target {}", event, portletWindow); final IPortletWindowId portletWindowId = portletWindow.getPortletWindowId(); - final Event unmarshalledEvent = this.unmarshall(portletWindow, event); + final Event unmarshalledEvent = + portletEventCoordinationHelper.unmarshall(portletWindow, event); portletEventQueue.offerEvent( portletWindowId, new QueuedEvent(sourceWindowId, unmarshalledEvent)); @@ -356,7 +334,8 @@ public void resolvePortletEvents( portletDefinition.getPortletDefinitionId(); // Check if the user can render the portlet definition before doing event tests if (ap.canRender(portletDefinitionId.getStringId())) { - if (this.supportsEvent(event, portletDefinitionId)) { + if (portletEventCoordinationHelper.supportsEvent( + event, portletDefinitionId)) { this.logger.debug("{} supports event {}", portletDefinition, event); final IPortletEntity portletEntity = @@ -373,7 +352,8 @@ public void resolvePortletEvents( final IPortletWindowId portletWindowId = portletWindow.getPortletWindowId(); final Event unmarshalledEvent = - this.unmarshall(portletWindow, event); + portletEventCoordinationHelper.unmarshall( + portletWindow, event); portletEventQueue.offerEvent( portletWindowId, new QueuedEvent(sourceWindowId, unmarshalledEvent)); @@ -384,197 +364,4 @@ public void resolvePortletEvents( } } } - - protected boolean isGlobalEvent( - HttpServletRequest request, IPortletWindowId sourceWindowId, Event event) { - final IPortletWindow portletWindow = - this.portletWindowRegistry.getPortletWindow(request, sourceWindowId); - final IPortletEntity portletEntity = portletWindow.getPortletEntity(); - final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition(); - final IPortletDefinitionId portletDefinitionId = portletDefinition.getPortletDefinitionId(); - final PortletApplicationDefinition parentPortletApplicationDescriptor = - this.portletDefinitionRegistry.getParentPortletApplicationDescriptor( - portletDefinitionId); - - final ContainerRuntimeOption globalEvents = - parentPortletApplicationDescriptor.getContainerRuntimeOption( - GLOBAL_EVENT__CONTAINER_OPTION); - if (globalEvents != null) { - final QName qName = event.getQName(); - final String qNameStr = qName.toString(); - for (final String globalEvent : globalEvents.getValues()) { - if (qNameStr.equals(globalEvent)) { - return true; - } - } - } - - return false; - } - - protected Event unmarshall(IPortletWindow portletWindow, Event event) { - // TODO make two types of Event impls, one for marshalled data and one for unmarshalled data - String value = (String) event.getValue(); - - final XMLInputFactory xmlInputFactory = this.xmlUtilities.getXmlInputFactory(); - final XMLStreamReader xml; - try { - xml = xmlInputFactory.createXMLStreamReader(new StringReader(value)); - } catch (XMLStreamException e) { - throw new IllegalStateException( - "Failed to create XMLStreamReader for portlet event: " + event, e); - } - - // now test if object is jaxb - final EventDefinition eventDefinitionDD = - getEventDefinition(portletWindow, event.getQName()); - - final PortletDefinition portletDefinition = - portletWindow.getPlutoPortletWindow().getPortletDefinition(); - final PortletApplicationDefinition application = portletDefinition.getApplication(); - final String portletApplicationName = application.getName(); - - final ClassLoader loader; - try { - loader = portletContextService.getClassLoader(portletApplicationName); - } catch (PortletContainerException e) { - throw new IllegalStateException( - "Failed to get ClassLoader for portlet application: " + portletApplicationName, - e); - } - - final String eventType = eventDefinitionDD.getValueType(); - final Class clazz; - try { - clazz = loader.loadClass(eventType).asSubclass(Serializable.class); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException( - "Declared event type '" - + eventType - + "' cannot be found in portlet application: " - + portletApplicationName, - e); - } - - // TODO cache JAXBContext in registered portlet application - final JAXBElement result; - try { - final JAXBContext jc = JAXBContext.newInstance(clazz); - final Unmarshaller unmarshaller = jc.createUnmarshaller(); - result = unmarshaller.unmarshal(xml, clazz); - } catch (JAXBException e) { - throw new IllegalArgumentException( - "Cannot create JAXBContext for event type '" - + eventType - + "' from portlet application: " - + portletApplicationName, - e); - } - - return new EventImpl(event.getQName(), result.getValue()); - } - - // TODO cache this resolution - protected EventDefinition getEventDefinition(IPortletWindow portletWindow, QName name) { - PortletApplicationDefinition appDD = - portletWindow.getPlutoPortletWindow().getPortletDefinition().getApplication(); - for (EventDefinition def : appDD.getEventDefinitions()) { - if (def.getQName() != null) { - if (def.getQName().equals(name)) return def; - } else { - QName tmp = new QName(appDD.getDefaultNamespace(), def.getName()); - if (tmp.equals(name)) return def; - } - } - throw new IllegalStateException(); - } - - protected Set getAllAliases( - QName eventName, PortletApplicationDefinition portletApplicationDefinition) { - final List eventDefinitions = - portletApplicationDefinition.getEventDefinitions(); - if (eventDefinitions == null || eventDefinitions.isEmpty()) { - return Collections.emptySet(); - } - - final String defaultNamespace = portletApplicationDefinition.getDefaultNamespace(); - - for (final EventDefinition eventDefinition : eventDefinitions) { - final QName defQName = eventDefinition.getQualifiedName(defaultNamespace); - if (defQName != null && defQName.equals(eventName)) { - final List aliases = eventDefinition.getAliases(); - if (aliases == null || aliases.isEmpty()) { - return Collections.emptySet(); - } - - return new LinkedHashSet(aliases); - } - } - - return Collections.emptySet(); - } - - protected boolean supportsEvent(Event event, IPortletDefinitionId portletDefinitionId) { - final QName eventName = event.getQName(); - - // The cache key to use - final Tuple key = - new Tuple(portletDefinitionId, eventName); - - // Check in the cache if the portlet definition supports this event - final Element element = this.supportedEventCache.get(key); - if (element != null) { - final Boolean supported = (Boolean) element.getObjectValue(); - if (supported != null) { - return supported; - } - } - - final PortletApplicationDefinition portletApplicationDescriptor = - this.portletDefinitionRegistry.getParentPortletApplicationDescriptor( - portletDefinitionId); - if (portletApplicationDescriptor == null) { - return false; - } - - final Set aliases = this.getAllAliases(eventName, portletApplicationDescriptor); - - final String defaultNamespace = portletApplicationDescriptor.getDefaultNamespace(); - - // No support found so far, do more complex namespace matching - final PortletDefinition portletDescriptor = - this.portletDefinitionRegistry.getParentPortletDescriptor(portletDefinitionId); - if (portletDescriptor == null) { - return false; - } - - final List supportedProcessingEvents = - portletDescriptor.getSupportedProcessingEvents(); - for (final EventDefinitionReference eventDefinitionReference : supportedProcessingEvents) { - final QName qualifiedName = eventDefinitionReference.getQualifiedName(defaultNamespace); - if (qualifiedName == null) { - continue; - } - - // See if the supported qname and event qname match explicitly - // Look for alias names - if (qualifiedName.equals(eventName) || aliases.contains(qualifiedName)) { - this.supportedEventCache.put(new Element(key, Boolean.TRUE)); - return true; - } - - // Look for namespaced events - if (StringUtils.isEmpty(qualifiedName.getNamespaceURI())) { - final QName namespacedName = - new QName(defaultNamespace, qualifiedName.getLocalPart()); - if (eventName.equals(namespacedName)) { - this.supportedEventCache.put(new Element(key, Boolean.TRUE)); - return true; - } - } - } - - this.supportedEventCache.put(new Element(key, Boolean.FALSE)); - return false; - } } diff --git a/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinationHelper.java b/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinationHelper.java new file mode 100644 index 00000000000..93da51d99a4 --- /dev/null +++ b/uPortal-web/src/main/java/org/apereo/portal/portlet/rendering/PortletEventCoordinationHelper.java @@ -0,0 +1,248 @@ +package org.apereo.portal.portlet.rendering; + +import java.io.Serializable; +import java.io.StringReader; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import javax.portlet.Event; +import javax.servlet.http.HttpServletRequest; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.Element; +import org.apache.commons.lang.StringUtils; +import org.apache.pluto.container.PortletContainerException; +import org.apache.pluto.container.driver.PortletContextService; +import org.apache.pluto.container.om.portlet.*; +import org.apereo.portal.portlet.container.EventImpl; +import org.apereo.portal.portlet.om.*; +import org.apereo.portal.portlet.registry.IPortletDefinitionRegistry; +import org.apereo.portal.portlet.registry.IPortletWindowRegistry; +import org.apereo.portal.utils.Tuple; +import org.apereo.portal.xml.XmlUtilities; +import org.springframework.stereotype.Component; + +@Component +public class PortletEventCoordinationHelper { + public static final String GLOBAL_EVENT__CONTAINER_OPTION = "org.apereo.portal.globalEvent"; + private XmlUtilities xmlUtilities; + private PortletContextService portletContextService; + private IPortletWindowRegistry portletWindowRegistry; + private Ehcache supportedEventCache; + + public PortletEventCoordinationHelper( + XmlUtilities xmlUtilities, + PortletContextService portletContextService, + IPortletWindowRegistry portletWindowRegistry, + Ehcache supportedEventCache, + IPortletDefinitionRegistry portletDefinitionRegistry) { + this.xmlUtilities = xmlUtilities; + this.portletContextService = portletContextService; + this.portletWindowRegistry = portletWindowRegistry; + this.supportedEventCache = supportedEventCache; + this.portletDefinitionRegistry = portletDefinitionRegistry; + } + + private IPortletDefinitionRegistry portletDefinitionRegistry; + + protected Event unmarshall(IPortletWindow portletWindow, Event event) { + // TODO make two types of Event impls, one for marshalled data and one for unmarshalled data + String value = (String) event.getValue(); + + final XMLInputFactory xmlInputFactory = this.xmlUtilities.getXmlInputFactory(); + final XMLStreamReader xml; + try { + xml = xmlInputFactory.createXMLStreamReader(new StringReader(value)); + } catch (XMLStreamException e) { + throw new IllegalStateException( + "Failed to create XMLStreamReader for portlet event: " + event, e); + } + + // now test if object is jaxb + final EventDefinition eventDefinitionDD = + getEventDefinition(portletWindow, event.getQName()); + + final PortletDefinition portletDefinition = + portletWindow.getPlutoPortletWindow().getPortletDefinition(); + final PortletApplicationDefinition application = portletDefinition.getApplication(); + final String portletApplicationName = application.getName(); + + final ClassLoader loader; + try { + loader = portletContextService.getClassLoader(portletApplicationName); + } catch (PortletContainerException e) { + throw new IllegalStateException( + "Failed to get ClassLoader for portlet application: " + portletApplicationName, + e); + } + + final String eventType = eventDefinitionDD.getValueType(); + final Class clazz; + try { + clazz = loader.loadClass(eventType).asSubclass(Serializable.class); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException( + "Declared event type '" + + eventType + + "' cannot be found in portlet application: " + + portletApplicationName, + e); + } + + // TODO cache JAXBContext in registered portlet application + final JAXBElement result; + try { + final JAXBContext jc = JAXBContext.newInstance(clazz); + final Unmarshaller unmarshaller = jc.createUnmarshaller(); + result = unmarshaller.unmarshal(xml, clazz); + } catch (JAXBException e) { + throw new IllegalArgumentException( + "Cannot create JAXBContext for event type '" + + eventType + + "' from portlet application: " + + portletApplicationName, + e); + } + + return new EventImpl(event.getQName(), result.getValue()); + } + + protected boolean isGlobalEvent( + HttpServletRequest request, IPortletWindowId sourceWindowId, Event event) { + final IPortletWindow portletWindow = + this.portletWindowRegistry.getPortletWindow(request, sourceWindowId); + final IPortletEntity portletEntity = portletWindow.getPortletEntity(); + final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition(); + final IPortletDefinitionId portletDefinitionId = portletDefinition.getPortletDefinitionId(); + final PortletApplicationDefinition parentPortletApplicationDescriptor = + this.portletDefinitionRegistry.getParentPortletApplicationDescriptor( + portletDefinitionId); + + final ContainerRuntimeOption globalEvents = + parentPortletApplicationDescriptor.getContainerRuntimeOption( + GLOBAL_EVENT__CONTAINER_OPTION); + if (globalEvents != null) { + final QName qName = event.getQName(); + final String qNameStr = qName.toString(); + for (final String globalEvent : globalEvents.getValues()) { + if (qNameStr.equals(globalEvent)) { + return true; + } + } + } + + return false; + } + + // TODO cache this resolution + protected EventDefinition getEventDefinition(IPortletWindow portletWindow, QName name) { + PortletApplicationDefinition appDD = + portletWindow.getPlutoPortletWindow().getPortletDefinition().getApplication(); + for (EventDefinition def : appDD.getEventDefinitions()) { + if (def.getQName() != null) { + if (def.getQName().equals(name)) return def; + } else { + QName tmp = new QName(appDD.getDefaultNamespace(), def.getName()); + if (tmp.equals(name)) return def; + } + } + throw new IllegalStateException(); + } + + protected Set getAllAliases( + QName eventName, PortletApplicationDefinition portletApplicationDefinition) { + final List eventDefinitions = + portletApplicationDefinition.getEventDefinitions(); + if (eventDefinitions == null || eventDefinitions.isEmpty()) { + return Collections.emptySet(); + } + + final String defaultNamespace = portletApplicationDefinition.getDefaultNamespace(); + + for (final EventDefinition eventDefinition : eventDefinitions) { + final QName defQName = eventDefinition.getQualifiedName(defaultNamespace); + if (defQName != null && defQName.equals(eventName)) { + final List aliases = eventDefinition.getAliases(); + if (aliases == null || aliases.isEmpty()) { + return Collections.emptySet(); + } + + return new LinkedHashSet(aliases); + } + } + + return Collections.emptySet(); + } + + protected boolean supportsEvent(Event event, IPortletDefinitionId portletDefinitionId) { + final QName eventName = event.getQName(); + + // The cache key to use + final Tuple key = + new Tuple(portletDefinitionId, eventName); + + // Check in the cache if the portlet definition supports this event + final Element element = this.supportedEventCache.get(key); + if (element != null) { + final Boolean supported = (Boolean) element.getObjectValue(); + if (supported != null) { + return supported; + } + } + + final PortletApplicationDefinition portletApplicationDescriptor = + this.portletDefinitionRegistry.getParentPortletApplicationDescriptor( + portletDefinitionId); + if (portletApplicationDescriptor == null) { + return false; + } + + final Set aliases = this.getAllAliases(eventName, portletApplicationDescriptor); + + final String defaultNamespace = portletApplicationDescriptor.getDefaultNamespace(); + + // No support found so far, do more complex namespace matching + final PortletDefinition portletDescriptor = + this.portletDefinitionRegistry.getParentPortletDescriptor(portletDefinitionId); + if (portletDescriptor == null) { + return false; + } + + final List supportedProcessingEvents = + portletDescriptor.getSupportedProcessingEvents(); + for (final EventDefinitionReference eventDefinitionReference : supportedProcessingEvents) { + final QName qualifiedName = eventDefinitionReference.getQualifiedName(defaultNamespace); + if (qualifiedName == null) { + continue; + } + + // See if the supported qname and event qname match explicitly + // Look for alias names + if (qualifiedName.equals(eventName) || aliases.contains(qualifiedName)) { + this.supportedEventCache.put(new Element(key, Boolean.TRUE)); + return true; + } + + // Look for namespaced events + if (StringUtils.isEmpty(qualifiedName.getNamespaceURI())) { + final QName namespacedName = + new QName(defaultNamespace, qualifiedName.getLocalPart()); + if (eventName.equals(namespacedName)) { + this.supportedEventCache.put(new Element(key, Boolean.TRUE)); + return true; + } + } + } + + this.supportedEventCache.put(new Element(key, Boolean.FALSE)); + return false; + } +} diff --git a/uPortal-webapp/src/test/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationServiceTest.java b/uPortal-webapp/src/test/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationServiceTest.java index 5f986c0f6b2..3f6116528ab 100644 --- a/uPortal-webapp/src/test/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationServiceTest.java +++ b/uPortal-webapp/src/test/java/org/apereo/portal/portlet/rendering/PortletEventCoordinatationServiceTest.java @@ -105,7 +105,8 @@ public void testSupportedEventResolution() throws Exception { .thenReturn((List) supportedProcessingEvents); final boolean supportsEvent = - portletEventCoordinatationService.supportsEvent(event, portletDefinitionId); + portletEventCoordinatationService.portletEventCoordinationHelper.supportsEvent( + event, portletDefinitionId); assertTrue(supportsEvent); } } diff --git a/uPortal-webapp/src/test/java/org/apereo/portal/url/UrlSyntaxProviderImplTest.java b/uPortal-webapp/src/test/java/org/apereo/portal/url/UrlSyntaxProviderImplTest.java index 483af326972..7e62209116b 100644 --- a/uPortal-webapp/src/test/java/org/apereo/portal/url/UrlSyntaxProviderImplTest.java +++ b/uPortal-webapp/src/test/java/org/apereo/portal/url/UrlSyntaxProviderImplTest.java @@ -14,11 +14,7 @@ */ package org.apereo.portal.url; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import static org.mockito.Mockito.when; import com.google.common.base.Function; @@ -986,22 +982,20 @@ public void testParsePortletWindowIdSuffix() { IPortletWindowId portletWindowId = this.urlSyntaxProvider.parsePortletWindowIdSuffix( request, - UrlSyntaxProviderImpl.PARAM_WINDOW_STATE, + PortalConstants.PARAM_WINDOW_STATE, ids, - UrlSyntaxProviderImpl.PARAM_WINDOW_STATE - + UrlSyntaxProviderImpl.SEPARATOR - + "pw2"); + PortalConstants.PARAM_WINDOW_STATE + PortalConstants.SEPARATOR + "pw2"); assertEquals(expectedPortletWindowId, portletWindowId); portletWindowId = this.urlSyntaxProvider.parsePortletWindowIdSuffix( request, - UrlSyntaxProviderImpl.PARAM_WINDOW_STATE, + PortalConstants.PARAM_WINDOW_STATE, ids, - UrlSyntaxProviderImpl.PARAM_WINDOW_STATE - + UrlSyntaxProviderImpl.SEPARATOR - + UrlSyntaxProviderImpl.SEPARATOR + PortalConstants.PARAM_WINDOW_STATE + + PortalConstants.SEPARATOR + + PortalConstants.SEPARATOR + "pw2"); assertNull(portletWindowId); @@ -1009,9 +1003,9 @@ public void testParsePortletWindowIdSuffix() { portletWindowId = this.urlSyntaxProvider.parsePortletWindowIdSuffix( request, - UrlSyntaxProviderImpl.PARAM_WINDOW_STATE, + PortalConstants.PARAM_WINDOW_STATE, ids, - UrlSyntaxProviderImpl.PARAM_WINDOW_STATE); + PortalConstants.PARAM_WINDOW_STATE); assertNull(portletWindowId); } @@ -1029,9 +1023,9 @@ public void testParsePortletParameterName() { Tuple portletParameterInfo = this.urlSyntaxProvider.parsePortletParameterName( request, - UrlSyntaxProviderImpl.PORTLET_PARAM_PREFIX + PortalConstants.PORTLET_PARAM_PREFIX + "pw2" - + UrlSyntaxProviderImpl.SEPARATOR + + PortalConstants.SEPARATOR + "foo", ids); @@ -1042,9 +1036,7 @@ public void testParsePortletParameterName() { portletParameterInfo = this.urlSyntaxProvider.parsePortletParameterName( request, - UrlSyntaxProviderImpl.PORTLET_PARAM_PREFIX - + UrlSyntaxProviderImpl.SEPARATOR - + "foo", + PortalConstants.PORTLET_PARAM_PREFIX + PortalConstants.SEPARATOR + "foo", ids); assertNotNull(portletParameterInfo); @@ -1054,9 +1046,9 @@ public void testParsePortletParameterName() { portletParameterInfo = this.urlSyntaxProvider.parsePortletParameterName( request, - UrlSyntaxProviderImpl.PORTLET_PARAM_PREFIX + PortalConstants.PORTLET_PARAM_PREFIX + "pw1" - + UrlSyntaxProviderImpl.SEPARATOR + + PortalConstants.SEPARATOR + "foo", ids);