All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opensaml.xml.util.ClassIndexedSet Maven / Gradle / Ivy

Go to download

XMLTooling-J is a low-level library that may be used to construct libraries that allow developers to work with XML in a Java beans manner.

There is a newer version: 1.4.2
Show newest version
/*
 * 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.xml.util;

import java.util.AbstractSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * Set implementation which provides indexed access to set members via their class,
 * and which allows only one instance of a given class to be present in the set. Null
 * members are not allowed.
 * 
 * @param  the type of object stored by this class
 */
public class ClassIndexedSet extends AbstractSet implements Set {
    
    /** Storage for set members. */
    private HashSet set;
    
    /** Storage for index of class -> member. */
    private HashMap, T> index;
    
    /**
     * Constructor.
     *
     */
    public ClassIndexedSet() {
        set = new HashSet();
        index = new HashMap, T>();
    }

    /** {@inheritDoc} */
    public boolean add(T o) {
        return add(o, false);
    }

    /**
     * Add member to set, optionally replacing any existing instance of the 
     * same class.
     * 
     * @param o the object to add
     * @param replace flag indicating whether to replace an existing class type
     * @return true if object was added
     * @throws IllegalArgumentException if set already contained an instance of the object's class
     *              and replacement was specified as false
     * @throws NullPointerException if the object to add was null
     */
    @SuppressWarnings("unchecked")
    public boolean add(T o, boolean replace) throws NullPointerException, IllegalArgumentException {
        if (o == null) {
            throw new NullPointerException("Null elements are not allowed");
        }
        boolean replacing = false;
        Class indexClass = getIndexClass(o);
        T existing = get(indexClass);
        if (existing != null) {
            replacing = true;
            if (replace) {
                remove(existing);
            } else {
                throw new IllegalArgumentException("Set already contains a member of index class " 
                        + indexClass.getName());
            }
        }
        index.put(indexClass, o);
        set.add(o);
        return replacing;
    }

    /** {@inheritDoc} */
    public void clear() {
        set.clear();
        index.clear();
    }

    /** {@inheritDoc} */
    @SuppressWarnings("unchecked")
    public boolean remove(Object o) {
        if  (set.contains(o)) {
            removeFromIndex((T) o);
            set.remove(o);
            return true;
        }
        return false;
    }

    /** {@inheritDoc} */
    public Iterator iterator() {
        return new ClassIndexedSetIterator(this, set.iterator()); 
    }

    /** {@inheritDoc} */
    public int size() {
        return set.size();
    }
    
    /**
     * Check whether set contains an instance of the specified class.
     * 
     * @param clazz the class to check
     * @return true if set contains an instance of the specified class, false otherwise
     */
    public boolean contains(Class clazz) {
        return get(clazz)!=null;
    }
    
    /**
     * Get the set element specified by the class parameter.
     * @param  generic parameter which eliminates need for casting by the caller
     * @param clazz the class to whose instance is to be retrieved
     * @return the element whose class is of the type specified, or null
     * 
     */
    @SuppressWarnings("unchecked")
    public  X get(Class clazz) {
        return (X) index.get(clazz);
    }
    
    /**
     * Get the index class of the specified object. Subclasses may override to use
     * a class index other than the main runtime class of the object.
     * 
     * @param o the object whose class index to determine
     * @return the class index value associated with the object instance
     */
    @SuppressWarnings("unchecked")
    protected Class getIndexClass(Object o) {
        return (Class) o.getClass();
    }
    
    /**
     * Remove the specified object from the index.
     * 
     * @param o the object to remove
     */
    private void removeFromIndex(T o) {
       index.remove(getIndexClass(o));
    }
    
    /**
     * Iterator for set implementation {@link ClassIndexedSet}.
     * 
     */
    protected class ClassIndexedSetIterator implements Iterator {
        
        /** The set instance over which this instance is an iterator. */
        private ClassIndexedSet set;
        
        /** The iterator for the owner's underlying storage. */
        private Iterator iterator;
        
        /** Flag which tracks whether next() has been called at least once. */
        private boolean nextCalled;
        
        /** Flag which tracks whether remove can currently be called. */
        private boolean removeStateValid;;
        
        /** The element most recently returned by next(), and the target for any subsequent
         * remove() operation. */
        private T current;
        
        /**
         * Constructor.
         *
         * @param parentSet the {@link ClassIndexedSet} over which this instance is an iterator
         * @param parentIterator the iterator for the parent's underlying storage
         */
        protected ClassIndexedSetIterator(ClassIndexedSet parentSet, Iterator parentIterator) {
            set = parentSet;
            iterator = parentIterator;
            current = null;
            nextCalled = false;
            removeStateValid = false;
        }

        /** {@inheritDoc} */
        public boolean hasNext() {
            return iterator.hasNext();
        }

        /** {@inheritDoc} */
        public T next() {
            current = iterator.next();
            nextCalled = true;
            removeStateValid = true;
            return current;
        }

        /** {@inheritDoc} */
        public void remove() {
            if (! nextCalled) {
                throw new IllegalStateException("remove() was called before calling next()");
            }
            if (! removeStateValid) {
                throw new IllegalStateException("remove() has already been called since the last call to next()");
            }
            iterator.remove();
            set.removeFromIndex(current);
            removeStateValid = false;
        }
        
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy