/** * 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.container.properties; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableSet; import java.lang.reflect.Array; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.apereo.portal.portlet.om.IPortletWindow; import org.apereo.portal.portlet.om.IPortletWindowId; import org.apereo.portal.url.IPortalRequestUtils; import org.apereo.portal.utils.Populator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Portlet property manager that just translates properties to/from the portal request attributes * */ @Service public class PropertyToAttributePropertiesManager extends BaseRequestPropertiesManager { private IPortalRequestUtils portalRequestUtils; private BiMap<String, String> propertyToAttributeMappings = ImmutableBiMap.of(); private BiMap<String, String> attributeToPropertyMappings = ImmutableBiMap.of(); private Set<String> nonNamespacedProperties = Collections.emptySet(); /** * Map of portlet property names to attribute names, if the value is null the key will be used * for both the property and attribute name */ @Resource(name = "portletPropertyToAttributeMappings") public void setPropertyMappings(Map<String, String> propertyMappings) { this.propertyToAttributeMappings = ImmutableBiMap.copyOf(propertyMappings); this.attributeToPropertyMappings = this.propertyToAttributeMappings.inverse(); } /** * Properties that should not be namespaced with the portlet's windowId when stored as request * attributes */ @Resource(name = "nonNamespacedPortletProperties") public void setNonNamespacedProperties(Set<String> nonNamespacedProperties) { this.nonNamespacedProperties = ImmutableSet.copyOf(nonNamespacedProperties); } @Autowired public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) { this.portalRequestUtils = portalRequestUtils; } @Override public boolean addResponseProperty( HttpServletRequest portletRequest, IPortletWindow portletWindow, String property, String value) { if (this.propertyToAttributeMappings.isEmpty() && this.nonNamespacedProperties.isEmpty()) { return false; } final HttpServletRequest portalRequest = this.portalRequestUtils.getOriginalPortalRequest(portletRequest); final String attributeName = getAttributeName(portletWindow, property); final Object existingValue = portalRequest.getAttribute(attributeName); if (!(existingValue instanceof List)) { this.logger.warn( "Attribute {} for property {} exists but is NOT a List, it will be replaced", attributeName, property); this.setResponseProperty(portletRequest, portletWindow, property, value); return true; } logger.debug("Adding property {} as attribute {}", property, attributeName); @SuppressWarnings("unchecked") final List<String> values = (List<String>) existingValue; values.add(value); portalRequest.setAttribute(attributeName, values); return true; } @Override public boolean setResponseProperty( HttpServletRequest portletRequest, IPortletWindow portletWindow, String property, String value) { if (this.propertyToAttributeMappings.isEmpty() && this.nonNamespacedProperties.isEmpty()) { return false; } final HttpServletRequest portalRequest = this.portalRequestUtils.getOriginalPortalRequest(portletRequest); final String attributeName = getAttributeName(portletWindow, property); logger.debug("Setting property {} as attribute {}", property, attributeName); final List<String> values = new LinkedList<String>(); values.add(value); portalRequest.setAttribute(attributeName, values); return true; } protected String getAttributeName(IPortletWindow portletWindow, String property) { final String mappedAttributeName = this.propertyToAttributeMappings.get(property); final String attributeName; if (mappedAttributeName == null) { attributeName = property; } else { attributeName = mappedAttributeName; } if (this.nonNamespacedProperties.contains(property)) { return attributeName; } final IPortletWindowId portletWindowId = portletWindow.getPortletWindowId(); return portletWindowId.getStringId() + attributeName; } @Override public <P extends Populator<String, String>> void populateRequestProperties( HttpServletRequest portletRequest, IPortletWindow portletWindow, P propertiesPopulator) { if (this.propertyToAttributeMappings.isEmpty() && this.nonNamespacedProperties.isEmpty()) { return; } final HttpServletRequest portalRequest = this.portalRequestUtils.getOriginalPortalRequest(portletRequest); final String windowIdStr = portletWindow.getPortletWindowId().getStringId(); for (@SuppressWarnings("unchecked") final Enumeration<String> attributeNames = portalRequest.getAttributeNames(); attributeNames.hasMoreElements(); ) { final String fullAttributeName = attributeNames.nextElement(); final String propertyName = getPropertyName(windowIdStr, fullAttributeName); if (propertyName == null) { continue; } logger.debug( "Found portal request attribute {} returning as property {}", fullAttributeName, propertyName); final Object value = portalRequest.getAttribute(fullAttributeName); convertValue(propertyName, value, propertiesPopulator); } } /** Convert a request attribute name to a portlet property name */ private String getPropertyName(final String windowIdStr, final String fullAttributeName) { final String attributeName; if (this.nonNamespacedProperties.contains(fullAttributeName)) { attributeName = fullAttributeName; } else if (fullAttributeName.startsWith(windowIdStr)) { attributeName = fullAttributeName.substring(windowIdStr.length()); } else { return null; } final String mappedPropertyName = this.attributeToPropertyMappings.get(attributeName); if (mappedPropertyName == null) { logger.warn( "Attribute {} found that matches the portlet window ID but it is not listed in the propertyMappings or nonNamespacedProperties and will not be returned to the portlet", attributeName); return null; } return mappedPropertyName; } protected <P extends Populator<String, String>> void convertValue( String name, Object value, P propertiesPopulator) { if (value == null) { return; } if (value instanceof Collection) { for (final Object obj : (Collection<?>) value) { propertiesPopulator.put(name, String.valueOf(obj)); } return; } if (value.getClass().isArray()) { final int len = Array.getLength(value); for (int i = 0; i < len; i++) { propertiesPopulator.put(name, String.valueOf(Array.get(value, i))); } return; } propertiesPopulator.put(name, String.valueOf(value)); } }