eu.eidas.auth.commons.PersonalAttributeList.java Source code

Java tutorial

Introduction

Here is the source code for eu.eidas.auth.commons.PersonalAttributeList.java

Source

/*
 * This work is Open Source and licensed by the European Commission under the
 * conditions of the European Public License v1.1
 *
 * (http://www.osor.eu/eupl/european-union-public-licence-eupl-v.1.1);
 *
 * any use of this file implies acceptance of the conditions of this license.
 * 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 eu.eidas.auth.commons;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

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

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import org.apache.commons.lang.StringUtils;

import eu.eidas.auth.commons.attribute.AttributeDefinition;
import eu.eidas.auth.commons.attribute.AttributeRegistry;
import eu.eidas.auth.commons.attribute.AttributeValue;
import eu.eidas.auth.commons.attribute.AttributeValueMarshaller;
import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException;
import eu.eidas.auth.commons.attribute.ImmutableAttributeMap;
import eu.eidas.auth.commons.attribute.PersonType;

/**
 * This class is a bean used to store the information relative to the PersonalAttributeList.
 *
 * @see PersonalAttribute
 * @deprecated use {@link eu.eidas.auth.commons.attribute.ImmutableAttributeMap} instead.
 */
@NotThreadSafe
@Deprecated
public final class PersonalAttributeList implements IPersonalAttributeList {

    /**
     * A {@link java.util.Map} key.
     */
    private abstract static class AbstractKey {

        @Nonnull
        private final String key;

        AbstractKey(@Nonnull String key) {
            this.key = key;
        }

        @Nonnull
        final String getKey() {
            return key;
        }

        @Override
        public final boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || !(o instanceof AbstractKey)) {
                return false;
            }

            AbstractKey other = (AbstractKey) o;

            return key.equals(other.key);

        }

        @Override
        public final int hashCode() {
            return key.hashCode();
        }
    }

    /**
     * A {@link java.util.Map} key which preserves the order of insertion.
     */
    private static final class CustomKey extends AbstractKey implements Comparable<CustomKey> {

        private final long index;

        CustomKey(long index, @Nonnull String key) {
            super(key);
            this.index = index;
        }

        long getIndex() {
            return index;
        }

        @Override
        public int compareTo(@Nonnull CustomKey o) {
            return Long.compare(index, o.index);
        }
    }

    /**
     * A {@link java.util.Map} key used only for Map retrieval operations such as {@link java.util.Map#get(Object)}.
     */
    private static final class RetrievalKey extends AbstractKey {

        RetrievalKey(@Nonnull String key) {
            super(key);
        }
    }

    /**
     * Unfortunately {@link java.util.concurrent.ConcurrentLinkedQueue} does not provide a {@link
     * Collection#equals(Object)} method.
     *
     * @param <E> the type of the items
     */
    private static final class ConcurrentLinkedQueue<E> extends java.util.concurrent.ConcurrentLinkedQueue<E> {

        @Override
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            }
            if (!(o instanceof ConcurrentLinkedQueue)) {
                return false;
            }

            Iterator<E> e1 = ConcurrentLinkedQueue.this.iterator();
            Iterator<?> e2 = ((ConcurrentLinkedQueue<?>) o).iterator();
            while (e1.hasNext() && e2.hasNext()) {
                E o1 = e1.next();
                Object o2 = e2.next();
                if (!(o1 == null ? o2 == null : o1.equals(o2))) {
                    return false;
                }
            }
            return !(e1.hasNext() || e2.hasNext());
        }

        @Override
        public int hashCode() {
            return super.hashCode();
        }
    }

    /**
     * Static factory method to copy a {@link PersonalAttributeList}.
     * <p/>
     * This method is more robust and flexible than implementing {@link #clone()}.
     *
     * @param copy the instance to copy
     * @return a copy of the given argument
     */
    @Nonnull
    public static PersonalAttributeList copyOf(@Nonnull IPersonalAttributeList copy) {
        PersonalAttributeList list = new PersonalAttributeList();
        for (final PersonalAttribute personalAttribute : copy) {
            list.add(personalAttribute);
        }
        return list;
    }

    /**
     * Static factory method to copy an {@link eu.eidas.auth.commons.attribute.ImmutableAttributeMap} as a {@link
     * PersonalAttributeList}.
     * <p/>
     *
     * @param copy the instance to copy
     * @return a copy of the given argument
     */
    @Nonnull
    public static PersonalAttributeList copyOf(@Nonnull ImmutableAttributeMap copy) {
        PersonalAttributeList list = new PersonalAttributeList();
        if (null != copy) {
            for (final Map.Entry<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> entry : copy
                    .getAttributeMap().entrySet()) {
                AttributeDefinition<?> attributeDefinition = entry.getKey();
                ImmutableSet<? extends AttributeValue<?>> values = entry.getValue();
                PersonalAttribute personalAttribute = new PersonalAttribute(
                        attributeDefinition.getNameUri().toASCIIString(), attributeDefinition.getFriendlyName());
                personalAttribute
                        .setEidasLegalPersonAttr(PersonType.LEGAL_PERSON == attributeDefinition.getPersonType());
                personalAttribute.setEidasNaturalPersonAttr(
                        PersonType.NATURAL_PERSON == attributeDefinition.getPersonType());
                personalAttribute.setIsRequired(attributeDefinition.isRequired());
                ImmutableList.Builder<String> builder = ImmutableList.builder();
                // do not marshal, we need raw values to be displayed
                /*AttributeValueMarshaller<?> attributeValueMarshaller =
                    attributeDefinition.getAttributeValueMarshaller();*/
                for (final AttributeValue value : values) {
                    //try {
                    //builder.add(attributeValueMarshaller.marshal(value));
                    builder.add(value.getValue().toString());
                    /*} catch (AttributeValueMarshallingException e) {
                    throw new IllegalStateException(e);
                    }*/
                }
                personalAttribute.setValue(builder.build());
                list.add(personalAttribute);
            }
        }
        return list;
    }

    /**
     * Static factory method to convert a {@link PersonalAttributeList} into an {@link
     * eu.eidas.auth.commons.attribute.ImmutableAttributeMap}.
     * <p/>
     *
     * @param copy the instance to copy
     * @return a copy of the given argument
     */
    @Nonnull
    public static ImmutableAttributeMap copyOf(@Nonnull IPersonalAttributeList copy,
            @Nonnull AttributeRegistry... attributeRegistries) {
        ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder();
        for (final PersonalAttribute personalAttribute : copy) {
            AttributeDefinition<?> attributeDefinition = getByName(personalAttribute.getName(),
                    attributeRegistries);
            if (!personalAttribute.isEmptyValue()) {
                List<String> personalAttributeValue = personalAttribute.getValue();
                ImmutableSet<AttributeValue<?>> attributeValues = toAttributeValues(attributeDefinition,
                        personalAttributeValue);
                builder.put((AttributeDefinition) attributeDefinition, (ImmutableSet) attributeValues);
            } else if (!personalAttribute.isEmptyComplexValue()) {
                builder.put(attributeDefinition, personalAttribute.getComplexValue().toString());
            } else if (personalAttribute.isEmpty()) {
                builder.put(attributeDefinition);
            }

        }
        return builder.build();
    }

    public static ImmutableSet<AttributeValue<?>> toAttributeValues(AttributeDefinition<?> attributeDefinition,
            List<String> personalAttributeValues) {
        AttributeValueMarshaller<?> attributeValueMarshaller = attributeDefinition.getAttributeValueMarshaller();
        ImmutableSet.Builder<AttributeValue<?>> setBuilder = ImmutableSet.builder();
        for (final String value : personalAttributeValues) {
            try {
                setBuilder.add(attributeValueMarshaller.unmarshal(value, false));
            } catch (AttributeValueMarshallingException e) {
                throw new IllegalStateException(e);
            }
        }
        return setBuilder.build();
    }

    private static AttributeDefinition getByName(String name, @Nonnull AttributeRegistry... attributeRegistries) {
        for (AttributeRegistry attributeRegistry : attributeRegistries) {
            AttributeDefinition attributeDefinition = attributeRegistry.getByName(name);
            if (null != attributeDefinition) {
                return attributeDefinition;
            }
        }
        return null;
    }

    /**
     * Static factory method to convert a {@link PersonalAttributeList} into an {@link
     * eu.eidas.auth.commons.attribute.ImmutableAttributeMap}. Only retains/copies the attributes where an
     * attributeDefinition is found in the attributeRegistry
     * <p/>
     *
     * @param copy the instance to copy
     * @param attributeRegistries the attribute registry where the attributes from copy are searched for
     * @return a copy of the given argument
     */
    @Nonnull
    public static ImmutableAttributeMap retainAttrsExistingInRegistry(@Nonnull IPersonalAttributeList copy,
            @Nonnull AttributeRegistry... attributeRegistries) {
        ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder();
        for (final PersonalAttribute personalAttribute : copy) {
            AttributeDefinition<?> attributeDefinition = getByName(personalAttribute.getName(),
                    attributeRegistries);
            if (null != attributeDefinition) {
                if (!personalAttribute.isEmptyValue()) {
                    List<String> personalAttributeValue = personalAttribute.getValue();
                    ImmutableSet<AttributeValue<?>> attributeValues = toAttributeValues(attributeDefinition,
                            personalAttributeValue);
                    builder.put((AttributeDefinition) attributeDefinition, (ImmutableSet) attributeValues);
                } else if (!personalAttribute.isEmptyComplexValue()) {
                    builder.put(attributeDefinition, personalAttribute.getComplexValue().toString());
                } else if (personalAttribute.isEmpty()) {
                    builder.put(attributeDefinition);
                }
            }
        }
        return builder.build();
    }

    @Nullable
    public static PersonalAttributeList fromString(@Nullable String personalAttributeListString) {
        if (null == personalAttributeListString) {
            return null;
        }
        return PersonalAttributeString.fromStringList(personalAttributeListString);
    }

    @Nullable
    public static String toString(@Nullable PersonalAttributeList personalAttributeList) {
        if (null == personalAttributeList) {
            return null;
        }
        return PersonalAttributeString.toStringList(personalAttributeList);
    }

    private final AtomicLong sequence = new AtomicLong(Long.MIN_VALUE);

    /**
     * Do not inherit from CHM but compose it.
     */
    private final ConcurrentMap<CustomKey, ConcurrentLinkedQueue<PersonalAttribute>> map;

    private NavigableMap<CustomKey, ConcurrentLinkedQueue<PersonalAttribute>> asNavigableMap() {
        return new TreeMap<CustomKey, ConcurrentLinkedQueue<PersonalAttribute>>(map);
    }

    private PersonalAttributeList(@Nonnull ConcurrentMap<CustomKey, ConcurrentLinkedQueue<PersonalAttribute>> map) {
        this.map = map;
    }

    /**
     * Default constructor.
     */
    public PersonalAttributeList() {
        this(new ConcurrentHashMap<CustomKey, ConcurrentLinkedQueue<PersonalAttribute>>());
    }

    /**
     * Constructor with initial capacity for the PersonalAttributeList size.
     *
     * @param capacity The initial capacity for the PersonalAttributeList.
     */
    public PersonalAttributeList(int capacity) {
        this(new ConcurrentHashMap<CustomKey, ConcurrentLinkedQueue<PersonalAttribute>>(capacity));
    }

    /**
     * {@inheritDoc}
     */
    @Nonnull
    @Override
    public Iterator<PersonalAttribute> iterator() {
        final Iterator<ConcurrentLinkedQueue<PersonalAttribute>> outerIterator = map.values().iterator();
        Iterator<PersonalAttribute> personalAttributeIterator = new Iterator<PersonalAttribute>() {

            Iterator<PersonalAttribute> currentInnerIterator;

            @Override
            public boolean hasNext() {
                return (currentInnerIterator != null && currentInnerIterator.hasNext()) || outerIterator.hasNext();
            }

            @Override
            public PersonalAttribute next() {
                if (null == currentInnerIterator || !currentInnerIterator.hasNext()) {
                    currentInnerIterator = outerIterator.next().iterator();

                }
                return currentInnerIterator.next();
            }

            @Override
            public void remove() {
                if (null != currentInnerIterator) {
                    currentInnerIterator.remove();
                }
                if (null != currentInnerIterator && !currentInnerIterator.hasNext() && null != outerIterator) {
                    outerIterator.remove();
                }
            }
        };
        return personalAttributeIterator;
    }

    /**
     * {@inheritDoc}
     */
    @Nullable
    @Override
    public PersonalAttribute getByFriendlyName(@Nonnull String friendlyName) {
        Collection<PersonalAttribute> values = values();
        if (null == values) {
            return null;
        }
        for (final PersonalAttribute value : values) {
            if (value.getFriendlyName().equals(friendlyName)) {
                return value;
            }
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Nullable
    @Override
    public Collection<PersonalAttribute> values(@Nullable String key) {
        if (null == key) {
            return null;
        }
        ConcurrentLinkedQueue<PersonalAttribute> personalAttributes = map.get(asRetrievalKey(key));
        if (null == personalAttributes || personalAttributes.isEmpty()) {
            return null;
        }
        return personalAttributes;
    }

    private AbstractKey asRetrievalKey(String attrName) {
        return new RetrievalKey(attrName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean add(@Nullable PersonalAttribute value) {
        if (null == value) {
            return false;
        }
        String key = value.getName();
        if (StringUtils.isEmpty(key)) {
            return false;
        }
        ConcurrentLinkedQueue<PersonalAttribute> existingList = map.get(asRetrievalKey(key));
        if (null == existingList) {
            ConcurrentLinkedQueue<PersonalAttribute> newList = new ConcurrentLinkedQueue<PersonalAttribute>();
            newList.offer(value);
            existingList = map.putIfAbsent(new CustomKey(sequence.getAndIncrement(), key), newList);
            if (null == existingList) {
                return true;
                //            } else {
                //                // already inserted in another thread
                //                sequence.decrementAndGet();
            }
        }
        return existingList.offer(value);
    }

    @Override
    public int size() {
        int size = 0;
        for (final ConcurrentLinkedQueue<PersonalAttribute> personalAttributes : map.values()) {
            size += personalAttributes.size();
        }
        return size;
    }

    @Override
    public boolean containsFriendlyName(String friendlyName) {
        return null != getByFriendlyName(friendlyName);
    }

    @Override
    public PersonalAttribute getFirst(PersonalAttribute personalAttribute) {
        if (null == personalAttribute) {
            return null;
        }
        String key = personalAttribute.getName();
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        ConcurrentLinkedQueue<PersonalAttribute> personalAttributes = map.get(asRetrievalKey(key));
        if (null == personalAttributes) {
            return null;
        }
        return personalAttributes.peek();
    }

    @Override
    public boolean contains(PersonalAttribute personalAttribute) {
        if (null == personalAttribute) {
            return false;
        }
        String key = personalAttribute.getName();
        if (StringUtils.isEmpty(key)) {
            return false;
        }
        return map.containsKey(asRetrievalKey(key));
    }

    @Nullable
    @Override
    public PersonalAttribute removeByFriendlyName(@Nonnull String friendlyName) {
        for (Iterator<ConcurrentLinkedQueue<PersonalAttribute>> i = map.values().iterator(); i.hasNext();) {
            ConcurrentLinkedQueue<PersonalAttribute> queue = i.next();
            PersonalAttribute personalAttribute = queue.peek();
            if (null != personalAttribute && personalAttribute.getFriendlyName().equals(friendlyName)) {
                i.remove();
                return personalAttribute;
            }
        }
        return null;
    }

    @Override
    public Collection<PersonalAttribute> values() {
        Collection<ConcurrentLinkedQueue<PersonalAttribute>> values = asNavigableMap().values();
        ImmutableList.Builder<PersonalAttribute> builder = new ImmutableList.Builder<PersonalAttribute>();
        for (final ConcurrentLinkedQueue<PersonalAttribute> value : values) {
            builder.addAll(value);
        }
        return builder.build();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        PersonalAttributeList that = (PersonalAttributeList) o;

        return map != null ? map.equals(that.map) : that.map == null;

    }

    @Override
    public int hashCode() {
        return map != null ? map.hashCode() : 0;
    }

    /**
     * Use {@link #toString(PersonalAttributeList)} instead.
     */
    @Nonnull
    @Override
    public String toString() {
        return PersonalAttributeString.toStringList(this);
    }
}