sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1397069 - in /sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection: CheckedArrayList.java CheckedHashMap.java CheckedHashSet.java SynchronizedIterator.java
Date Thu, 11 Oct 2012 14:21:02 GMT
Author: desruisseaux
Date: Thu Oct 11 14:21:01 2012
New Revision: 1397069

URL: http://svn.apache.org/viewvc?rev=1397069&view=rev
Log:
Ported the checked collection classes, which are going to be needed by the metadata module.
Those classes provide hooks for controlling write access and synchronization lock, which are
too functionalities needed by sis-metadata.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java
  (with props)

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java?rev=1397069&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java
Thu Oct 11 14:21:01 2012
@@ -0,0 +1,497 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.sis.util.collection;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import net.jcip.annotations.ThreadSafe;
+import org.apache.sis.util.resources.Errors;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+
+
+/**
+ * A {@linkplain Collections#checkedList(List) checked} and
+ * {@linkplain Collections#synchronizedList(List) synchronized} {@link ArrayList}.
+ * The type checks are performed at run-time in addition to the compile-time checks.
+ *
+ * <p>Using this class is similar to wrapping an {@link ArrayList} using the methods
provided
+ * in the standard {@link Collections} class, except for the following advantages:</p>
+ *
+ * <ul>
+ *   <li>Avoid the two levels of indirection (for type check and synchronization).</li>
+ *   <li>Checks for write permission.</li>
+ *   <li>Overrideable methods for controlling the synchronization lock,
+ *       type checks and write permission checks.</li>
+ * </ul>
+ *
+ * <p>The synchronization is provided mostly in order to prevent damages
+ * to the list in case of concurrent access. It does <strong>not</strong> prevent
+ * {@link java.util.ConcurrentModificationException} to be thrown during iterations,
+ * unless the whole iteration is synchronized on this list {@linkplain #getLock() lock}.
+ * For real concurrency, see the {@link java.util.concurrent} package instead.</p>
+ *
+ * {@note The above is the reason why the name of this class emphases the <cite>checked</cite>
+ * aspect rather than the <cite>synchronized</cite> aspect of the list.}
+ *
+ * @param <E> The type of elements in the list.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ *
+ * @see Collections#checkedList(List)
+ * @see Collections#synchronizedList(List)
+ */
+@ThreadSafe
+public class CheckedArrayList<E> extends ArrayList<E> implements CheckedContainer<E>,
Cloneable {
+    /**
+     * Serial version UID for compatibility with different versions.
+     */
+    private static final long serialVersionUID = -587331971085094268L;
+
+    /**
+     * The element type.
+     */
+    private final Class<E> type;
+
+    /**
+     * Constructs a list of the specified type.
+     *
+     * @param type The element type (can not be null).
+     */
+    public CheckedArrayList(final Class<E> type) {
+        super();
+        this.type = type;
+        ensureNonNull("type", type);
+    }
+
+    /**
+     * Constructs a list of the specified type and initial capacity.
+     *
+     * @param type The element type (should not be null).
+     * @param capacity The initial capacity.
+     */
+    public CheckedArrayList(final Class<E> type, final int capacity) {
+        super(capacity);
+        this.type = type;
+        ensureNonNull("type", type);
+    }
+
+    /**
+     * Returns the element type given at construction time.
+     */
+    @Override
+    public Class<E> getElementType() {
+        return type;
+    }
+
+    /**
+     * Ensures that the given element can be added to this list.
+     * The default implementation ensures that the object is assignable to the type specified
+     * at construction time. Subclasses can override this method if they need to perform
+     * additional checks.
+     *
+     * @param  element the object to check, or {@code null}.
+     * @throws IllegalArgumentException if the specified element can not be added to this
list.
+     */
+    protected void ensureValid(final E element) throws IllegalArgumentException {
+        if (element!=null && !type.isInstance(element)) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.IllegalArgumentClass_3, "element", element.getClass(), type));
+        }
+    }
+
+    /**
+     * Ensures that all elements of the given collection can be added to this list.
+     *
+     * @param  collection the collection to check, or {@code null}.
+     * @throws IllegalArgumentException if at least one element can not be added to this
list.
+     */
+    private void ensureValidCollection(final Collection<? extends E> collection) throws
IllegalArgumentException {
+        for (final E element : collection) {
+            ensureValid(element);
+        }
+    }
+
+    /**
+     * Checks if changes in this list are allowed. This method is automatically invoked
+     * after this list got the {@linkplain #getLock() lock} and before any operation that
+     * may change the content. If the write operation is allowed, then this method shall
+     * returns normally. Otherwise an {@link UnsupportedOperationException} is thrown.
+     * <p>
+     * The default implementation does nothing significant (see below), thus allowing this
list to
+     * be modified. Subclasses can override this method if they want to control write permissions.
+     *
+     * {@note Actually the current implementation contains an <code>assert</code>
statement
+     * ensuring that the thread holds the lock. This is an implementation details that may
+     * change in any future version of the SIS library. Nevertheless methods that override
+     * this one are encouraged to invoke <code>super.checkWritePermission()</code>.}
+     *
+     * @throws UnsupportedOperationException if this list is unmodifiable.
+     */
+    protected void checkWritePermission() throws UnsupportedOperationException {
+        assert Thread.holdsLock(getLock());
+    }
+
+    /**
+     * Returns the synchronization lock. The default implementation returns {@code this}.
+     *
+     * {@section Note for subclass implementors}
+     * Subclasses that override this method must be careful to update the lock reference
+     * when this list is {@linkplain #clone() cloned}.
+     *
+     * @return The synchronization lock.
+     */
+    protected Object getLock() {
+        return this;
+    }
+
+    /**
+     * Returns an iterator over the elements in this list.
+     */
+    @Override
+    public Iterator<E> iterator() {
+        final Object lock = getLock();
+        synchronized (lock) {
+            return new SynchronizedIterator<>(super.iterator(), lock);
+        }
+    }
+
+    // Note: providing a synchronized iterator is a little bit of paranoia because the ArrayList
+    // implementation inherits the default AbstractList implementation, which delegate its
work
+    // to the public List methods. All the later are already synchronized. We do not override
+    // ListIterator for this reason and because it is less used.
+
+    /**
+     * Returns the number of elements in this list.
+     */
+    @Override
+    public int size() {
+        synchronized (getLock()) {
+            return super.size();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     */
+    @Override
+    public boolean isEmpty() {
+        synchronized (getLock()) {
+            return super.isEmpty();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     */
+    @Override
+    public boolean contains(final Object o) {
+        synchronized (getLock()) {
+            return super.contains(o);
+        }
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in this list,
+     * or -1 if none.
+     */
+    @Override
+    public int indexOf(Object o) {
+        synchronized (getLock()) {
+            return super.indexOf(o);
+        }
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in this list,
+     * or -1 if none.
+     */
+    @Override
+    public int lastIndexOf(Object o) {
+        synchronized (getLock()) {
+            return super.lastIndexOf(o);
+        }
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     */
+    @Override
+    public E get(int index) {
+        synchronized (getLock()) {
+            return super.get(index);
+        }
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the specified element.
+     *
+     * @param  index   index of element to replace.
+     * @param  element element to be stored at the specified position.
+     * @return the element previously at the specified position.
+     * @throws IndexOutOfBoundsException if index out of range.
+     * @throws IllegalArgumentException if the specified element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public E set(final int index, final E element)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValid(element);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.set(index, element);
+        }
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param  element element to be appended to this list.
+     * @return always {@code true}.
+     * @throws IllegalArgumentException if the specified element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean add(final E element)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValid(element);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.add(element);
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list.
+     *
+     * @param  index index at which the specified element is to be inserted.
+     * @param  element element to be inserted.
+     * @throws IndexOutOfBoundsException if index out of range.
+     * @throws IllegalArgumentException if the specified element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public void add(final int index, final E element)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValid(element);
+        synchronized (getLock()) {
+            checkWritePermission();
+            super.add(index, element);
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of this list,
+     * in the order that they are returned by the specified Collection's Iterator.
+     *
+     * @param  collection the elements to be inserted into this list.
+     * @return {@code true} if this list changed as a result of the call.
+     * @throws IllegalArgumentException if at least one element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean addAll(final Collection<? extends E> collection)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValidCollection(collection);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.addAll(collection);
+        }
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this list,
+     * starting at the specified position.
+     *
+     * @param  index index at which to insert first element fromm the specified collection.
+     * @param  collection elements to be inserted into this list.
+     * @return {@code true} if this list changed as a result of the call.
+     * @throws IllegalArgumentException if at least one element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean addAll(final int index, final Collection<? extends E> collection)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValidCollection(collection);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.addAll(index, collection);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public E remove(int index) throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.remove(index);
+        }
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean remove(Object o) throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.remove(o);
+        }
+    }
+
+    /**
+     * Removes all of this list's elements that are also contained in the specified collection.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean removeAll(Collection<?> c) throws UnsupportedOperationException
{
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.removeAll(c);
+        }
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the specified collection.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean retainAll(Collection<?> c) throws UnsupportedOperationException
{
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.retainAll(c);
+        }
+    }
+
+    /**
+     * Trims the capacity to the list's current size.
+     */
+    @Override
+    public void trimToSize() {
+        synchronized (getLock()) {
+            super.trimToSize();
+        }
+    }
+
+    /**
+     * Increases the capacity, if necessary, to ensure that it can hold the given number
+     * of elements.
+     */
+    @Override
+    public void ensureCapacity(final int minCapacity) {
+        synchronized (getLock()) {
+            super.ensureCapacity(minCapacity);
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public void clear() throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            super.clear();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list.
+     */
+    @Override
+    public Object[] toArray() {
+        synchronized (getLock()) {
+            return super.toArray();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in proper sequence.
+     *
+     * @param <T> The type of array elements.
+     */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        synchronized (getLock()) {
+            return super.toArray(a);
+        }
+    }
+
+    /**
+     * Returns a string representation of this list.
+     */
+    @Override
+    public String toString() {
+        synchronized (getLock()) {
+            return super.toString();
+        }
+    }
+
+    /**
+     * Compares the specified object with this list for equality.
+     */
+    @Override
+    public boolean equals(Object o) {
+        synchronized (getLock()) {
+            return super.equals(o);
+        }
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     */
+    @Override
+    public int hashCode() {
+        synchronized (getLock()) {
+            return super.hashCode();
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this list.
+     *
+     * @return A shallow copy of this list.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public CheckedArrayList<E> clone() {
+        synchronized (getLock()) {
+            return (CheckedArrayList<E>) super.clone();
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedArrayList.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java?rev=1397069&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java
Thu Oct 11 14:21:01 2012
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.sis.util.collection;
+
+import java.util.Map;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import net.jcip.annotations.ThreadSafe;
+import org.apache.sis.util.resources.Errors;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+
+
+/**
+ * A {@linkplain Collections#checkedMap(Map) checked} and
+ * {@linkplain Collections#synchronizedMap(Map) synchronized} {@link LinkedHashMap}.
+ * The type checks are performed at run-time in addition to the compile-time checks.
+ *
+ * <p>Using this class is similar to wrapping a {@link LinkedHashMap} using the methods
provided
+ * in the standard {@link Collections} class, except for the following advantages:</p>
+ *
+ * <ul>
+ *   <li>Avoid the two levels of indirection (for type check and synchronization).</li>
+ *   <li>Checks for write permission.</li>
+ *   <li>Overrideable methods for controlling the synchronization lock and write permission
checks.</li>
+ * </ul>
+ *
+ * <p>The synchronization is provided mostly in order to prevent damages
+ * to the map in case of concurrent access. It does <strong>not</strong> prevent
+ * {@link java.util.ConcurrentModificationException} to be thrown during iterations,
+ * unless the whole iteration is synchronized on this map {@linkplain #getLock() lock}.
+ * For real concurrency, see the {@link java.util.concurrent} package instead.</p>
+ *
+ * {@note The above is the reason why the name of this class emphases the <cite>checked</cite>
+ * aspect rather than the <cite>synchronized</cite> aspect of the map.}
+ *
+ * @todo Current implementation do not synchronize the {@linkplain #entrySet entry set},
+ *       {@linkplain #keySet key set} and {@linkplain #values values} collection.
+ *
+ * @param <K> The type of keys in the map.
+ * @param <V> The type of values in the map.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ *
+ * @see Collections#checkedMap(Map)
+ * @see Collections#synchronizedMap(Map)
+ */
+@ThreadSafe
+public class CheckedHashMap<K,V> extends LinkedHashMap<K,V> implements Cloneable
{
+    /**
+     * Serial version UID for compatibility with different versions.
+     */
+    private static final long serialVersionUID = -7777695267921872849L;
+
+    /**
+     * The class type for keys.
+     */
+    private final Class<K> keyType;
+
+    /**
+     * The class type for values.
+     */
+    private final Class<V> valueType;
+
+    /**
+     * Constructs a map of the specified key and value types.
+     *
+     * @param keyType   The key type (can not be null).
+     * @param valueType The value type (can not be null).
+     */
+    public CheckedHashMap(final Class<K> keyType, final Class<V> valueType) {
+        this.keyType   = keyType;
+        this.valueType = valueType;
+        ensureNonNull("keyType",   keyType);
+        ensureNonNull("valueType", valueType);
+    }
+
+    /**
+     * Checks the type of the specified object.
+     *
+     * @param  element the object to check, or {@code null}.
+     * @throws IllegalArgumentException if the specified element is not of the expected type.
+     */
+    private static <E> void ensureValidType(final E element, final Class<E> type)
+            throws IllegalArgumentException
+    {
+        if (element!=null && !type.isInstance(element)) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.IllegalArgumentClass_3, "element", element.getClass(), type));
+        }
+    }
+
+    /**
+     * Checks if changes in this map are allowed. This method is automatically invoked
+     * after this map got the {@linkplain #getLock() lock} and before any operation that
+     * may change the content. If the write operation is allowed, then this method shall
+     * returns normally. Otherwise an {@link UnsupportedOperationException} is thrown.
+     * <p>
+     * The default implementation does nothing significant (see below), thus allowing this
map to
+     * be modified. Subclasses can override this method if they want to control write permissions.
+     *
+     * {@note Actually the current implementation contains an <code>assert</code>
statement
+     * ensuring that the thread holds the lock. This is an implementation details that may
+     * change in any future version of the SIS library. Nevertheless methods that override
+     * this one are encouraged to invoke <code>super.checkWritePermission()</code>.}
+     *
+     * @throws UnsupportedOperationException if this map is unmodifiable.
+     */
+    protected void checkWritePermission() throws UnsupportedOperationException {
+        assert Thread.holdsLock(getLock());
+    }
+
+    /**
+     * Returns the synchronization lock. The default implementation returns {@code this}.
+     *
+     * {@section Note for subclass implementors}
+     * Subclasses that override this method must be careful to update the lock reference
+     * when this map is {@linkplain #clone() cloned}.
+     *
+     * @return The synchronization lock.
+     */
+    protected Object getLock() {
+        return this;
+    }
+
+    /**
+     * Returns the number of elements in this map.
+     */
+    @Override
+    public int size() {
+        synchronized (getLock()) {
+            return super.size();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this map contains no elements.
+     */
+    @Override
+    public boolean isEmpty() {
+        synchronized (getLock()) {
+            return super.isEmpty();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this map contains the specified key.
+     */
+    @Override
+    public boolean containsKey(final Object key) {
+        synchronized (getLock()) {
+            return super.containsKey(key);
+        }
+    }
+
+    /**
+     * Returns {@code true} if this map contains the specified value.
+     */
+    @Override
+    public boolean containsValue(final Object value) {
+        synchronized (getLock()) {
+            return super.containsValue(value);
+        }
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped, or {@code null} if none.
+     */
+    @Override
+    public V get(Object key) {
+        synchronized (getLock()) {
+            return super.get(key);
+        }
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param  key key with which the specified value is to be associated.
+     * @param  value value to be associated with the specified key.
+     * @return previous value associated with specified key, or {@code null}.
+     * @throws IllegalArgumentException if the key or the value is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public V put(final K key, final V value)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValidType(key,     keyType);
+        ensureValidType(value, valueType);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.put(key, value);
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) throws UnsupportedOperationException
{
+        for (final Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
+            ensureValidType(entry.getKey(),     keyType);
+            ensureValidType(entry.getValue(), valueType);
+        }
+        synchronized (getLock()) {
+            checkWritePermission();
+            super.putAll(m);
+        }
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public V remove(Object key) throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.remove(key);
+        }
+    }
+
+    /**
+     * Removes all of the elements from this map.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public void clear() throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            super.clear();
+        }
+    }
+
+    /**
+     * Returns a string representation of this map.
+     */
+    @Override
+    public String toString() {
+        synchronized (getLock()) {
+            return super.toString();
+        }
+    }
+
+    /**
+     * Compares the specified object with this map for equality.
+     */
+    @Override
+    public boolean equals(Object o) {
+        synchronized (getLock()) {
+            return super.equals(o);
+        }
+    }
+
+    /**
+     * Returns the hash code value for this map.
+     */
+    @Override
+    public int hashCode() {
+        synchronized (getLock()) {
+            return super.hashCode();
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this map.
+     *
+     * @return A shallow copy of this map.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public CheckedHashMap<K,V> clone() {
+        synchronized (getLock()) {
+            return (CheckedHashMap<K,V>) super.clone();
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java?rev=1397069&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java
Thu Oct 11 14:21:01 2012
@@ -0,0 +1,363 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.sis.util.collection;
+
+import java.util.Set;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import net.jcip.annotations.ThreadSafe;
+import org.apache.sis.util.resources.Errors;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+
+
+/**
+ * A {@linkplain Collections#checkedSet(Set) checked} and
+ * {@linkplain Collections#synchronizedSet(Set) synchronized} {@link LinkedHashSet}.
+ * The type checks are performed at run-time in addition to the compile-time checks.
+ *
+ * <p>Using this class is similar to wrapping a {@link LinkedHashSet} using the methods
provided
+ * in the standard {@link Collections} class, except for the following advantages:</p>
+ *
+ * <ul>
+ *   <li>Avoid the two levels of indirection (for type check and synchronization).</li>
+ *   <li>Checks for write permission.</li>
+ *   <li>Overrideable methods for controlling the synchronization lock,
+ *       type checks and write permission checks.</li>
+ * </ul>
+ *
+ * <p>The synchronization is provided mostly in order to prevent damages
+ * to the set in case of concurrent accesses. It does <strong>not</strong> prevent
+ * {@link java.util.ConcurrentModificationException} to be thrown during iterations,
+ * unless the whole iteration is synchronized on this set {@linkplain #getLock() lock}.
+ * For real concurrency, see the {@link java.util.concurrent} package instead.</p>
+ *
+ * {@note The above is the reason why the name of this class emphases the <cite>checked</cite>
+ * aspect rather than the <cite>synchronized</cite> aspect of the set.}
+ *
+ * @param <E> The type of elements in the set.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ *
+ * @see Collections#checkedSet(Set)
+ * @see Collections#synchronizedSet(Set)
+ */
+@ThreadSafe
+public class CheckedHashSet<E> extends LinkedHashSet<E> implements CheckedContainer<E>,
Cloneable {
+    /**
+     * Serial version UID for compatibility with different versions.
+     */
+    private static final long serialVersionUID = -9014541457174735097L;
+
+    /**
+     * The element type.
+     */
+    private final Class<E> type;
+
+    /**
+     * Constructs a set of the specified type.
+     *
+     * @param type The element type (can not be null).
+     */
+    public CheckedHashSet(final Class<E> type) {
+        super();
+        this.type = type;
+        ensureNonNull("type", type);
+    }
+
+    /**
+     * Constructs a set of the specified type and initial capacity.
+     *
+     * @param type The element type (should not be null).
+     * @param capacity The initial capacity.
+     */
+    public CheckedHashSet(final Class<E> type, final int capacity) {
+        super(capacity);
+        this.type = type;
+        ensureNonNull("type", type);
+    }
+
+    /**
+     * Returns the element type given at construction time.
+     */
+    @Override
+    public Class<E> getElementType() {
+        return type;
+    }
+
+    /**
+     * Ensures that the given element can be added to this set.
+     * The default implementation ensures that the object is assignable to the type specified
+     * at construction time. Subclasses can override this method if they need to perform
+     * additional checks.
+     *
+     * @param  element the object to check, or {@code null}.
+     * @throws IllegalArgumentException if the specified element can not be added to this
set.
+     */
+    protected void ensureValid(final E element) throws IllegalArgumentException {
+        if (element!=null && !type.isInstance(element)) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.IllegalArgumentClass_3, "element", element.getClass(), type));
+        }
+    }
+
+    /**
+     * Ensures that all elements of the given collection can be added to this set.
+     *
+     * @param  collection the collection to check, or {@code null}.
+     * @throws IllegalArgumentException if at least one element can not be added to this
set.
+     */
+    private void ensureValidCollection(final Collection<? extends E> collection) throws
IllegalArgumentException {
+        for (final E element : collection) {
+            ensureValid(element);
+        }
+    }
+
+    /**
+     * Checks if changes in this set are allowed. This method is automatically invoked
+     * after this set got the {@linkplain #getLock() lock} and before any operation that
+     * may change the content. If the write operation is allowed, then this method shall
+     * returns normally. Otherwise an {@link UnsupportedOperationException} is thrown.
+     * <p>
+     * The default implementation does nothing significant (see below), thus allowing this
set to
+     * be modified. Subclasses can override this method if they want to control write permissions.
+     *
+     * {@note Actually the current implementation contains an <code>assert</code>
statement
+     * ensuring that the thread holds the lock. This is an implementation details that may
+     * change in any future version of the SIS library. Nevertheless methods that override
+     * this one are encouraged to invoke <code>super.checkWritePermission()</code>.}
+     *
+     * @throws UnsupportedOperationException if this set is unmodifiable.
+     */
+    protected void checkWritePermission() throws UnsupportedOperationException {
+        assert Thread.holdsLock(getLock());
+    }
+
+    /**
+     * Returns the synchronization lock. The default implementation returns {@code this}.
+     *
+     * {@section Note for subclass implementors}
+     * Subclasses that override this method must be careful to update the lock reference
+     * when this set is {@linkplain #clone() cloned}.
+     *
+     * @return The synchronization lock.
+     */
+    protected Object getLock() {
+        return this;
+    }
+
+    /**
+     * Returns an iterator over the elements in this set.
+     */
+    @Override
+    public Iterator<E> iterator() {
+        final Object lock = getLock();
+        synchronized (lock) {
+            return new SynchronizedIterator<>(super.iterator(), lock);
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     */
+    @Override
+    public int size() {
+        synchronized (getLock()) {
+            return super.size();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     */
+    @Override
+    public boolean isEmpty() {
+        synchronized (getLock()) {
+            return super.isEmpty();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     */
+    @Override
+    public boolean contains(final Object o) {
+        synchronized (getLock()) {
+            return super.contains(o);
+        }
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param  element element to be added to this set.
+     * @return {@code true} if the set did not already contain the specified element.
+     * @throws IllegalArgumentException if the specified element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean add(final E element)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValid(element);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.add(element);
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to this set.
+     *
+     * @param  collection the elements to be inserted into this set.
+     * @return {@code true} if this set changed as a result of the call.
+     * @throws IllegalArgumentException if at least one element is not of the expected type.
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean addAll(final Collection<? extends E> collection)
+            throws IllegalArgumentException, UnsupportedOperationException
+    {
+        ensureValidCollection(collection);
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.addAll(collection);
+        }
+    }
+
+    /**
+     * Removes the specified element from this set.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean remove(Object o) throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.remove(o);
+        }
+    }
+
+    /**
+     * Removes all of this set's elements that are also contained in the specified collection.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean removeAll(Collection<?> c) throws UnsupportedOperationException
{
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.removeAll(c);
+        }
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the specified collection.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public boolean retainAll(Collection<?> c) throws UnsupportedOperationException
{
+        synchronized (getLock()) {
+            checkWritePermission();
+            return super.retainAll(c);
+        }
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     *
+     * @throws UnsupportedOperationException if this collection is unmodifiable.
+     */
+    @Override
+    public void clear() throws UnsupportedOperationException {
+        synchronized (getLock()) {
+            checkWritePermission();
+            super.clear();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     */
+    @Override
+    public Object[] toArray() {
+        synchronized (getLock()) {
+            return super.toArray();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     *
+     * @param <T> The type of array elements.
+     */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        synchronized (getLock()) {
+            return super.toArray(a);
+        }
+    }
+
+    /**
+     * Returns a string representation of this set.
+     */
+    @Override
+    public String toString() {
+        synchronized (getLock()) {
+            return super.toString();
+        }
+    }
+
+    /**
+     * Compares the specified object with this set for equality.
+     */
+    @Override
+    public boolean equals(Object o) {
+        synchronized (getLock()) {
+            return super.equals(o);
+        }
+    }
+
+    /**
+     * Returns the hash code value for this set.
+     */
+    @Override
+    public int hashCode() {
+        synchronized (getLock()) {
+            return super.hashCode();
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this set.
+     *
+     * @return A shallow copy of this set.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public CheckedHashSet<E> clone() {
+        synchronized (getLock()) {
+            return (CheckedHashSet<E>) super.clone();
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/CheckedHashSet.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java?rev=1397069&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java
Thu Oct 11 14:21:01 2012
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.sis.util.collection;
+
+import java.util.Iterator;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+
+
+/**
+ * An iterator synchronized on the given lock. The functionality is equivalent to the one
provided
+ * by {@link java.util.Collections#synchronizedSet} iterator, except that the synchronization
is
+ * performed on an arbitrary lock.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ *
+ * @see java.util.Collections#synchronizedSet
+ */
+@ThreadSafe
+final class SynchronizedIterator<E> implements Iterator<E> {
+    /**
+     * The wrapped iterator.
+     */
+    @GuardedBy("lock")
+    private final Iterator<E> iterator;
+
+    /**
+     * The lock.
+     */
+    private final Object lock;
+
+    /**
+     * Creates a new iterator.
+     */
+    SynchronizedIterator(final Iterator<E> iterator, final Object lock) {
+        this.iterator = iterator;
+        this.lock = lock;
+    }
+
+    /**
+     * Returns {@code true} if there is more elements to iterate over.
+     */
+    @Override
+    public boolean hasNext() {
+        synchronized (lock) {
+            return iterator.hasNext();
+        }
+    }
+
+    /**
+     * Returns the next element in iterator order.
+     */
+    @Override
+    public E next() {
+        synchronized (lock) {
+            return iterator.next();
+        }
+    }
+
+    /**
+     * Removes the last iterated element.
+     */
+    @Override
+    public void remove() {
+        synchronized (lock) {
+            iterator.remove();
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/SynchronizedIterator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message