org.opensaml.security.credential.impl.AbstractChainingCredentialResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.opensaml.security.credential.impl.AbstractChainingCredentialResolver.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.security.credential.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

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.logic.Constraint;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;

import org.opensaml.security.credential.Credential;
import org.opensaml.security.credential.CredentialResolver;
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.ImmutableList;

/**
 * An abstract implementation of {@link CredentialResolver} which chains together one or more underlying credential 
 * resolver implementations. Resolved credentials are returned from all underlying resolvers in the chain, 
 * in the order implied by the order of the resolvers in the chain.
 * 
 * @param <ResolverType> the subtype of CredentialResolver to be chained
 */
public abstract class AbstractChainingCredentialResolver<ResolverType extends CredentialResolver>
        extends AbstractCredentialResolver {

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

    /** List of credential resolvers in the chain. */
    @Nonnull
    @NonnullElements
    private List<ResolverType> resolvers;

    /**
     * Constructor.
     * 
     * @param credResolvers the list of chained credential resolvers
     */
    public AbstractChainingCredentialResolver(@Nonnull final List<ResolverType> credResolvers) {
        Constraint.isNotNull(credResolvers, "CredentialResolver list cannot be null");
        resolvers = new ArrayList<>(Collections2.filter(credResolvers, Predicates.notNull()));
    }

    /**
     * Get the unmodifiable list of credential resolvers which comprise the resolver chain.
     * 
     * @return the list of credential resolvers in the chain
     */
    @Nonnull
    @NonnullElements
    @Unmodifiable
    @NotLive
    public List<ResolverType> getResolverChain() {
        return ImmutableList.copyOf(resolvers);
    }

    /** {@inheritDoc} */
    @Nonnull
    public Iterable<Credential> resolve(@Nullable CriteriaSet criteriaSet) throws ResolverException {
        if (resolvers.isEmpty()) {
            log.warn("Chaining credential resolver resolution was attempted with an empty resolver chain");
            throw new IllegalStateException("The resolver chain is empty");
        }
        return new CredentialIterable(this, criteriaSet);
    }

    /**
     * Implementation of {@link Iterable} to be returned by {@link ChainingCredentialResolver}.
     */
    public class CredentialIterable implements Iterable<Credential> {

        /** The chaining credential resolver which owns this instance. */
        private AbstractChainingCredentialResolver<ResolverType> parent;

        /** The criteria set on which to base resolution. */
        private CriteriaSet critSet;

        /**
         * Constructor.
         * 
         * @param resolver the chaining parent of this iterable
         * @param criteriaSet the set of criteria which is input to the underyling resolvers
         */
        public CredentialIterable(@Nonnull final AbstractChainingCredentialResolver<ResolverType> resolver,
                @Nullable final CriteriaSet criteriaSet) {
            parent = resolver;
            critSet = criteriaSet;
        }

        /** {@inheritDoc} */
        @Override
        @Nonnull
        public Iterator<Credential> iterator() {
            return new CredentialIterator(parent, critSet);
        }

    }

    /**
     * Implementation of {@link Iterator} to be returned (indirectly) by {@link ChainingCredentialResolver}.
     */
    public class CredentialIterator implements Iterator<Credential> {

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

        /** The chaining credential resolver which owns this instance. */
        private AbstractChainingCredentialResolver<ResolverType> parent;

        /** The criteria set on which to base resolution. */
        private CriteriaSet critSet;

        /** The iterator over resolvers in the chain. */
        private Iterator<ResolverType> resolverIterator;

        /** The iterator over Credential instances from the current resolver. */
        private Iterator<Credential> credentialIterator;

        /** The current resolver which is returning credentials. */
        private CredentialResolver currentResolver;

        /** The next credential that is safe to return. */
        private Credential nextCredential;

        /**
         * Constructor.
         * 
         * @param resolver the chaining parent of this iterable
         * @param criteriaSet the set of criteria which is input to the underyling resolvers
         */
        public CredentialIterator(@Nonnull final AbstractChainingCredentialResolver<ResolverType> resolver,
                @Nullable final CriteriaSet criteriaSet) {
            Constraint.isNotNull(resolver, "Parent resolver cannot be null");

            parent = resolver;
            critSet = criteriaSet;
            resolverIterator = parent.getResolverChain().iterator();
            credentialIterator = getNextCredentialIterator();
            nextCredential = null;
        }

        /** {@inheritDoc} */
        @Override
        public boolean hasNext() {
            if (nextCredential != null) {
                return true;
            }
            nextCredential = getNextCredential();
            if (nextCredential != null) {
                return true;
            }
            return false;
        }

        /** {@inheritDoc} */
        @Override
        public Credential next() {
            Credential tempCred;
            if (nextCredential != null) {
                tempCred = nextCredential;
                nextCredential = null;
                return tempCred;
            }
            tempCred = getNextCredential();
            if (tempCred != null) {
                return tempCred;
            } else {
                throw new NoSuchElementException("No more Credential elements are available");
            }
        }

        /** {@inheritDoc} */
        @Override
        public void remove() {
            throw new UnsupportedOperationException("Remove operation is not supported by this iterator");
        }

        /**
         * Get the iterator from the next resolver in the chain.
         * 
         * @return an iterator of credentials, or null if none is available
         */
        @Nullable
        private Iterator<Credential> getNextCredentialIterator() {
            while (resolverIterator.hasNext()) {
                currentResolver = resolverIterator.next();
                log.debug("Getting credential iterator from next resolver in chain: {}",
                        currentResolver.getClass().toString());
                try {
                    return currentResolver.resolve(critSet).iterator();
                } catch (ResolverException e) {
                    log.error(String.format("Error resolving credentials from chaining resolver member '%s'",
                            currentResolver.getClass().getName()), e);
                    if (resolverIterator.hasNext()) {
                        log.error("Will attempt to resolve credentials from next member of resolver chain");
                    }
                }
            }

            log.debug("No more credential resolvers available in the resolver chain");
            currentResolver = null;
            return null;
        }

        /**
         * Get the next credential that will be returned by this iterator.
         * 
         * @return the next credential to return, or null if none is available
         */
        @Nullable
        private Credential getNextCredential() {
            if (credentialIterator != null) {
                if (credentialIterator.hasNext()) {
                    return credentialIterator.next();
                }
            }

            credentialIterator = getNextCredentialIterator();
            while (credentialIterator != null) {
                if (credentialIterator.hasNext()) {
                    return credentialIterator.next();
                }
                credentialIterator = getNextCredentialIterator();
            }

            return null;
        }

    }

}