/** * 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.layout; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import java.util.LinkedHashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils; import org.apereo.portal.IUserPreferencesManager; import org.apereo.portal.IUserProfile; import org.apereo.portal.layout.dao.IStylesheetDescriptorDao; import org.apereo.portal.layout.dao.IStylesheetUserPreferencesDao; import org.apereo.portal.layout.om.ILayoutAttributeDescriptor; import org.apereo.portal.layout.om.IOutputPropertyDescriptor; import org.apereo.portal.layout.om.IStylesheetData; import org.apereo.portal.layout.om.IStylesheetData.Scope; import org.apereo.portal.layout.om.IStylesheetDescriptor; import org.apereo.portal.layout.om.IStylesheetParameterDescriptor; import org.apereo.portal.layout.om.IStylesheetUserPreferences; import org.apereo.portal.security.IPerson; import org.apereo.portal.user.IUserInstance; import org.apereo.portal.user.IUserInstanceManager; import org.apereo.portal.utils.IFragmentDefinitionUtils; import org.apereo.portal.utils.Populator; import org.apereo.portal.utils.web.PortalWebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.util.WebUtils; /** * Handles retrieving and storing the various scopes of stylesheet user preference data. * */ @Service public class StylesheetUserPreferencesServiceImpl implements IStylesheetUserPreferencesService { private static final String OUTPUT_PROPERTIES_KEY = StylesheetUserPreferencesServiceImpl.class.getName() + ".OUTPUT_PROPERTIES"; private static final String STYLESHEET_PARAMETERS_KEY = StylesheetUserPreferencesServiceImpl.class.getName() + ".STYLESHEET_PARAMETERS"; private static final String LAYOUT_ATTRIBUTES_KEY = StylesheetUserPreferencesServiceImpl.class.getName() + ".LAYOUT_ATTRIBUTES"; public static final String STYLESHEET_STRUCTURE_OVERRIDE_REQUEST_ATTRIBUTE = StylesheetUserPreferencesServiceImpl.class.getCanonicalName() + ".STYLESHEET_STRUCTURE_NAME"; public static final String STYLESHEET_THEME_OVERRIDE_REQUEST_ATTRIBUTE_NAME = StylesheetUserPreferencesServiceImpl.class.getCanonicalName() + ".STYLESHEET_THEME_NAME"; protected final Logger logger = LoggerFactory.getLogger(getClass()); private IFragmentDefinitionUtils fragmentUtils; private IUserInstanceManager userInstanceManager; private IStylesheetDescriptorDao stylesheetDescriptorDao; private IStylesheetUserPreferencesDao stylesheetUserPreferencesDao; @Autowired public void setUserInstanceManager(IUserInstanceManager userInstanceManager) { this.userInstanceManager = userInstanceManager; } @Autowired public void setStylesheetDescriptorDao(IStylesheetDescriptorDao stylesheetDescriptorDao) { this.stylesheetDescriptorDao = stylesheetDescriptorDao; } @Autowired public void setStylesheetUserPreferencesDao( IStylesheetUserPreferencesDao stylesheetUserPreferencesDao) { this.stylesheetUserPreferencesDao = stylesheetUserPreferencesDao; } @Autowired public void setFragmentDefinitionUtils(final IFragmentDefinitionUtils utils) { this.fragmentUtils = utils; } protected static final class StylesheetPreferencesKey { private final IPerson person; private final IUserProfile userProfile; private final IStylesheetDescriptor stylesheetDescriptor; private final String str; private StylesheetPreferencesKey( IPerson person, IUserProfile userProfile, IStylesheetDescriptor stylesheetDescriptor) { this.person = person; this.userProfile = userProfile; this.stylesheetDescriptor = stylesheetDescriptor; this.str = "[" + stylesheetDescriptor.getId() + "," + person.getUserName() + "," + userProfile.getProfileId() + "]"; } public String toString() { return this.str; } } protected final StylesheetPreferencesKey getStylesheetPreferencesKey( HttpServletRequest request, PreferencesScope prefScope) { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request); final IPerson person = userInstance.getPerson(); final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager(); final IUserProfile userProfile = preferencesManager.getUserProfile(); final IStylesheetDescriptor stylesheetDescriptor = getStylesheetDescriptor(request, prefScope); return new StylesheetPreferencesKey(person, userProfile, stylesheetDescriptor); } protected final IStylesheetUserPreferences getDistributedStylesheetUserPreferences( HttpServletRequest request, PreferencesScope prefScope) { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request); final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager(); final IUserLayoutManager userLayoutManager = preferencesManager.getUserLayoutManager(); final IUserLayout userLayout = userLayoutManager.getUserLayout(); return prefScope.getDistributedIStylesheetUserPreferences(userLayout); } protected final Scope getWriteScope( HttpServletRequest request, PreferencesScope prefScope, StylesheetPreferencesKey stylesheetPreferencesKey, IStylesheetData descriptor) { final Scope scope = descriptor.getScope(); final boolean persistentScopeReadOnly = stylesheetPreferencesKey.person.isGuest(); if (persistentScopeReadOnly && Scope.PERSISTENT == scope) { return Scope.SESSION; } return scope; } protected final boolean compareValues(String value, String defaultValue) { return value == defaultValue || (value != null && value.equals(defaultValue)); } protected final <T> T getDataValue( HttpServletRequest request, StylesheetPreferencesKey stylesheetPreferencesKey, Scope scope, String mapKey, String name) { switch (scope) { case SESSION: { final HttpSession session = request.getSession(false); if (session == null) { return null; } final Map<String, T> outputProperties = PortalWebUtils.getMapSessionAttribute( session, mapKey + stylesheetPreferencesKey.toString(), false); if (outputProperties == null) { return null; } return outputProperties.get(name); } case REQUEST: { final Map<String, T> outputProperties = PortalWebUtils.getMapRequestAttribute( request, mapKey + stylesheetPreferencesKey.toString(), false); if (outputProperties == null) { return null; } return outputProperties.get(name); } default: { return null; } } } protected final <T> T putDataValue( HttpServletRequest request, StylesheetPreferencesKey stylesheetPreferencesKey, Scope scope, String mapKey, String name, T value) { switch (scope) { case SESSION: { final HttpSession session = request.getSession(); final Map<String, T> outputProperties = PortalWebUtils.getMapSessionAttribute( session, mapKey + stylesheetPreferencesKey.toString()); return outputProperties.put(name, value); } case REQUEST: { final Map<String, T> outputProperties = PortalWebUtils.getMapRequestAttribute( request, mapKey + stylesheetPreferencesKey.toString()); return outputProperties.put(name, value); } default: { return null; } } } protected final <T> T removeDataValue( HttpServletRequest request, StylesheetPreferencesKey stylesheetPreferencesKey, Scope scope, String mapKey, String name) { switch (scope) { case SESSION: { final HttpSession session = request.getSession(false); if (session == null) { return null; } final Map<String, T> outputProperties = PortalWebUtils.getMapSessionAttribute( session, mapKey + stylesheetPreferencesKey.toString(), false); if (outputProperties == null) { return null; } return outputProperties.remove(name); } case REQUEST: { final Map<String, T> outputProperties = PortalWebUtils.getMapRequestAttribute( request, mapKey + stylesheetPreferencesKey.toString(), false); if (outputProperties == null) { return null; } return outputProperties.remove(name); } default: { return null; } } } @Override public IStylesheetDescriptor getStylesheetDescriptor( HttpServletRequest request, PreferencesScope prefScope) { String stylesheetName = this.getStyleSheetName(request, prefScope); if (!StringUtils.isBlank(stylesheetName)) { return this.stylesheetDescriptorDao.getStylesheetDescriptorByName(stylesheetName); } else { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request); final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager(); final IUserProfile userProfile = preferencesManager.getUserProfile(); final int stylesheetId = prefScope.getStylesheetId(userProfile); return this.stylesheetDescriptorDao.getStylesheetDescriptor(stylesheetId); } } @Transactional @Override public String removeOutputProperty( HttpServletRequest request, PreferencesScope prefScope, String name) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final IOutputPropertyDescriptor outputPropertyDescriptor = stylesheetDescriptor.getOutputPropertyDescriptor(name); if (outputPropertyDescriptor == null) { logger.warn( "Attempted to remove output property '{}' but no such output property is defined in stylesheet descriptor '{}'. It will be ignored", new Object[] {name, stylesheetDescriptor.getName()}); return null; } final Scope scope = this.getWriteScope( request, prefScope, stylesheetPreferencesKey, outputPropertyDescriptor); switch (scope) { case PERSISTENT: { final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { return null; } final String oldValue = stylesheetUserPreferences.removeOutputProperty(name); this.stylesheetUserPreferencesDao.storeStylesheetUserPreferences( stylesheetUserPreferences); this.clearStylesheetUserPreferencesCache(request, stylesheetPreferencesKey); return oldValue; } default: { return removeDataValue( request, stylesheetPreferencesKey, scope, OUTPUT_PROPERTIES_KEY, name); } } } @Override public <P extends Populator<String, String>> P populateOutputProperties( HttpServletRequest request, PreferencesScope prefScope, P properties) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; //Get the scoped sources once final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); final Map<String, String> sessionOutputProperties; final HttpSession session = request.getSession(false); if (session == null) { sessionOutputProperties = null; } else { sessionOutputProperties = PortalWebUtils.getMapSessionAttribute( session, OUTPUT_PROPERTIES_KEY + stylesheetPreferencesKey.toString(), false); } final Map<String, String> requestOutputProperties = PortalWebUtils.getMapRequestAttribute( request, OUTPUT_PROPERTIES_KEY + stylesheetPreferencesKey.toString(), false); //Try getting each output property to populate the Properties for (final IOutputPropertyDescriptor outputPropertyDescriptor : stylesheetDescriptor.getOutputPropertyDescriptors()) { final String name = outputPropertyDescriptor.getName(); final String value; final Scope scope = outputPropertyDescriptor.getScope(); switch (scope) { case PERSISTENT: { if (stylesheetUserPreferences == null) { value = null; break; } value = stylesheetUserPreferences.getOutputProperty(name); break; } case SESSION: { if (sessionOutputProperties == null) { value = null; break; } value = sessionOutputProperties.get(name); break; } case REQUEST: { if (requestOutputProperties == null) { value = null; break; } value = requestOutputProperties.get(name); break; } default: { value = null; break; } } //Don't add unset properties if (value == null) { continue; } //If the value is equal to the default value remove the property and return null if (this.compareValues(value, outputPropertyDescriptor.getDefaultValue())) { this.removeOutputProperty(request, prefScope, name); continue; } properties.put(name, value); } return properties; } @Override public String getStylesheetParameter( HttpServletRequest request, PreferencesScope prefScope, String name) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final IStylesheetParameterDescriptor stylesheetParameterDescriptor = stylesheetDescriptor.getStylesheetParameterDescriptor(name); if (stylesheetParameterDescriptor == null) { logger.warn( "Attempted to get stylesheet parameter '{}' but no such stylesheet parameter is defined in stylesheet descriptor '{}'. null will be returned", new Object[] {name, stylesheetDescriptor.getName()}); return null; } final String value; final Scope scope = stylesheetParameterDescriptor.getScope(); switch (scope) { case PERSISTENT: { final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { return null; } value = stylesheetUserPreferences.getStylesheetParameter(name); break; } default: { value = this.getDataValue( request, stylesheetPreferencesKey, scope, STYLESHEET_PARAMETERS_KEY, name); break; } } if (value == null) { return null; } //If the value is equal to the default value remove the property and return null if (this.compareValues(value, stylesheetParameterDescriptor.getDefaultValue())) { this.removeStylesheetParameter(request, prefScope, name); return null; } return value; } @Transactional @Override public String setStylesheetParameter( HttpServletRequest request, PreferencesScope prefScope, String name, String value) { logger.trace( "Setting stylesheet parameter {} with scope {} to {}.", name, prefScope, value); final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final IStylesheetParameterDescriptor stylesheetParameterDescriptor = stylesheetDescriptor.getStylesheetParameterDescriptor(name); if (stylesheetParameterDescriptor == null) { logger.warn( "Attempted to set stylesheet parameter {}={} but no such stylesheet parameter is defined in stylesheet descriptor {}. It will be ignored", new Object[] {name, value, stylesheetDescriptor.getName()}); return null; } if (this.compareValues(value, stylesheetParameterDescriptor.getDefaultValue())) { return this.removeStylesheetParameter(request, prefScope, name); } final Scope scope = this.getWriteScope( request, prefScope, stylesheetPreferencesKey, stylesheetParameterDescriptor); switch (scope) { case PERSISTENT: { IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { stylesheetUserPreferences = this.stylesheetUserPreferencesDao.createStylesheetUserPreferences( stylesheetDescriptor, stylesheetPreferencesKey.person, stylesheetPreferencesKey.userProfile); this.clearStylesheetUserPreferencesCache(request, stylesheetPreferencesKey); } final String oldValue = stylesheetUserPreferences.setStylesheetParameter(name, value); this.stylesheetUserPreferencesDao.storeStylesheetUserPreferences( stylesheetUserPreferences); return oldValue; } default: { return this.putDataValue( request, stylesheetPreferencesKey, scope, STYLESHEET_PARAMETERS_KEY, name, value); } } } @Transactional @Override public String removeStylesheetParameter( HttpServletRequest request, PreferencesScope prefScope, String name) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final IStylesheetParameterDescriptor stylesheetParameterDescriptor = stylesheetDescriptor.getStylesheetParameterDescriptor(name); if (stylesheetParameterDescriptor == null) { logger.warn( "Attempted to remove stylesheet parameter {} but no such stylesheet parameter is defined in stylesheet descriptor {}. It will be ignored", new Object[] {name, stylesheetDescriptor.getName()}); return null; } final Scope scope = this.getWriteScope( request, prefScope, stylesheetPreferencesKey, stylesheetParameterDescriptor); switch (scope) { case PERSISTENT: { final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { return null; } final String oldValue = stylesheetUserPreferences.removeStylesheetParameter(name); this.stylesheetUserPreferencesDao.storeStylesheetUserPreferences( stylesheetUserPreferences); return oldValue; } default: { return removeDataValue( request, stylesheetPreferencesKey, scope, STYLESHEET_PARAMETERS_KEY, name); } } } @Override public <P extends Populator<String, String>> P populateStylesheetParameters( HttpServletRequest request, PreferencesScope prefScope, P stylesheetParameters) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; //Get the scoped sources once final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); final Map<String, String> sessionStylesheetParameters; final HttpSession session = request.getSession(false); if (session == null) { sessionStylesheetParameters = null; } else { sessionStylesheetParameters = PortalWebUtils.getMapSessionAttribute( session, STYLESHEET_PARAMETERS_KEY + stylesheetPreferencesKey.toString(), false); } final Map<String, String> requestStylesheetParameters = PortalWebUtils.getMapRequestAttribute( request, STYLESHEET_PARAMETERS_KEY + stylesheetPreferencesKey.toString(), false); //Try getting each stylesheet parameter to populate the Map for (final IStylesheetParameterDescriptor stylesheetParameterDescriptor : stylesheetDescriptor.getStylesheetParameterDescriptors()) { final String name = stylesheetParameterDescriptor.getName(); final String value; final Scope scope = stylesheetParameterDescriptor.getScope(); switch (scope) { case PERSISTENT: { if (stylesheetUserPreferences == null) { value = null; break; } value = stylesheetUserPreferences.getStylesheetParameter(name); break; } case SESSION: { if (sessionStylesheetParameters == null) { value = null; break; } value = sessionStylesheetParameters.get(name); break; } case REQUEST: { if (requestStylesheetParameters == null) { value = null; break; } value = requestStylesheetParameters.get(name); break; } default: { value = null; break; } } //Don't add unset properties if (value == null) { continue; } //If the value is equal to the default value remove the property and return null if (this.compareValues(value, stylesheetParameterDescriptor.getDefaultValue())) { this.removeStylesheetParameter(request, prefScope, name); continue; } stylesheetParameters.put(name, value); } return stylesheetParameters; } @Override public String getLayoutAttribute( HttpServletRequest request, PreferencesScope prefScope, String nodeId, String name) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final ILayoutAttributeDescriptor layoutAttributeDescriptor = stylesheetDescriptor.getLayoutAttributeDescriptor(name); if (layoutAttributeDescriptor == null) { logger.warn( "Attempted to get layout attribute {} for ID=\"{}\" but no such stylesheet parameter is defined in stylesheet descriptor {}. Null will be returned", new Object[] {name, nodeId, stylesheetDescriptor.getName()}); return null; } //Load the default value String defaultValue = null; final IStylesheetUserPreferences distributedStylesheetUserPreferences = this.getDistributedStylesheetUserPreferences(request, prefScope); if (distributedStylesheetUserPreferences != null) { defaultValue = distributedStylesheetUserPreferences.getLayoutAttribute(nodeId, name); // special handling for fragment owner if (this.isFragmentOwnerStylesheetPreferencesKey(stylesheetPreferencesKey)) { return defaultValue; } if (this.compareValues(defaultValue, layoutAttributeDescriptor.getDefaultValue())) { //DLM attribute value matches the stylesheet descriptor default, remove the DLM value distributedStylesheetUserPreferences.removeLayoutAttribute(nodeId, name); defaultValue = null; } } final String value; final Scope scope = layoutAttributeDescriptor.getScope(); switch (scope) { case PERSISTENT: { final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { value = null; break; } value = stylesheetUserPreferences.getLayoutAttribute(nodeId, name); break; } default: { final Map<String, String> nodeAttributes = this.getDataValue( request, stylesheetPreferencesKey, scope, LAYOUT_ATTRIBUTES_KEY, nodeId); if (nodeAttributes == null) { value = null; break; } value = nodeAttributes.get(name); break; } } if (value == null) { return defaultValue; } if (!this.isFragmentOwnerStylesheetPreferencesKey(stylesheetPreferencesKey)) { if (this.compareValues(value, layoutAttributeDescriptor.getDefaultValue()) || //Value is equal to stylesheet descriptor default (defaultValue != null && this.compareValues( value, defaultValue))) { //Value is equal to DLM stylesheet preferences default //Remove the user's customized value this.removeLayoutAttribute(request, prefScope, nodeId, name); return null; } } return value; } private static final String NO_PERSISTENT_IStylesheetUserPreferences = StylesheetUserPreferencesServiceImpl.class.getName() + ".NO_PERSISTENT_IStylesheetUserPreferences"; private String getCacheKey(StylesheetPreferencesKey stylesheetPreferencesKey) { return NO_PERSISTENT_IStylesheetUserPreferences + "." + stylesheetPreferencesKey.toString(); } private IStylesheetUserPreferences getStylesheetUserPreferences( HttpServletRequest request, StylesheetPreferencesKey stylesheetPreferencesKey) { final String key = getCacheKey(stylesheetPreferencesKey); if (request.getAttribute(key) != null) { return null; } final HttpSession session = request.getSession(); if (session.getAttribute(key) != null) { request.setAttribute(key, Boolean.TRUE); return null; } final IStylesheetUserPreferences stylesheetUserPreferences = this.stylesheetUserPreferencesDao.getStylesheetUserPreferences( stylesheetPreferencesKey.stylesheetDescriptor, stylesheetPreferencesKey.person, stylesheetPreferencesKey.userProfile); if (stylesheetUserPreferences == null) { session.setAttribute(key, Boolean.TRUE); request.setAttribute(key, Boolean.TRUE); } return stylesheetUserPreferences; } private void clearStylesheetUserPreferencesCache( HttpServletRequest request, StylesheetPreferencesKey stylesheetPreferencesKey) { final String key = getCacheKey(stylesheetPreferencesKey); request.removeAttribute(key); final HttpSession session = request.getSession(); session.removeAttribute(key); } /** @return Map<nodeId, Map<name, value>> */ protected ConcurrentMap<String, Map<String, String>> getRequestLayoutAttributes( HttpServletRequest request, StylesheetPreferencesKey stylesheetPreferencesKey) { return PortalWebUtils.getMapRequestAttribute( request, LAYOUT_ATTRIBUTES_KEY + stylesheetPreferencesKey.toString(), false); } /** @return Map<nodeId, Map<name, value>> */ protected ConcurrentMap<String, Map<String, String>> getSessionLayoutAttributes( HttpSession session, StylesheetPreferencesKey stylesheetPreferencesKey) { return PortalWebUtils.getMapSessionAttribute( session, LAYOUT_ATTRIBUTES_KEY + stylesheetPreferencesKey.toString(), false); } @Transactional @Override public String setLayoutAttribute( HttpServletRequest request, PreferencesScope prefScope, String nodeId, String name, String value) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final ILayoutAttributeDescriptor layoutAttributeDescriptor = stylesheetDescriptor.getLayoutAttributeDescriptor(name); if (layoutAttributeDescriptor == null) { logger.warn( "Attempted to set layout attribute {}={} on node with ID=\"{}\" but no such stylesheet parameter is defined in stylesheet descriptor {}. It will be ignored.", new Object[] {name, value, nodeId, stylesheetDescriptor.getName()}); return null; } if (this.compareValues(value, layoutAttributeDescriptor.getDefaultValue())) { //Value matches the default value, remove the attribute return this.removeLayoutAttribute(request, prefScope, nodeId, name); } final IStylesheetUserPreferences distributedStylesheetUserPreferences = this.getDistributedStylesheetUserPreferences(request, prefScope); if (distributedStylesheetUserPreferences != null) { final String defaultValue = distributedStylesheetUserPreferences.getLayoutAttribute(nodeId, name); if (this.compareValues(value, defaultValue)) { //Value matches the DLM preferences value, remove the value return this.removeLayoutAttribute(request, prefScope, nodeId, name); } } final Scope scope = this.getWriteScope( request, prefScope, stylesheetPreferencesKey, layoutAttributeDescriptor); switch (scope) { case PERSISTENT: { IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { stylesheetUserPreferences = this.stylesheetUserPreferencesDao.createStylesheetUserPreferences( stylesheetDescriptor, stylesheetPreferencesKey.person, stylesheetPreferencesKey.userProfile); this.clearStylesheetUserPreferencesCache(request, stylesheetPreferencesKey); } final String oldValue = stylesheetUserPreferences.setLayoutAttribute(nodeId, name, value); this.stylesheetUserPreferencesDao.storeStylesheetUserPreferences( stylesheetUserPreferences); return oldValue; } default: { //Determine the mutex to use for accessing the nodeAttributes map final Object mutex; switch (scope) { case REQUEST: { mutex = PortalWebUtils.getRequestAttributeMutex(request); break; } case SESSION: { final HttpSession session = request.getSession(); mutex = WebUtils.getSessionMutex(session); break; } default: { mutex = new Object(); break; } } //Get/Create the nodeAttributes map Map<String, String> nodeAttributes; synchronized (mutex) { nodeAttributes = this.getDataValue( request, stylesheetPreferencesKey, scope, LAYOUT_ATTRIBUTES_KEY, nodeId); if (nodeAttributes == null) { nodeAttributes = new ConcurrentHashMap<String, String>(); this.putDataValue( request, stylesheetPreferencesKey, scope, LAYOUT_ATTRIBUTES_KEY, nodeId, nodeAttributes); } } return nodeAttributes.put(name, value); } } } @Transactional @Override public String removeLayoutAttribute( HttpServletRequest request, PreferencesScope prefScope, String nodeId, String name) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; final ILayoutAttributeDescriptor layoutAttributeDescriptor = stylesheetDescriptor.getLayoutAttributeDescriptor(name); if (layoutAttributeDescriptor == null) { logger.warn( "Attempted to remove layout attribute {} for ID=\"{}\" but no such stylesheet parameter is defined in stylesheet descriptor {}. It will be ignored.", new Object[] {name, nodeId, stylesheetDescriptor.getName()}); return null; } final Scope scope = this.getWriteScope( request, prefScope, stylesheetPreferencesKey, layoutAttributeDescriptor); switch (scope) { case PERSISTENT: { final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences == null) { break; } final String oldValue = stylesheetUserPreferences.removeLayoutAttribute(nodeId, name); if (oldValue != null) { this.stylesheetUserPreferencesDao.storeStylesheetUserPreferences( stylesheetUserPreferences); return oldValue; } } default: { final Map<String, String> nodeAttributes = this.getDataValue( request, stylesheetPreferencesKey, scope, LAYOUT_ATTRIBUTES_KEY, nodeId); if (nodeAttributes == null) { break; } final String oldValue = nodeAttributes.remove(name); if (oldValue != null) { return oldValue; } } } final IStylesheetUserPreferences distributedStylesheetUserPreferences = this.getDistributedStylesheetUserPreferences(request, prefScope); if (distributedStylesheetUserPreferences != null) { return distributedStylesheetUserPreferences.removeLayoutAttribute(nodeId, name); } return null; } @Override public Iterable<String> getAllLayoutAttributeNodeIds( HttpServletRequest request, PreferencesScope prefScope) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final LinkedHashSet<String> allNodeIds = new LinkedHashSet<String>(); final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences != null) { allNodeIds.addAll(stylesheetUserPreferences.getAllLayoutAttributeNodeIds()); } final HttpSession session = request.getSession(false); if (session != null) { final Map<String, Map<String, String>> sessionLayoutAttributes = getSessionLayoutAttributes(session, stylesheetPreferencesKey); if (sessionLayoutAttributes != null) { allNodeIds.addAll(sessionLayoutAttributes.keySet()); } } final Map<String, Map<String, String>> requestLayoutAttributes = getRequestLayoutAttributes(request, stylesheetPreferencesKey); if (requestLayoutAttributes != null) { allNodeIds.addAll(requestLayoutAttributes.keySet()); } final IStylesheetUserPreferences distributedStylesheetUserPreferences = this.getDistributedStylesheetUserPreferences(request, prefScope); if (distributedStylesheetUserPreferences != null) { allNodeIds.addAll(distributedStylesheetUserPreferences.getAllLayoutAttributeNodeIds()); } return allNodeIds; } @Override public Map<String, String> getAllNodesAndValuesForAttribute( HttpServletRequest request, PreferencesScope prefScope, String name) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final Builder<String, String> result = ImmutableMap.builder(); final boolean isFragmentOwner = this.isFragmentOwnerStylesheetPreferencesKey(stylesheetPreferencesKey); if (!isFragmentOwner) { final IStylesheetUserPreferences distributedStylesheetUserPreferences = this.getDistributedStylesheetUserPreferences(request, prefScope); if (distributedStylesheetUserPreferences != null) { final Map<String, String> allNodesAndValuesForAttribute = distributedStylesheetUserPreferences.getAllNodesAndValuesForAttribute(name); result.putAll(allNodesAndValuesForAttribute); } } final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); if (stylesheetUserPreferences != null) { final Map<String, String> allNodesAndValuesForAttribute = stylesheetUserPreferences.getAllNodesAndValuesForAttribute(name); result.putAll(allNodesAndValuesForAttribute); } final HttpSession session = request.getSession(false); if (session != null) { //nodeId, name, value final Map<String, Map<String, String>> sessionLayoutAttributes = getSessionLayoutAttributes(session, stylesheetPreferencesKey); getAllNodesAndValuesForAttribute(sessionLayoutAttributes, name, result); } final Map<String, Map<String, String>> requestLayoutAttributes = getRequestLayoutAttributes(request, stylesheetPreferencesKey); if (requestLayoutAttributes != null) { getAllNodesAndValuesForAttribute(requestLayoutAttributes, name, result); } return result.build(); } protected void getAllNodesAndValuesForAttribute( Map<String, Map<String, String>> layoutAttributes, String name, Builder<String, String> result) { if (layoutAttributes == null) { return; } for (Map.Entry<String, Map<String, String>> layoutNodeAttributesEntry : layoutAttributes.entrySet()) { //name, value final Map<String, String> layoutNodeAttribute = layoutNodeAttributesEntry.getValue(); final String value = layoutNodeAttribute.get(name); if (value != null) { final String nodeId = layoutNodeAttributesEntry.getKey(); result.put(nodeId, value); } } } @Override public <P extends Populator<String, String>> P populateLayoutAttributes( HttpServletRequest request, PreferencesScope prefScope, String nodeId, P layoutAttributes) { final StylesheetPreferencesKey stylesheetPreferencesKey = this.getStylesheetPreferencesKey(request, prefScope); final IStylesheetDescriptor stylesheetDescriptor = stylesheetPreferencesKey.stylesheetDescriptor; //Get the scoped sources once final IStylesheetUserPreferences stylesheetUserPreferences = this.getStylesheetUserPreferences(request, stylesheetPreferencesKey); final Map<String, Map<String, String>> sessionLayoutAttributes; final HttpSession session = request.getSession(false); if (session == null) { sessionLayoutAttributes = null; } else { sessionLayoutAttributes = getSessionLayoutAttributes(session, stylesheetPreferencesKey); } final Map<String, Map<String, String>> requestLayoutAttributes = getRequestLayoutAttributes(request, stylesheetPreferencesKey); final IStylesheetUserPreferences distributedStylesheetUserPreferences = this.getDistributedStylesheetUserPreferences(request, prefScope); if (distributedStylesheetUserPreferences != null) { distributedStylesheetUserPreferences.populateLayoutAttributes(nodeId, layoutAttributes); } //Try getting each layout attribute to populate the Map for (final ILayoutAttributeDescriptor layoutAttributeDescriptor : stylesheetDescriptor.getLayoutAttributeDescriptors()) { final String name = layoutAttributeDescriptor.getName(); String value; final Scope scope = layoutAttributeDescriptor.getScope(); switch (scope) { case PERSISTENT: { if (stylesheetUserPreferences == null) { value = null; break; } value = stylesheetUserPreferences.getLayoutAttribute(nodeId, name); break; } case SESSION: { if (sessionLayoutAttributes == null) { value = null; break; } final Map<String, String> nodeAttributes = sessionLayoutAttributes.get(nodeId); if (nodeAttributes == null) { value = null; break; } value = nodeAttributes.get(name); break; } case REQUEST: { if (requestLayoutAttributes == null) { value = null; break; } final Map<String, String> nodeAttributes = requestLayoutAttributes.get(nodeId); if (nodeAttributes == null) { value = null; break; } value = nodeAttributes.get(name); break; } default: { value = null; break; } } //Don't add unset properties if (value == null) { continue; } //If the value is equal to the default value remove the property and return null if (this.compareValues(value, layoutAttributeDescriptor.getDefaultValue())) { this.removeLayoutAttribute(request, prefScope, nodeId, name); continue; } layoutAttributes.put(name, value); } return layoutAttributes; } @Override public void setStructureStylesheetOverride(HttpServletRequest request, String override) { request.setAttribute( StylesheetUserPreferencesServiceImpl .STYLESHEET_STRUCTURE_OVERRIDE_REQUEST_ATTRIBUTE, override); } @Override public void setThemeStyleSheetOverride(HttpServletRequest request, String override) { request.setAttribute( StylesheetUserPreferencesServiceImpl .STYLESHEET_THEME_OVERRIDE_REQUEST_ATTRIBUTE_NAME, override); } /** * Returns the stylesheet name if overridden in the request object. * * @param request HttpRequest * @param scope Scope (Structure or Theme) * @return Stylesheet name if set as an override in the request, else null if it was not. */ protected String getStyleSheetName(final HttpServletRequest request, PreferencesScope scope) { final String stylesheetNameFromRequest; if (scope.equals(PreferencesScope.STRUCTURE)) { stylesheetNameFromRequest = (String) request.getAttribute(STYLESHEET_STRUCTURE_OVERRIDE_REQUEST_ATTRIBUTE); } else { stylesheetNameFromRequest = (String) request.getAttribute(STYLESHEET_THEME_OVERRIDE_REQUEST_ATTRIBUTE_NAME); } return stylesheetNameFromRequest; } protected boolean isFragmentOwnerStylesheetPreferencesKey(final StylesheetPreferencesKey key) { return this.isFragmentOwner(key.person); } protected boolean isFragmentOwner(final IPerson person) { return this.fragmentUtils.getFragmentDefinitionByOwner(person) != null; } }