org.opensaml.saml.metadata.resolver.impl.AbstractBatchMetadataResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.opensaml.saml.metadata.resolver.impl.AbstractBatchMetadataResolver.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 org.opensaml.saml.metadata.resolver.impl;

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;

import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.saml.metadata.IterableMetadataSource;
import org.opensaml.saml.metadata.resolver.BatchMetadataResolver;
import org.opensaml.saml.metadata.resolver.filter.FilterException;
import org.opensaml.saml.metadata.resolver.index.MetadataIndex;
import org.opensaml.saml.metadata.resolver.index.impl.MetadataIndexManager;
import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * Abstract subclass for metadata resolvers that process and resolve metadata at a given point 
 * in time from a single metadata source document.
 */
public abstract class AbstractBatchMetadataResolver extends AbstractMetadataResolver
        implements BatchMetadataResolver, IterableMetadataSource {

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

    /** Flag indicating whether to cache the original source metadata document. */
    private boolean cacheSourceMetadata;

    /** The set of indexes configured. */
    private Set<MetadataIndex> indexes;

    /** Constructor. */
    public AbstractBatchMetadataResolver() {
        super();

        indexes = Collections.emptySet();

        setCacheSourceMetadata(true);
    }

    /** {@inheritDoc} */
    @Override
    public Iterator<EntityDescriptor> iterator() {
        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
        return Collections.unmodifiableList(getBackingStore().getOrderedDescriptors()).iterator();
    }

    /**
     * Get whether to cache the original source metadata document.
     * 
     * @return true if source should be cached, false otherwise
     */
    protected boolean isCacheSourceMetadata() {
        return cacheSourceMetadata;
    }

    /**
     * Set whether to cache the original source metadata document.
     * 
     * @param flag true if source should be cached, false otherwise
     */
    protected void setCacheSourceMetadata(boolean flag) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
        cacheSourceMetadata = flag;
    }

    /**
     * Get the configured indexes.
     * 
     * @return the set of configured indexes
     */
    @Nonnull
    @NonnullElements
    @Unmodifiable
    @NotLive
    public Set<MetadataIndex> getIndexes() {
        return ImmutableSet.copyOf(indexes);
    }

    /**
     * Set the configured indexes.
     * 
     * @param newIndexes the new indexes to set
     */
    public void setIndexes(@Nullable final Set<MetadataIndex> newIndexes) {
        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
        if (newIndexes == null) {
            indexes = Collections.emptySet();
        } else {
            indexes = new HashSet<>(Collections2.filter(newIndexes, Predicates.notNull()));
        }
    }

    /** {@inheritDoc} */
    @Override
    @Nonnull
    public Iterable<EntityDescriptor> resolve(CriteriaSet criteria) throws ResolverException {
        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);

        //TODO add filtering for entity role, protocol? maybe
        //TODO add filtering for binding? probably not, belongs better in RoleDescriptorResolver

        EntityIdCriterion entityIdCriterion = criteria.get(EntityIdCriterion.class);
        if (entityIdCriterion != null) {
            return lookupEntityID(entityIdCriterion.getEntityId());
        } else {
            return lookupByIndexes(criteria);
        }

    }

    /**
     * Resolve the set up descriptors based on the indexes currently held.
     * 
     * @param criteria the criteria set to process
     * 
     * @return descriptors resolved via indexes, and based on the input criteria set. May be empty.
     */
    @Nonnull
    @NonnullElements
    protected Set<EntityDescriptor> lookupByIndexes(@Nonnull final CriteriaSet criteria) {
        return getBackingStore().getSecondaryIndexManager().lookupEntityDescriptors(criteria);
    }

    /** {@inheritDoc} */
    @Override
    protected void indexEntityDescriptor(@Nonnull final EntityDescriptor entityDescriptor,
            @Nonnull final EntityBackingStore backingStore) {
        super.indexEntityDescriptor(entityDescriptor, backingStore);

        ((BatchEntityBackingStore) backingStore).getSecondaryIndexManager().indexEntityDescriptor(entityDescriptor);
    }

    /** {@inheritDoc} */
    @Override
    @Nonnull
    protected BatchEntityBackingStore createNewBackingStore() {
        return new BatchEntityBackingStore(getIndexes());
    }

    /** {@inheritDoc} */
    @Override
    @Nonnull
    protected BatchEntityBackingStore getBackingStore() {
        return (BatchEntityBackingStore) super.getBackingStore();
    }

    /** {@inheritDoc} */
    @Override
    protected void initMetadataResolver() throws ComponentInitializationException {
        super.initMetadataResolver();
        // Init this to an empty instance to ensure we always have a non-null instance,
        // even if initialization in the subclass fails for whatever reason.
        // Most subclasses will replace this with a new populated instance.
        setBackingStore(createNewBackingStore());
    }

    /**
     * Convenience method for getting the current effective cached original metadata.
     * 
     * <p>
     * Note: may or may not be the same as that obtained from {@link #getCachedFilteredMetadata()},
     * depending on what metadata filtering produced from the original metadata document.
     * </p>
     * 
     * @return the current effective cached metadata document
     */
    @Nullable
    protected XMLObject getCachedOriginalMetadata() {
        return getBackingStore().getCachedOriginalMetadata();
    }

    /**
     * Convenience method for getting the current effective cached filtered metadata.
     * 
     * <p>
     * Note: may or may not be the same as that obtained from {@link #getCachedOriginalMetadata()},
     * depending on what metadata filtering produced from the original metadata document.
     * </p>
     * 
     * @return the current effective cached metadata document
     */
    @Nullable
    protected XMLObject getCachedFilteredMetadata() {
        return getBackingStore().getCachedFilteredMetadata();
    }

    /**
     * Process the specified new metadata document, including metadata filtering 
     * and return its data in a new entity backing store instance.
     * 
     * @param root the root of the new metadata document being processed
     * 
     * @return the new backing store instance
     * 
     * @throws FilterException if there is a problem filtering the metadata
     */
    @Nonnull
    protected BatchEntityBackingStore preProcessNewMetadata(@Nonnull final XMLObject root) throws FilterException {

        BatchEntityBackingStore newBackingStore = createNewBackingStore();

        XMLObject filteredMetadata = filterMetadata(root);

        if (isCacheSourceMetadata()) {
            newBackingStore.setCachedOriginalMetadata(root);
            newBackingStore.setCachedFilteredMetadata(filteredMetadata);
        }

        if (filteredMetadata == null) {
            log.info("Metadata filtering process produced a null document, resulting in an empty data set");
            return newBackingStore;
        }

        if (filteredMetadata instanceof EntityDescriptor) {
            preProcessEntityDescriptor((EntityDescriptor) filteredMetadata, newBackingStore);
        } else if (filteredMetadata instanceof EntitiesDescriptor) {
            preProcessEntitiesDescriptor((EntitiesDescriptor) filteredMetadata, newBackingStore);
        } else {
            log.warn("Document root was neither an EntityDescriptor nor an EntitiesDescriptor: {}",
                    root.getClass().getName());
        }

        return newBackingStore;
    }

    /**
     * Specialized entity backing store implementation for batch metadata resolvers.
     * 
     * <p>
     * Adds the following to parent impl:
     * <ol>
     * <li>capable of storing the original metadata document on which the backing store is based</li>
     * <li>stores data for any secondary indexes defined</li>
     * </ol>
     * </p>
     */
    protected class BatchEntityBackingStore extends EntityBackingStore {

        /** The cached original source metadata document. */
        private XMLObject cachedOriginalMetadata;

        /** The cached original source metadata document. */
        private XMLObject cachedFilteredMetadata;

        /** Manager for secondary indexes. */
        private MetadataIndexManager secondaryIndexManager;

        /**
         * Constructor.
         *
         * @param initIndexes secondary indexes for which to initialize storage
         */
        protected BatchEntityBackingStore(
                @Nullable @NonnullElements @Unmodifiable @NotLive Set<MetadataIndex> initIndexes) {
            super();
            secondaryIndexManager = new MetadataIndexManager(initIndexes);
        }

        /**
         * Get the cached original source metadata.
         * 
         * @return the cached metadata
         */
        public XMLObject getCachedOriginalMetadata() {
            return cachedOriginalMetadata;
        }

        /**
         * Set the cached original source metadata.
         * 
         * @param metadata The new cached metadata
         */
        public void setCachedOriginalMetadata(XMLObject metadata) {
            cachedOriginalMetadata = metadata;
        }

        /**
         * Get the cached filtered source metadata.
         * 
         * @return the cached metadata
         */
        public XMLObject getCachedFilteredMetadata() {
            return cachedFilteredMetadata;
        }

        /**
         * Set the cached filtered source metadata.
         * 
         * @param metadata The new cached metadata
         */
        public void setCachedFilteredMetadata(XMLObject metadata) {
            cachedFilteredMetadata = metadata;
        }

        /**
         * Get the secondary index manager.
         * 
         * @return the manager for secondary indexes
         */
        public MetadataIndexManager getSecondaryIndexManager() {
            return secondaryIndexManager;
        }

    }

}