/** * 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.rendering.xslt; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import org.apereo.portal.EntityIdentifier; import org.apereo.portal.groups.IGroupMember; import org.apereo.portal.security.IPerson; import org.apereo.portal.services.GroupService; import org.apereo.portal.user.IUserInstance; import org.apereo.portal.user.IUserInstanceManager; import org.apereo.portal.utils.threading.SingletonDoubleCheckedCreator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; /** * Maps a user attribute to a skin. The user's attribute named by {@link * #setSkinAttributeName(String)} is used to look up a skin name via the {@link * #setAttributeToSkinMap(Map)} map and the skin name is set to in the transformer using the {@link * #setSkinParameterName(String)} parameter. * */ public class UserGroupSkinMappingTransformerConfigurationSource extends SkinMappingTransformerConfigurationSource { private final SingletonDoubleCheckedCreator<Map<IGroupMember, String>> groupMemberToSkinMappingCreator = new GroupMemberMappingCreator(); private IUserInstanceManager userInstanceManager; private Map<String, String> groupToSkinMap = Collections.emptyMap(); private static final String LOGGER_NAME = UserGroupSkinMappingTransformerConfigurationSource.class.getName(); private Logger logger; /** * Inits and/or returns already initialized logger. <br> * You have to use this method in order to use the logger,<br> * you should not call the private variable directly.<br> * This was done because Tomcat may instantiate all listeners before calling contextInitialized * on any listener.<br> * Note that there is no synchronization here on purpose. The object returned by getLog for a * logger name is<br> * idempotent and getLog itself is thread safe. Eventually all <br> * threads will see an instance level logger variable and calls to getLog will stop. * * @return the log for this class */ protected Logger getLogger() { Logger l = this.logger; if (l == null) { l = LoggerFactory.getLogger(LOGGER_NAME); this.logger = l; } return l; } @Autowired public void setUserInstanceManager(IUserInstanceManager userInstanceManager) { this.userInstanceManager = userInstanceManager; } /** Map of group keys to skin names. Defaults to an empty map. */ public void setGroupToSkinMap(Map<String, String> groupToSkinMap) { this.groupToSkinMap = groupToSkinMap; } protected String getSkinName(HttpServletRequest request) { final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request); final IPerson person = userInstance.getPerson(); final EntityIdentifier personIdentifier = person.getEntityIdentifier(); final IGroupMember groupMember = GroupService.getGroupMember(personIdentifier); final Map<IGroupMember, String> groupMemberToSkinMapping = groupMemberToSkinMappingCreator.get(); for (final Entry<IGroupMember, String> groupToSkinEntry : groupMemberToSkinMapping.entrySet()) { final IGroupMember group = groupToSkinEntry.getKey(); if (group.isGroup() && groupMember.isDeepMemberOf(group.asGroup())) { final String skin = groupToSkinEntry.getValue(); getLogger() .debug( "Setting skin override {} for {} because they are a member of {}", new Object[] {skin, person.getUserName(), group}); //Cache the resolution return skin; } } getLogger() .debug( "No user {} is not a member of any configured groups, no skin override will be done", person.getUserName()); return null; } private final class GroupMemberMappingCreator extends SingletonDoubleCheckedCreator<Map<IGroupMember, String>> { @Override protected Map<IGroupMember, String> createSingleton(Object... args) { final Map<IGroupMember, String> groupMemberToSkinMapping = new LinkedHashMap<IGroupMember, String>(groupToSkinMap.size()); for (final Entry<String, String> groupToSkinEntry : groupToSkinMap.entrySet()) { final String group = groupToSkinEntry.getKey(); final IGroupMember groupMember = this.findGroup(group); if (groupMember != null) { final String skin = groupToSkinEntry.getValue(); groupMemberToSkinMapping.put(groupMember, skin); } } return groupMemberToSkinMapping; } protected IGroupMember findGroup(String group) { //Find group by ID final IGroupMember groupMember = GroupService.findGroup(group); if (groupMember != null) { return groupMember; } //No matching ID, search by name final EntityIdentifier[] results = GroupService.searchForGroups(group, GroupService.IS, IPerson.class); if (results == null || results.length == 0) { getLogger() .warn( "Configured group '" + group + "' cannot be found for skin mapping. This mapping will be ignored"); return null; } //Warn if multiple results are found if (results.length > 1) { getLogger() .warn( results.length + " groups were found for skin mapping group '" + group + "'. The first result will be used. " + Arrays.toString(results)); } return GroupService.getGroupMember(results[0]); } } }