net.shibboleth.idp.attribute.resolver.AbstractAttributeDefinition.java Source code

Java tutorial

Introduction

Here is the source code for net.shibboleth.idp.attribute.resolver.AbstractAttributeDefinition.java

Source

/*
 * Licensed to the University Corporation for Advanced Internet Development, 
 * Inc. (UCAID) under one or more contributor license agreements.  See the 
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID 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
 *
 *    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 net.shibboleth.idp.attribute.resolver;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;

import net.shibboleth.idp.attribute.AttributeEncoder;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.annotation.constraint.NullableElements;
import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
import net.shibboleth.utilities.java.support.collection.CollectionSupport;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.primitive.StringSupport;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

/** Base class for attribute definition resolver plugins. */
@ThreadSafe
public abstract class AbstractAttributeDefinition extends AbstractResolverPlugin<IdPAttribute>
        implements AttributeDefinition {

    /** Class logger. */
    @Nonnull
    private final Logger log = LoggerFactory.getLogger(AbstractAttributeDefinition.class);

    /** Whether this attribute definition is only a dependency and thus its values should never be released. */
    private boolean dependencyOnly;

    /** The sourceAttributeID attributeName. */
    @Nullable
    private String sourceAttributeID;

    /** Attribute encoders associated with this definition. */
    @Nonnull
    private Set<AttributeEncoder<?>> encoders = Collections.emptySet();

    /** Localized human intelligible attribute name. */
    @Nonnull
    private Map<Locale, String> displayNames = Collections.emptyMap();

    /** Localized human readable description of attribute. */
    @Nonnull
    private Map<Locale, String> displayDescriptions = Collections.emptyMap();

    /** cache for the log prefix - to save multiple recalculations. */
    @Nullable
    private String logPrefix;

    /**
     * Gets whether this attribute definition is only a dependency and thus its values should never be released outside
     * the resolver.
     * 
     * @return true if this attribute is only used as a dependency, false otherwise
     */
    @Override
    public boolean isDependencyOnly() {
        return dependencyOnly;
    }

    /**
     * Sets whether this attribute definition is only a dependency and thus its values should never be released outside
     * the resolver.
     * 
     * @param isDependencyOnly whether this attribute definition is only a dependency
     */
    public void setDependencyOnly(final boolean isDependencyOnly) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);

        dependencyOnly = isDependencyOnly;
    }

    /**
     * Gets the localized human readable descriptions of attribute.
     * 
     * @return human readable descriptions of attribute
     */
    @Override
    @Nonnull
    @NonnullElements
    @Unmodifiable
    public Map<Locale, String> getDisplayDescriptions() {
        return displayDescriptions;
    }

    /**
     * Sets the localized human readable descriptions of attribute.
     * 
     * @param descriptions localized human readable descriptions of attribute
     */
    public void setDisplayDescriptions(@Nullable @NullableElements final Map<Locale, String> descriptions) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);

        HashMap<Locale, String> checkedDescriptions = new HashMap<>();
        String trimmedDescription;
        for (Entry<Locale, String> entry : descriptions.entrySet()) {
            trimmedDescription = StringSupport.trimOrNull(entry.getValue());
            if (trimmedDescription != null) {
                checkedDescriptions.put(entry.getKey(), trimmedDescription);
            }
        }

        displayDescriptions = ImmutableMap.copyOf(checkedDescriptions);
    }

    /**
     * Gets the localized human readable names of the attribute.
     * 
     * @return human readable names of the attribute
     */
    @Override
    @Nonnull
    @NonnullElements
    @Unmodifiable
    public Map<Locale, String> getDisplayNames() {
        return displayNames;
    }

    /**
     * Sets the localized human readable names of the attribute.
     * 
     * @param names localized human readable names of the attribute
     */
    public void setDisplayNames(@Nullable @NullableElements final Map<Locale, String> names) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);

        HashMap<Locale, String> checkedNames = new HashMap<>();
        String trimmedName;
        for (Entry<Locale, String> entry : names.entrySet()) {
            trimmedName = StringSupport.trimOrNull(entry.getValue());
            if (trimmedName != null) {
                checkedNames.put(entry.getKey(), trimmedName);
            }
        }

        displayNames = ImmutableMap.copyOf(checkedNames);
    }

    /**
     * Gets the unmodifiable encoders used to encode the values of this attribute in to protocol specific formats. The
     * returned collection is never null nor contains any null.
     * 
     * @return encoders used to encode the values of this attribute in to protocol specific formats, never null
     */
    @Override
    @Nonnull
    @NonnullElements
    @Unmodifiable
    public Set<AttributeEncoder<?>> getAttributeEncoders() {
        return encoders;
    }

    /**
     * Sets the encoders used to encode the values of this attribute in to protocol specific formats.
     * 
     * @param attributeEncoders encoders used to encode the values of this attribute in to protocol specific formats
     */
    public void setAttributeEncoders(@Nullable @NullableElements final Set<AttributeEncoder<?>> attributeEncoders) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);

        Set<AttributeEncoder<?>> checkedEncoders = new HashSet<>();
        CollectionSupport.addIf(checkedEncoders, attributeEncoders, Predicates.notNull());
        encoders = ImmutableSet.copyOf(checkedEncoders);
    }

    /**
     * Gets the source attribute id.
     * 
     * @return the source attribute id
     */
    public String getSourceAttributeId() {
        return sourceAttributeID;
    }

    /**
     * Sets the source attribute id.
     * 
     * @param attributeId the source attribute id
     */
    public void setSourceAttributeId(String attributeId) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        sourceAttributeID = StringSupport.trimOrNull(attributeId);
    }

    /** {@inheritDoc} */
    @Override
    protected void doInitialize() throws ComponentInitializationException {

        // Set up the dependencies first. Then the initialize in the parent
        // will correctly rehash the dependencies.
        if (null != getSourceAttributeId()) {
            for (ResolverPluginDependency depends : getDependencies()) {
                depends.setDependencyAttributeId(getSourceAttributeId());
            }
        }
        super.doInitialize();

        // The Id is now definitive. Just in case it was used prior to that, reset the getPrefixCache
        logPrefix = null;
    }

    /**
     * {@inheritDoc}
     * 
     * This method delegates the actual resolution of the attribute's values to the
     * {@link #doAttributeDefinitionResolve(AttributeResolutionContext, AttributeResolverWorkContext)} method.
     * Afterwards, if null was not returned, this method will attach the registered display names, descriptions,
     * and encoders to the resultant attribute.
     */
    @Override
    @Nullable
    protected IdPAttribute doResolve(@Nonnull final AttributeResolutionContext resolutionContext,
            @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException {

        final IdPAttribute resolvedAttribute = doAttributeDefinitionResolve(resolutionContext, workContext);

        if (null == resolvedAttribute) {
            log.debug("{} no attribute was produced during resolution", getLogPrefix());
            return null;
        }

        if (resolvedAttribute.getValues().isEmpty()) {
            log.debug("{} produced an attribute with no values", getLogPrefix());
        } else {
            log.debug("{} produced an attribute with the following values {}", getLogPrefix(),
                    resolvedAttribute.getValues());
        }

        log.trace("{} associating the following display descriptions with the resolved attribute: {}",
                getLogPrefix(), getDisplayDescriptions());
        resolvedAttribute.setDisplayDescriptions(getDisplayDescriptions());

        log.trace("{} associating the following display names with the resolved attribute: {}", getLogPrefix(),
                getDisplayNames());
        resolvedAttribute.setDisplayNames(getDisplayNames());

        log.trace("{} associating the following encoders with the resolved attribute: {}", getLogPrefix(),
                getAttributeEncoders());
        resolvedAttribute.setEncoders(getAttributeEncoders());

        return resolvedAttribute;
    }

    /**
     * Creates and populates the values for the resolved attribute. Implementations should <strong>not</strong> set, or
     * otherwise manage, the resolved attribute's display name, description or encoders. Nor should the resultant
     * attribute be recorded in the given resolution context.
     * 
     * @param resolutionContext current attribute resolution context
     * @param workContext current resolver work context
     * 
     * @return resolved attribute or null if nothing to resolve.
     * @throws ResolutionException thrown if there is a problem resolving and creating the attribute
     */
    @Nullable
    protected abstract IdPAttribute doAttributeDefinitionResolve(
            @Nonnull final AttributeResolutionContext resolutionContext,
            @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException;

    /**
     * return a string which is to be prepended to all log messages.
     * 
     * @return "Attribute Definition '<definitionID>' :"
     */
    @Nonnull
    @NotEmpty
    protected String getLogPrefix() {
        // local cache of cached entry to allow unsynchronised clearing.
        String prefix = logPrefix;
        if (null == prefix) {
            StringBuilder builder = new StringBuilder("Attribute Definition '").append(getId()).append("':");
            prefix = builder.toString();
            if (null == logPrefix) {
                logPrefix = prefix;
            }
        }
        return prefix;
    }

}