Java tutorial
/** * 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: * * http://www.apache.org/licenses/LICENSE-2.0 * * 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.persondir; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.jasig.services.persondir.IPersonAttributes; import org.jasig.services.persondir.support.AbstractDefaultAttributePersonAttributeDao; import org.jasig.services.persondir.support.AttributeNamedPersonImpl; import org.jasig.services.persondir.support.IUsernameAttributeProvider; import org.jasig.services.persondir.support.MultivaluedPersonAttributeUtils; import org.jasig.services.persondir.support.NamedPersonImpl; /** * LocalAccountPersonAttributeDao provides a person directory implementation * that uses uPortal's internal account store. This implementation overrides * several methods of AbstractQueryPersonAttributeDao to allow for the use of * arbitrary user attributes without requiring an administrator to add new * entries to the result or query attribute mappings. * * @author Jen Bourey, jbourey@unicon.net * @version $Revision$ */ public class LocalAccountPersonAttributeDao extends AbstractDefaultAttributePersonAttributeDao { private ILocalAccountDao localAccountDao; private Map<String, Set<String>> resultAttributeMapping; private Set<String> possibleUserAttributes; private String unmappedUsernameAttribute = null; private String displayNameAttribute = "displayName"; private Map<String, Set<String>> queryAttributeMapping; /** * Set the local portal account DAO. * * @param localAccountDao */ public void setLocalAccountDao(ILocalAccountDao localAccountDao) { this.localAccountDao = localAccountDao; } public void setQueryAttributeMapping(final Map<String, ?> queryAttributeMapping) { final Map<String, Set<String>> parsedQueryAttributeMapping = MultivaluedPersonAttributeUtils .parseAttributeToAttributeMapping(queryAttributeMapping); if (parsedQueryAttributeMapping.containsKey("")) { throw new IllegalArgumentException( "The map from attribute names to attributes must not have any empty keys."); } this.queryAttributeMapping = parsedQueryAttributeMapping; } /** * @return the resultAttributeMapping */ public Map<String, Set<String>> getResultAttributeMapping() { return resultAttributeMapping; } /** * Set the {@link Map} to use for mapping from a data layer name to an attribute name or {@link Set} of attribute * names. Data layer names that are specified but have null mappings will use the column name for the attribute * name. Data layer names that are not specified as keys in this {@link Map} will be ignored. * <br> * The passed {@link Map} must have keys of type {@link String} and values of type {@link String} or a {@link Set} * of {@link String}. * * @param resultAttributeMapping {@link Map} from column names to attribute names, may not be null. * @throws IllegalArgumentException If the {@link Map} doesn't follow the rules stated above. * @see MultivaluedPersonAttributeUtils#parseAttributeToAttributeMapping(Map) */ public void setResultAttributeMapping(Map<String, ?> resultAttributeMapping) { final Map<String, Set<String>> parsedResultAttributeMapping = MultivaluedPersonAttributeUtils .parseAttributeToAttributeMapping(resultAttributeMapping); if (parsedResultAttributeMapping.containsKey("")) { throw new IllegalArgumentException( "The map from attribute names to attributes must not have any empty keys."); } final Collection<String> userAttributes = MultivaluedPersonAttributeUtils .flattenCollection(parsedResultAttributeMapping.values()); this.resultAttributeMapping = parsedResultAttributeMapping; this.possibleUserAttributes = Collections.unmodifiableSet(new LinkedHashSet<String>(userAttributes)); } /** * @return the userNameAttribute */ public String getUnmappedUsernameAttribute() { return unmappedUsernameAttribute; } /** * The returned attribute to use as the userName for the mapped IPersons. If null the {@link #setDefaultAttributeName(String)} * value will be used and if that is null the {@link AttributeNamedPersonImpl#DEFAULT_USER_NAME_ATTRIBUTE} value is * used. * * @param userNameAttribute the userNameAttribute to set */ public void setUnmappedUsernameAttribute(String userNameAttribute) { this.unmappedUsernameAttribute = userNameAttribute; } /** * Return the list of all possible attribute names. This implementation * queries the database to provide a list of all mapped attribute names, * plus all attribute keys currently in-use in the database. * * @return Set */ public Set<String> getPossibleUserAttributeNames() { final Set<String> names = new HashSet<String>(); names.addAll(this.possibleUserAttributes); names.addAll(localAccountDao.getCurrentAttributeNames()); names.add(displayNameAttribute); return names; } /** * Return the list of all possible query attributes. This implementation * queries the database to provide a list of all mapped query attribute names, * plus all attribute keys currently in-use in the database. * * @return Set */ public Set<String> getAvailableQueryAttributes() { if (this.queryAttributeMapping == null) { return Collections.emptySet(); } return Collections.unmodifiableSet(this.queryAttributeMapping.keySet()); } /* (non-Javadoc) * @see org.jasig.services.persondir.IPersonAttributeDao#getPeopleWithMultivaluedAttributes(java.util.Map) */ public final Set<IPersonAttributes> getPeopleWithMultivaluedAttributes(Map<String, List<Object>> query) { Validate.notNull(query, "query may not be null."); //Generate the query to pass to the subclass final LocalAccountQuery queryBuilder = this.generateQuery(query); if (queryBuilder == null) { this.logger.debug("No queryBuilder was generated for query " + query + ", null will be returned"); return null; } //Get the username from the query, if specified final IUsernameAttributeProvider usernameAttributeProvider = this.getUsernameAttributeProvider(); //Execute the query in the subclass final List<ILocalAccountPerson> unmappedPeople = localAccountDao.getPeople(queryBuilder); if (unmappedPeople == null) { return null; } //Map the attributes of the found people according to resultAttributeMapping if it is set final Set<IPersonAttributes> mappedPeople = new LinkedHashSet<IPersonAttributes>(); for (final ILocalAccountPerson unmappedPerson : unmappedPeople) { final IPersonAttributes mappedPerson = this.mapPersonAttributes(unmappedPerson); mappedPeople.add(mappedPerson); } return Collections.unmodifiableSet(mappedPeople); } protected LocalAccountQuery generateQuery(Map<String, List<Object>> query) { LocalAccountQuery queryBuilder = new LocalAccountQuery(); String userNameAttribute = this.getConfiguredUserNameAttribute(); for (final Map.Entry<String, List<Object>> queryEntry : query.entrySet()) { String attrName = queryEntry.getKey(); if (userNameAttribute.equals(attrName)) { String value = queryEntry.getValue().get(0).toString(); queryBuilder.setUserName(value); } else { List<String> values = new ArrayList<String>(); for (Object o : queryEntry.getValue()) { values.add(o.toString()); } queryBuilder.setAttribute(attrName, values); } } if (this.logger.isDebugEnabled()) { this.logger.debug("Generated query builder '" + queryBuilder + "' from query Map " + query + "."); } return queryBuilder; } /** * This implementation uses the result attribute mapping to supplement, rather * than replace, the attributes returned from the database. */ protected IPersonAttributes mapPersonAttributes(final ILocalAccountPerson person) { final Map<String, List<Object>> mappedAttributes = new LinkedHashMap<String, List<Object>>(); mappedAttributes.putAll(person.getAttributes()); // map the user's username to the portal's username attribute in the // attribute map mappedAttributes.put(this.getUsernameAttributeProvider().getUsernameAttribute(), Collections.<Object>singletonList(person.getName())); // if the user does not have a display name attribute set, attempt // to build one from the first and last name attributes if (!mappedAttributes.containsKey(displayNameAttribute) || mappedAttributes.get(displayNameAttribute).size() == 0 || StringUtils.isBlank((String) mappedAttributes.get(displayNameAttribute).get(0))) { final List<Object> firstNames = mappedAttributes.get("givenName"); final List<Object> lastNames = mappedAttributes.get("sn"); final StringBuilder displayName = new StringBuilder(); if (firstNames != null && firstNames.size() > 0) { displayName.append(firstNames.get(0)).append(" "); } if (lastNames != null && lastNames.size() > 0) { displayName.append(lastNames.get(0)); } mappedAttributes.put(displayNameAttribute, Collections.<Object>singletonList(displayName.toString())); } for (final Map.Entry<String, Set<String>> resultAttrEntry : this.getResultAttributeMapping().entrySet()) { final String dataKey = resultAttrEntry.getKey(); //Only map found data attributes if (mappedAttributes.containsKey(dataKey)) { Set<String> resultKeys = resultAttrEntry.getValue(); //If dataKey has no mapped resultKeys just use the dataKey if (resultKeys == null) { resultKeys = Collections.singleton(dataKey); } //Add the value to the mapped attributes for each mapped key final List<Object> value = mappedAttributes.get(dataKey); for (final String resultKey : resultKeys) { if (resultKey == null) { //TODO is this possible? if (!mappedAttributes.containsKey(dataKey)) { mappedAttributes.put(dataKey, value); } } else if (!mappedAttributes.containsKey(resultKey)) { mappedAttributes.put(resultKey, value); } } } } final IPersonAttributes newPerson; final String name = person.getName(); if (name != null) { newPerson = new NamedPersonImpl(name, mappedAttributes); } else { final String userNameAttribute = this.getConfiguredUserNameAttribute(); newPerson = new AttributeNamedPersonImpl(userNameAttribute, mappedAttributes); } return newPerson; } /** * @return The appropriate attribute to user for the user name. Since {@link #getDefaultAttributeName()} should * never return null this method should never return null either. */ protected String getConfiguredUserNameAttribute() { //If configured explicitly use it if (this.unmappedUsernameAttribute != null) { return this.unmappedUsernameAttribute; } final IUsernameAttributeProvider usernameAttributeProvider = this.getUsernameAttributeProvider(); return usernameAttributeProvider.getUsernameAttribute(); } }