openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r417856 [20/22] - in /incubator/openjpa/trunk/openjpa-lib: java/ main/ main/java/ main/java/org/apache/openjpa/lib/ant/ main/java/org/apache/openjpa/lib/conf/ main/java/org/apache/openjpa/lib/jdbc/ main/java/org/apache/openjpa/lib/log/ main...
Date Wed, 28 Jun 2006 19:34:40 GMT
Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArrayList.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArrayList.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArrayList.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArrayList.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,1248 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * Written by Dawid Kurzyniec, on the basis of public specifications and
+ * public domain sources from JSR 166, and released to the public domain,
+ * as explained at http://creativecommons.org/licenses/publicdomain.
+ */
+package org.apache.openjpa.lib.util.concurrent;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import java.lang.reflect.Array;
+
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+
+public class CopyOnWriteArrayList implements List, Cloneable, Serializable {
+    private static final long serialVersionUID = 8673264195747942595L;
+    private volatile transient Object[] array;
+
+    public CopyOnWriteArrayList() {
+        setArray(new Object[0]);
+    }
+
+    public CopyOnWriteArrayList(Collection c) {
+        // must deal with concurrent collections
+        Object[] array = c.toArray();
+
+        // make sure the array is Object[] type
+        if (array.getClass() != Object[].class) {
+            array = Arrays.copyOf(array, array.length, Object[].class);
+        }
+
+        // assume that c.toArray() has returned a new array instance, as
+        // required by the spec
+        setArray(array);
+    }
+
+    public CopyOnWriteArrayList(Object[] array) {
+        setArray(Arrays.copyOf(array, array.length, Object[].class));
+    }
+
+    final Object[] getArray() {
+        return array;
+    }
+
+    final void setArray(Object[] array) {
+        this.array = array;
+    }
+
+    public int size() {
+        return getArray().length;
+    }
+
+    public boolean isEmpty() {
+        return getArray().length == 0;
+    }
+
+    private static int search(Object[] array, Object subject, int pos, int end) {
+        if (subject == null) {
+            for (; pos < end; pos++) {
+                if (array[pos] == null) {
+                    return pos;
+                }
+            }
+        } else {
+            for (; pos < end; pos++) {
+                if (subject.equals(array[pos])) {
+                    return pos;
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    private static int reverseSearch(Object[] array, Object subject, int start,
+        int pos) {
+        if (subject == null) {
+            for (pos--; pos >= start; pos--) {
+                if (array[pos] == null) {
+                    return pos;
+                }
+            }
+        } else {
+            for (pos--; pos >= start; pos--) {
+                if (subject.equals(array[pos])) {
+                    return pos;
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    public boolean contains(Object o) {
+        Object[] array = getArray();
+
+        return search(array, o, 0, array.length) >= 0;
+    }
+
+    public Iterator iterator() {
+        return new COWIterator(getArray(), 0);
+    }
+
+    public Object[] toArray() {
+        Object[] array = getArray();
+
+        return Arrays.copyOf(array, array.length, Object[].class);
+    }
+
+    public Object[] toArray(Object[] a) {
+        Object[] array = getArray();
+        int length = array.length;
+
+        if (a.length < length) {
+            return Arrays.copyOf(array, length, a.getClass());
+        } else {
+            System.arraycopy(array, 0, a, 0, length);
+
+            if (a.length > length) {
+                a[length] = null;
+            }
+
+            return a;
+        }
+    }
+
+    public boolean add(Object o) {
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int length = oldarr.length;
+            Object[] newarr = new Object[length + 1];
+            System.arraycopy(oldarr, 0, newarr, 0, length);
+            newarr[length] = o;
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public boolean addIfAbsent(Object o) {
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int length = oldarr.length;
+
+            if (search(array, o, 0, length) >= 0) {
+                return false;
+            }
+
+            Object[] newarr = new Object[length + 1];
+            System.arraycopy(oldarr, 0, newarr, 0, length);
+            newarr[length] = o;
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public int addAllAbsent(Collection c) {
+        Object[] arr = c.toArray();
+
+        if (arr.length == 0) {
+            return 0;
+        }
+
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int oldlength = oldarr.length;
+            Object[] tmp = new Object[arr.length];
+            int added = 0;
+
+            for (int i = 0; i < arr.length; i++) {
+                Object o = arr[i];
+
+                if ((search(oldarr, o, 0, oldlength) < 0) &&
+                        (search(tmp, o, 0, added) < 0)) {
+                    tmp[added++] = o;
+                }
+            }
+
+            if (added == 0) {
+                return 0;
+            }
+
+            Object[] newarr = new Object[oldlength + added];
+            System.arraycopy(oldarr, 0, newarr, 0, oldlength);
+            System.arraycopy(tmp, 0, newarr, oldlength, added);
+            setArray(newarr);
+
+            return added;
+        }
+    }
+
+    public boolean remove(Object o) {
+        synchronized (this) {
+            Object[] array = getArray();
+            int length = array.length;
+            int pos = search(array, o, 0, length);
+
+            if (pos < 0) {
+                return false;
+            }
+
+            Object[] newarr = new Object[length - 1];
+            int moved = length - pos - 1;
+
+            if (pos > 0) {
+                System.arraycopy(array, 0, newarr, 0, pos);
+            }
+
+            if (moved > 0) {
+                System.arraycopy(array, pos + 1, newarr, pos, moved);
+            }
+
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public boolean containsAll(Collection c) {
+        Object[] array = getArray();
+
+        for (Iterator itr = c.iterator(); itr.hasNext();) {
+            if (search(array, itr.next(), 0, array.length) < 0) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public boolean addAll(Collection c) {
+        // must deal with concurrent collections
+        Object[] ca = c.toArray();
+
+        if (ca.length == 0) {
+            return false;
+        }
+
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int length = oldarr.length;
+            Object[] newarr = new Object[length + ca.length];
+            System.arraycopy(oldarr, 0, newarr, 0, length);
+
+            int pos = length;
+            System.arraycopy(ca, 0, newarr, pos, ca.length);
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public boolean addAll(int index, Collection c) {
+        // must deal with concurrent collections
+        Object[] ca = c.toArray();
+
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int length = oldarr.length;
+
+            if ((index < 0) || (index > length)) {
+                throw new IndexOutOfBoundsException("Index: " + index +
+                    ", Size: " + length);
+            }
+
+            if (ca.length == 0) {
+                return false;
+            }
+
+            Object[] newarr = new Object[length + ca.length];
+            int moved = length - index;
+            System.arraycopy(oldarr, 0, newarr, 0, index);
+
+            int pos = length;
+            System.arraycopy(ca, 0, newarr, index, ca.length);
+
+            if (moved > 0) {
+                System.arraycopy(oldarr, index, newarr, index + ca.length, moved);
+            }
+
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public boolean removeAll(Collection c) {
+        if (c.isEmpty()) {
+            return false;
+        }
+
+        synchronized (this) {
+            Object[] array = getArray();
+            int length = array.length;
+            Object[] tmp = new Object[length];
+            int newlen = 0;
+
+            for (int i = 0; i < length; i++) {
+                Object o = array[i];
+
+                if (!c.contains(o)) {
+                    tmp[newlen++] = o;
+                }
+            }
+
+            if (newlen == length) {
+                return false;
+            }
+
+            Object[] newarr = new Object[newlen];
+            System.arraycopy(tmp, 0, newarr, 0, newlen);
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public boolean retainAll(Collection c) {
+        synchronized (this) {
+            Object[] array = getArray();
+            int length = array.length;
+            Object[] tmp = new Object[length];
+            int newlen = 0;
+
+            for (int i = 0; i < length; i++) {
+                Object o = array[i];
+
+                if (c.contains(o)) {
+                    tmp[newlen++] = o;
+                }
+            }
+
+            if (newlen == length) {
+                return false;
+            }
+
+            Object[] newarr = new Object[newlen];
+            System.arraycopy(tmp, 0, newarr, 0, newlen);
+            setArray(newarr);
+
+            return true;
+        }
+    }
+
+    public void clear() {
+        setArray(new Object[0]);
+    }
+
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof List)) {
+            return false;
+        }
+
+        ListIterator itr = ((List) o).listIterator();
+        Object[] array = getArray();
+        int length = array.length;
+        int idx = 0;
+
+        while ((idx < length) && itr.hasNext()) {
+            Object o1 = array[idx++];
+            Object o2 = itr.next();
+
+            if (!eq(o1, o2)) {
+                return false;
+            }
+        }
+
+        return ((idx == length) && !itr.hasNext());
+    }
+
+    public int hashCode() {
+        int hashCode = 1;
+        Object[] array = getArray();
+        int length = array.length;
+
+        for (int i = 0; i < length; i++) {
+            Object o = array[i];
+            hashCode = (31 * hashCode) + ((o == null) ? 0 : o.hashCode());
+        }
+
+        return hashCode;
+    }
+
+    public Object get(int index) {
+        return getArray()[index];
+    }
+
+    public Object set(int index, Object element) {
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int length = oldarr.length;
+
+            // piggyback the array bounds check
+            Object oldVal = oldarr[index];
+
+            if (oldVal == element) {
+                setArray(oldarr);
+            } else {
+                Object[] newarr = new Object[length];
+                System.arraycopy(oldarr, 0, newarr, 0, length);
+                newarr[index] = element;
+                setArray(newarr);
+            }
+
+            return oldVal;
+        }
+    }
+
+    public void add(int index, Object element) {
+        synchronized (this) {
+            Object[] oldarr = getArray();
+            int length = oldarr.length;
+
+            if ((index < 0) || (index > length)) {
+                throw new IndexOutOfBoundsException("Index: " + index +
+                    ", Size: " + length);
+            }
+
+            Object[] newarr = new Object[length + 1];
+            int moved = length - index;
+            System.arraycopy(oldarr, 0, newarr, 0, index);
+            newarr[index] = element;
+
+            if (moved > 0) {
+                System.arraycopy(oldarr, index, newarr, index + 1, moved);
+            }
+
+            setArray(newarr);
+        }
+    }
+
+    public Object remove(int index) {
+        synchronized (this) {
+            Object[] array = getArray();
+            int length = array.length;
+
+            if ((index < 0) || (index >= length)) {
+                throw new IndexOutOfBoundsException("Index: " + index +
+                    ", Size: " + length);
+            }
+
+            Object result = array[index];
+            Object[] newarr = new Object[length - 1];
+            int moved = length - index - 1;
+
+            if (index > 0) {
+                System.arraycopy(array, 0, newarr, 0, index);
+            }
+
+            if (moved > 0) {
+                System.arraycopy(array, index + 1, newarr, index, moved);
+            }
+
+            setArray(newarr);
+
+            return result;
+        }
+    }
+
+    public int indexOf(Object o) {
+        Object[] array = getArray();
+
+        return search(array, o, 0, array.length);
+    }
+
+    public int indexOf(Object o, int index) {
+        Object[] array = getArray();
+
+        return search(array, o, index, array.length);
+    }
+
+    public int lastIndexOf(Object o) {
+        Object[] array = getArray();
+
+        return reverseSearch(array, o, 0, array.length);
+    }
+
+    public int lastIndexOf(Object o, int index) {
+        Object[] array = getArray();
+
+        return reverseSearch(array, o, 0, index);
+    }
+
+    public ListIterator listIterator() {
+        return new COWIterator(getArray(), 0);
+    }
+
+    public ListIterator listIterator(int index) {
+        Object[] array = getArray();
+
+        if ((index < 0) || (index > array.length)) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " +
+                array.length);
+        }
+
+        return new COWIterator(array, index);
+    }
+
+    public List subList(int fromIndex, int toIndex) {
+        Object[] array = getArray();
+
+        if ((fromIndex < 0) || (toIndex > array.length) ||
+                (fromIndex > toIndex)) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        return new COWSubList(fromIndex, toIndex - fromIndex);
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+
+        Object[] array = getArray();
+        int length = array.length;
+        out.writeInt(length);
+
+        for (int i = 0; i < length; i++)
+            out.writeObject(array[i]);
+    }
+
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+
+        int length = in.readInt();
+        Object[] array = new Object[length];
+
+        for (int i = 0; i < length; i++) {
+            array[i] = in.readObject();
+        }
+
+        setArray(array);
+    }
+
+    public String toString() {
+        Object[] array = getArray();
+        int length = array.length;
+        StringBuffer buf = new StringBuffer();
+        buf.append('[');
+
+        for (int i = 0; i < length; i++) {
+            if (i > 0) {
+                buf.append(", ");
+            }
+
+            buf.append(array[i]);
+        }
+
+        buf.append(']');
+
+        return buf.toString();
+    }
+
+    private static boolean eq(Object o1, Object o2) {
+        return ((o1 == null) ? (o2 == null) : o1.equals(o2));
+    }
+
+    static class COWIterator implements ListIterator {
+        final Object[] array;
+        int cursor;
+
+        COWIterator(Object[] array, int cursor) {
+            this.array = array;
+            this.cursor = cursor;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        public boolean hasPrevious() {
+            return cursor > 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public Object next() {
+            try {
+                return array[cursor++];
+            } catch (IndexOutOfBoundsException e) {
+                throw new NoSuchElementException();
+            }
+
+            // todo: should decrement cursor on failure?...
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        public Object previous() {
+            try {
+                return array[--cursor];
+            } catch (IndexOutOfBoundsException e) {
+                throw new NoSuchElementException();
+            }
+
+            // todo: should decrement cursor on failure?...
+        }
+
+        public void add(Object val) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(Object val) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    class COWSubList implements Serializable, List {
+        final int offset;
+        int length;
+        Object[] expectedArray;
+
+        COWSubList(int offset, int length) {
+            this.offset = offset;
+            this.length = length;
+            this.expectedArray = getArray();
+        }
+
+        public int size() {
+            return length;
+        }
+
+        public boolean isEmpty() {
+            return length == 0;
+        }
+
+        public boolean contains(Object o) {
+            return search(getArray(), o, offset, offset + length) >= 0;
+        }
+
+        public Iterator iterator() {
+            return listIterator();
+        }
+
+        public Object[] toArray() {
+            Object[] array = getArray();
+            Object[] newarr = new Object[length];
+            System.arraycopy(array, offset, newarr, 0, length);
+
+            return newarr;
+        }
+
+        public Object[] toArray(Object[] a) {
+            Object[] array = getArray();
+
+            if (a.length < length) {
+                a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
+                        length);
+                System.arraycopy(array, offset, a, 0, length);
+            } else {
+                System.arraycopy(array, offset, a, 0, length);
+
+                if (a.length > length) {
+                    a[length] = null;
+                }
+            }
+
+            return a;
+        }
+
+        public boolean add(Object o) {
+            add(length, o);
+
+            return true;
+        }
+
+        public boolean remove(Object o) {
+            synchronized (CopyOnWriteArrayList.this) {
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = array.length;
+                int pos = search(array, o, offset, length);
+
+                if (pos < 0) {
+                    return false;
+                }
+
+                Object[] newarr = new Object[fullLength - 1];
+                int moved = length - pos - 1;
+
+                if (pos > 0) {
+                    System.arraycopy(array, 0, newarr, 0, pos);
+                }
+
+                if (moved > 0) {
+                    System.arraycopy(array, pos + 1, newarr, pos, moved);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length--;
+
+                return true;
+            }
+        }
+
+        public boolean containsAll(Collection c) {
+            Object[] array = getArray();
+
+            for (Iterator itr = c.iterator(); itr.hasNext();) {
+                if (search(array, itr.next(), offset, length) < 0) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public boolean addAll(Collection c) {
+            return addAll(length, c);
+        }
+
+        public boolean addAll(int index, Collection c) {
+            int added = c.size();
+
+            synchronized (CopyOnWriteArrayList.this) {
+                if ((index < 0) || (index >= length)) {
+                    throw new IndexOutOfBoundsException("Index: " + index +
+                        ", Size: " + length);
+                }
+
+                Object[] oldarr = getArray();
+
+                if (oldarr != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                if (added == 0) {
+                    return false;
+                }
+
+                int fullLength = oldarr.length;
+                Object[] newarr = new Object[fullLength + added];
+                int pos = offset + index;
+                int newpos = pos;
+                System.arraycopy(oldarr, 0, newarr, 0, pos);
+
+                int rem = fullLength - pos;
+
+                for (Iterator itr = c.iterator(); itr.hasNext();) {
+                    newarr[newpos++] = itr.next();
+                }
+
+                if (rem > 0) {
+                    System.arraycopy(oldarr, pos, newarr, newpos, rem);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length += added;
+
+                return true;
+            }
+        }
+
+        public boolean removeAll(Collection c) {
+            if (c.isEmpty()) {
+                return false;
+            }
+
+            synchronized (CopyOnWriteArrayList.this) {
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = array.length;
+                Object[] tmp = new Object[length];
+                int retained = 0;
+
+                for (int i = offset; i < (offset + length); i++) {
+                    Object o = array[i];
+
+                    if (!c.contains(o)) {
+                        tmp[retained++] = o;
+                    }
+                }
+
+                if (retained == length) {
+                    return false;
+                }
+
+                Object[] newarr = new Object[(fullLength + retained) - length];
+                int moved = fullLength - offset - length;
+
+                if (offset > 0) {
+                    System.arraycopy(array, 0, newarr, 0, offset);
+                }
+
+                if (retained > 0) {
+                    System.arraycopy(tmp, 0, newarr, offset, retained);
+                }
+
+                if (moved > 0) {
+                    System.arraycopy(array, offset + length, newarr,
+                        offset + retained, moved);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length = retained;
+
+                return true;
+            }
+        }
+
+        public boolean retainAll(Collection c) {
+            synchronized (CopyOnWriteArrayList.this) {
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = array.length;
+                Object[] tmp = new Object[length];
+                int retained = 0;
+
+                for (int i = offset; i < (offset + length); i++) {
+                    Object o = array[i];
+
+                    if (c.contains(o)) {
+                        tmp[retained++] = o;
+                    }
+                }
+
+                if (retained == length) {
+                    return false;
+                }
+
+                Object[] newarr = new Object[(fullLength + retained) - length];
+                int moved = fullLength - offset - length;
+
+                if (offset > 0) {
+                    System.arraycopy(array, 0, newarr, 0, offset);
+                }
+
+                if (retained > 0) {
+                    System.arraycopy(tmp, 0, newarr, offset, retained);
+                }
+
+                if (moved > 0) {
+                    System.arraycopy(array, offset + length, newarr,
+                        offset + retained, moved);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length = retained;
+
+                return true;
+            }
+        }
+
+        public void clear() {
+            synchronized (CopyOnWriteArrayList.this) {
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = array.length;
+                Object[] newarr = new Object[fullLength - length];
+                int moved = fullLength - offset - length;
+
+                if (offset > 0) {
+                    System.arraycopy(array, 0, newarr, 0, offset);
+                }
+
+                if (moved > 0) {
+                    System.arraycopy(array, offset + length, newarr, offset,
+                        moved);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length = 0;
+            }
+        }
+
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+
+            if (!(o instanceof List)) {
+                return false;
+            }
+
+            Object[] array;
+            int last;
+
+            synchronized (CopyOnWriteArrayList.this) {
+                array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                last = offset + length;
+            }
+
+            ListIterator itr = ((List) o).listIterator();
+            int idx = offset;
+
+            while ((idx < last) && itr.hasNext()) {
+                Object o1 = array[idx];
+                Object o2 = itr.next();
+
+                if (!eq(o1, o2)) {
+                    return false;
+                }
+            }
+
+            return ((idx == last) && !itr.hasNext());
+        }
+
+        public int hashCode() {
+            int hashCode = 1;
+            Object[] array;
+            int last;
+
+            synchronized (CopyOnWriteArrayList.this) {
+                array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                last = offset + length;
+            }
+
+            for (int i = offset; i < last; i++) {
+                Object o = array[i];
+                hashCode = (31 * hashCode) + ((o == null) ? 0 : o.hashCode());
+            }
+
+            return hashCode;
+        }
+
+        public Object get(int index) {
+            return getArray()[offset + index];
+        }
+
+        public Object set(int index, Object element) {
+            synchronized (CopyOnWriteArrayList.this) {
+                if ((index < 0) || (index >= length)) {
+                    throw new IndexOutOfBoundsException("Index: " + index +
+                        ", Size: " + length);
+                }
+
+                Object[] oldarr = getArray();
+
+                if (oldarr != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = oldarr.length;
+
+                // piggyback the array bounds check
+                Object oldVal = oldarr[offset + index];
+
+                if (oldVal == element) {
+                    setArray(oldarr);
+                } else {
+                    Object[] newarr = new Object[fullLength];
+                    System.arraycopy(oldarr, 0, newarr, 0, fullLength);
+                    newarr[offset + index] = element;
+                    setArray(newarr);
+                    expectedArray = newarr;
+                }
+
+                return oldVal;
+            }
+        }
+
+        public void add(int index, Object element) {
+            synchronized (CopyOnWriteArrayList.this) {
+                if ((index < 0) || (index > length)) {
+                    throw new IndexOutOfBoundsException("Index: " + index +
+                        ", Size: " + length);
+                }
+
+                Object[] oldarr = getArray();
+
+                if (oldarr != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = oldarr.length;
+                Object[] newarr = new Object[fullLength + 1];
+                int pos = offset + index;
+                int moved = fullLength - pos;
+                System.arraycopy(oldarr, 0, newarr, 0, pos);
+                newarr[pos] = element;
+
+                if (moved > 0) {
+                    System.arraycopy(oldarr, pos, newarr, pos + 1, moved);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length++;
+            }
+        }
+
+        public Object remove(int index) {
+            synchronized (CopyOnWriteArrayList.this) {
+                if ((index < 0) || (index >= length)) {
+                    throw new IndexOutOfBoundsException("Index: " + index +
+                        ", Size: " + length);
+                }
+
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                int fullLength = array.length;
+                int pos = offset + index;
+                Object result = array[pos];
+                Object[] newarr = new Object[fullLength - 1];
+                int moved = fullLength - pos - 1;
+
+                if (index > 0) {
+                    System.arraycopy(array, 0, newarr, 0, pos);
+                }
+
+                if (moved > 0) {
+                    System.arraycopy(array, pos + 1, newarr, pos, moved);
+                }
+
+                setArray(newarr);
+                expectedArray = newarr;
+                length--;
+
+                return result;
+            }
+        }
+
+        public int indexOf(Object o) {
+            int pos = search(getArray(), o, offset, offset + length);
+
+            return (pos >= 0) ? (pos - offset) : (-1);
+        }
+
+        public int indexOf(Object o, int index) {
+            int pos = search(getArray(), o, offset + index, offset + length) -
+                offset;
+
+            return (pos >= 0) ? (pos - offset) : (-1);
+        }
+
+        public int lastIndexOf(Object o) {
+            int pos = reverseSearch(getArray(), o, offset, offset + length) -
+                offset;
+
+            return (pos >= 0) ? (pos - offset) : (-1);
+        }
+
+        public int lastIndexOf(Object o, int index) {
+            int pos = reverseSearch(getArray(), o, offset, offset + index) -
+                offset;
+
+            return (pos >= 0) ? (pos - offset) : (-1);
+        }
+
+        public ListIterator listIterator() {
+            // must synchronize to atomically obtain the array and length
+            synchronized (CopyOnWriteArrayList.this) {
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                return new COWSubIterator(array, offset, offset + length, offset);
+            }
+        }
+
+        public ListIterator listIterator(int index) {
+            // must synchronize to atomically obtain the array and length
+            synchronized (CopyOnWriteArrayList.this) {
+                if ((index < 0) || (index >= length)) {
+                    throw new IndexOutOfBoundsException("Index: " + index +
+                        ", Size: " + length);
+                }
+
+                Object[] array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                return new COWSubIterator(array, offset, offset + length,
+                    offset + index);
+            }
+        }
+
+        public List subList(int fromIndex, int toIndex) {
+            if ((fromIndex < 0) || (toIndex > length) || (fromIndex > toIndex)) {
+                throw new IndexOutOfBoundsException();
+            }
+
+            return new COWSubList(offset + fromIndex, toIndex - fromIndex);
+        }
+
+        public String toString() {
+            Object[] array;
+            int last;
+
+            synchronized (CopyOnWriteArrayList.this) {
+                array = getArray();
+
+                if (array != expectedArray) {
+                    throw new ConcurrentModificationException();
+                }
+
+                last = offset + length;
+            }
+
+            StringBuffer buf = new StringBuffer();
+            buf.append('[');
+
+            for (int i = offset; i < last; i++) {
+                if (i > offset) {
+                    buf.append(", ");
+                }
+
+                buf.append(array[i]);
+            }
+
+            buf.append(']');
+
+            return buf.toString();
+        }
+    }
+
+    static class COWSubIterator implements ListIterator {
+        final Object[] array;
+        int cursor;
+        int first;
+        int last;
+
+        COWSubIterator(Object[] array, int first, int last, int cursor) {
+            this.array = array;
+            this.first = first;
+            this.last = last;
+            this.cursor = cursor;
+        }
+
+        public boolean hasNext() {
+            return cursor < last;
+        }
+
+        public boolean hasPrevious() {
+            return cursor > first;
+        }
+
+        public int nextIndex() {
+            return cursor - first;
+        }
+
+        public Object next() {
+            if (cursor == last) {
+                throw new NoSuchElementException();
+            }
+
+            return array[cursor++];
+        }
+
+        public int previousIndex() {
+            return cursor - first - 1;
+        }
+
+        public Object previous() {
+            if (cursor == first) {
+                throw new NoSuchElementException();
+            }
+
+            return array[--cursor];
+        }
+
+        public void add(Object val) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(Object val) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArrayList.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArraySet.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArraySet.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArraySet.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArraySet.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain. Use, modify, and
+ * redistribute this code in any way without acknowledgement.
+ */
+package org.apache.openjpa.lib.util.concurrent;
+
+import java.util.*;
+
+
+/**
+ * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
+ * for all of its operations.  Thus, it shares the same basic properties:
+ * <ul>
+ *  <li>It is best suited for applications in which set sizes generally
+ *       stay small, read-only operations
+ *       vastly outnumber mutative operations, and you need
+ *       to prevent interference among threads during traversal.
+ *  <li>It is thread-safe.
+ *  <li>Mutative operations (<tt>add</tt>, <tt>set</tt>, <tt>remove</tt>, etc.)
+ *      are expensive since they usually entail copying the entire underlying
+ *      array.
+ *  <li>Iterators do not support the mutative <tt>remove</tt> operation.
+ *  <li>Traversal via iterators is fast and cannot encounter
+ *      interference from other threads. Iterators rely on
+ *      unchanging snapshots of the array at the time the iterators were
+ *      constructed.
+ * </ul>
+ *
+ * <p> <b>Sample Usage.</b> The following code sketch uses a
+ * copy-on-write set to maintain a set of Handler objects that
+ * perform some action upon state updates.
+ *
+ * <pre>
+ * class Handler { void handle(); ... }
+ *
+ * class X {
+ *    private final CopyOnWriteArraySet&lt;Handler&gt; handlers
+ *       = new CopyOnWriteArraySet&lt;Handler&gt;();
+ *    public void addHandler(Handler h) { handlers.add(h); }
+ *
+ *    private long internalState;
+ *    private synchronized void changeState() { internalState = ...; }
+ *
+ *    public void update() {
+ *       changeState();
+ *       for (Handler handler : handlers)
+ *          handler.handle();
+ *    }
+ * }
+ * </pre>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../guide/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @see CopyOnWriteArrayList
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CopyOnWriteArraySet extends AbstractSet implements java.io.Serializable {
+    private static final long serialVersionUID = 5457747651344034263L;
+    private final CopyOnWriteArrayList al;
+
+    /**
+     * Creates an empty set.
+     */
+    public CopyOnWriteArraySet() {
+        al = new CopyOnWriteArrayList();
+    }
+
+    /**
+     * Creates a set containing all of the elements of the specified
+     * collection.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArraySet(Collection c) {
+        al = new CopyOnWriteArrayList();
+        al.addAllAbsent(c);
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return al.size();
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return al.isEmpty();
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     * More formally, returns <tt>true</tt> if and only if this set
+     * contains an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return al.contains(o);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    public Object[] toArray() {
+        return al.toArray();
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * <tt>null</tt>.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose <tt>x</tt> is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of <tt>String</tt>:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
+     * <tt>toArray()</tt>.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    public Object[] toArray(Object[] a) {
+        return al.toArray(a);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        al.clear();
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
+     * if this set contains such an element.  Returns <tt>true</tt> if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return <tt>true</tt> if this set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return al.remove(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element <tt>e</tt> to this set if
+     * the set contains no element <tt>e2</tt> such that
+     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns <tt>false</tt>.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if this set did not already contain the specified
+     *         element
+     */
+    public boolean add(Object e) {
+        return al.addIfAbsent(e);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns <tt>true</tt> if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return <tt>true</tt> if this set contains all of the elements of the
+    *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection c) {
+        return al.containsAll(c);
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present.  If the specified collection is also a
+     * set, the <tt>addAll</tt> operation effectively modifies this set so
+     * that its value is the <i>union</i> of the two sets.  The behavior of
+     * this operation is undefined if the specified collection is modified
+     * while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection c) {
+        return al.addAllAbsent(c) > 0;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection.  If the specified collection is also a set,
+     * this operation effectively modifies this set so that its value is the
+     * <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection (optional)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements (optional),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection c) {
+        return al.removeAll(c);
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.  In other words, removes from this set all of
+     * its elements that are not contained in the specified collection.  If
+     * the specified collection is also a set, this operation effectively
+     * modifies this set so that its value is the <i>intersection</i> of the
+     * two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection (optional)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements (optional),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection c) {
+        return al.retainAll(c);
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set
+     * in the order in which these elements were added.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the set
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * <tt>remove</tt> method.
+     *
+     * @return an iterator over the elements in this set
+     */
+    public Iterator iterator() {
+        return al.iterator();
+    }
+
+    /**
+     * Compares the specified object with this set for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link Set} and the elements
+     * returned by an {@linkplain List#iterator() iterator} over the
+     * specified set are the same as the elements returned by an
+     * iterator over this set.  More formally, the two iterators are
+     * considered to return the same elements if they return the same
+     * number of elements and for every element {@code e1} returned by
+     * the iterator over the specified set, there is an element
+     * {@code e2} returned by the iterator over this set such that
+     * {@code (e1==null ? e2==null : e1.equals(e2))}.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof Set)) {
+            return false;
+        }
+
+        Set set = (Set) (o);
+        Iterator it = set.iterator();
+
+        // Uses O(n^2) algorithm that is only appropriate
+        // for small sets, which CopyOnWriteArraySets should be.
+
+        //  Use a single snapshot of underlying array
+        Object[] elements = al.getArray();
+        int len = elements.length;
+
+        // Mark matched elements to avoid re-checking
+        boolean[] matched = new boolean[len];
+        int k = 0;
+outer: 
+        while (it.hasNext()) {
+            if (++k > len) {
+                return false;
+            }
+
+            Object x = it.next();
+
+            for (int i = 0; i < len; ++i) {
+                if (!matched[i] && eq(x, elements[i])) {
+                    matched[i] = true;
+
+                    continue outer;
+                }
+            }
+
+            return false;
+        }
+
+        return k == len;
+    }
+
+    /**
+     * Test for equality, coping with nulls.
+     */
+    private static boolean eq(Object o1, Object o2) {
+        return ((o1 == null) ? (o2 == null) : o1.equals(o2));
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/CopyOnWriteArraySet.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOCondVar.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOCondVar.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOCondVar.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOCondVar.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * Originally written by Doug Lea and released into the public domain.
+ * This may be used for any purposes whatsoever without acknowledgment.
+ * Thanks for the assistance and support of Sun Microsystems Labs,
+ * and everyone contributing, testing, and using this code.
+ */
+package org.apache.openjpa.lib.util.concurrent;
+
+import java.util.*;
+
+
+class FIFOCondVar extends CondVar implements Condition, java.io.Serializable {
+    private static final WaitQueue.QueuedSync sync = new WaitQueue.QueuedSync() {
+            public boolean recheck(WaitQueue.WaitNode node) {
+                return false;
+            }
+
+            public void takeOver(WaitQueue.WaitNode node) {
+            }
+        };
+
+    // wait queue; only accessed when holding the lock
+    private final WaitQueue wq = new FIFOWaitQueue();
+
+    /**
+     * Create a new CondVar that relies on the given mutual exclusion lock.
+     * @param lock A non-reentrant mutual exclusion lock.
+     */
+    FIFOCondVar(ExclusiveLock lock) {
+        super(lock);
+    }
+
+    public void awaitUninterruptibly() {
+        int holdCount = lock.getHoldCount();
+
+        if (holdCount == 0) {
+            throw new IllegalMonitorStateException();
+        }
+
+        WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+        wq.insert(n);
+
+        for (int i = holdCount; i > 0; i--)
+            lock.unlock();
+
+        try {
+            n.doWaitUninterruptibly(sync);
+        } finally {
+            for (int i = holdCount; i > 0; i--)
+                lock.lock();
+        }
+    }
+
+    public void await() throws InterruptedException {
+        int holdCount = lock.getHoldCount();
+
+        if (holdCount == 0) {
+            throw new IllegalMonitorStateException();
+        }
+
+        if (Thread.interrupted()) {
+            throw new InterruptedException();
+        }
+
+        WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+        wq.insert(n);
+
+        for (int i = holdCount; i > 0; i--)
+            lock.unlock();
+
+        try {
+            n.doWait(sync);
+        } finally {
+            for (int i = holdCount; i > 0; i--)
+                lock.lock();
+        }
+    }
+
+    public boolean await(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        int holdCount = lock.getHoldCount();
+
+        if (holdCount == 0) {
+            throw new IllegalMonitorStateException();
+        }
+
+        if (Thread.interrupted()) {
+            throw new InterruptedException();
+        }
+
+        long nanos = unit.toNanos(timeout);
+        WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+        wq.insert(n);
+
+        boolean success = false;
+
+        for (int i = holdCount; i > 0; i--)
+            lock.unlock();
+
+        try {
+            success = n.doTimedWait(sync, nanos);
+        } finally {
+            for (int i = holdCount; i > 0; i--)
+                lock.lock();
+        }
+
+        return success;
+    }
+
+    //    public long awaitNanos(long timeout) throws InterruptedException {
+    //        throw new UnsupportedOperationException();
+    //    }
+    public boolean awaitUntil(Date deadline) throws InterruptedException {
+        if (deadline == null) {
+            throw new NullPointerException();
+        }
+
+        long abstime = deadline.getTime();
+        long start = System.currentTimeMillis();
+        long msecs = abstime - start;
+
+        return await(msecs, TimeUnit.MILLISECONDS);
+    }
+
+    public void signal() {
+        if (!lock.isHeldByCurrentThread()) {
+            throw new IllegalMonitorStateException();
+        }
+
+        for (;;) {
+            WaitQueue.WaitNode w = wq.extract();
+
+            if (w == null) {
+                return; // no one to signal
+            }
+
+            if (w.signal(sync)) {
+                return; // notify if still waiting, else skip
+            }
+        }
+    }
+
+    public void signalAll() {
+        if (!lock.isHeldByCurrentThread()) {
+            throw new IllegalMonitorStateException();
+        }
+
+        for (;;) {
+            WaitQueue.WaitNode w = wq.extract();
+
+            if (w == null) {
+                return; // no more to signal
+            }
+
+            w.signal(sync);
+        }
+    }
+
+    protected boolean hasWaiters() {
+        if (!lock.isHeldByCurrentThread()) {
+            throw new IllegalMonitorStateException();
+        }
+
+        return wq.hasNodes();
+    }
+
+    protected int getWaitQueueLength() {
+        if (!lock.isHeldByCurrentThread()) {
+            throw new IllegalMonitorStateException();
+        }
+
+        return wq.getLength();
+    }
+
+    protected Collection getWaitingThreads() {
+        if (!lock.isHeldByCurrentThread()) {
+            throw new IllegalMonitorStateException();
+        }
+
+        return wq.getWaitingThreads();
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOCondVar.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOWaitQueue.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOWaitQueue.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOWaitQueue.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOWaitQueue.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/licenses/publicdomain
+ */
+package org.apache.openjpa.lib.util.concurrent;
+
+import java.util.*;
+
+
+/**
+ * Simple linked list queue used in FIFOSemaphore.
+ * Methods are not synchronized; they depend on synch of callers.
+ * Must be public, since it is used by Semaphore (outside this package).
+ * NOTE: this class is NOT present in java.util.concurrent.
+ */
+class FIFOWaitQueue extends WaitQueue implements java.io.Serializable {
+    protected transient WaitNode head_ = null;
+    protected transient WaitNode tail_ = null;
+
+    public FIFOWaitQueue() {
+    }
+
+    public void insert(WaitNode w) {
+        if (tail_ == null) {
+            head_ = tail_ = w;
+        } else {
+            tail_.next = w;
+            tail_ = w;
+        }
+    }
+
+    public WaitNode extract() {
+        if (head_ == null) {
+            return null;
+        } else {
+            WaitNode w = head_;
+            head_ = w.next;
+
+            if (head_ == null) {
+                tail_ = null;
+            }
+
+            w.next = null;
+
+            return w;
+        }
+    }
+
+    public boolean hasNodes() {
+        return head_ != null;
+    }
+
+    public int getLength() {
+        int count = 0;
+        WaitNode node = head_;
+
+        while (node != null) {
+            if (node.waiting) {
+                count++;
+            }
+
+            node = node.next;
+        }
+
+        return count;
+    }
+
+    public Collection getWaitingThreads() {
+        List list = new ArrayList();
+        int count = 0;
+        WaitNode node = head_;
+
+        while (node != null) {
+            if (node.waiting) {
+                list.add(node.owner);
+            }
+
+            node = node.next;
+        }
+
+        return list;
+    }
+
+    public boolean isWaiting(Thread thread) {
+        if (thread == null) {
+            throw new NullPointerException();
+        }
+
+        for (WaitNode node = head_; node != null; node = node.next) {
+            if (node.waiting && (node.owner == thread)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/FIFOWaitQueue.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/Lock.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/Lock.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/Lock.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/Lock.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/licenses/publicdomain
+ */
+package org.apache.openjpa.lib.util.concurrent;
+
+
+/**
+ * <tt>Lock</tt> implementations provide more extensive locking
+ * operations than can be obtained using <tt>synchronized</tt> methods
+ * and statements.  They allow more flexible structuring, may have
+ * quite different properties, and may support multiple associated
+ * {@link Condition} objects.
+ *
+ * <p>A lock is a tool for controlling access to a shared resource by
+ * multiple threads. Commonly, a lock provides exclusive access to a
+ * shared resource: only one thread at a time can acquire the lock and
+ * all access to the shared resource requires that the lock be
+ * acquired first. However, some locks may allow concurrent access to
+ * a shared resource, such as the read lock of a {@link
+ * ReadWriteLock}.
+ *
+ * <p>The use of <tt>synchronized</tt> methods or statements provides
+ * access to the implicit monitor lock associated with every object, but
+ * forces all lock acquisition and release to occur in a block-structured way:
+ * when multiple locks are acquired they must be released in the opposite
+ * order, and all locks must be released in the same lexical scope in which
+ * they were acquired.
+ *
+ * <p>While the scoping mechanism for <tt>synchronized</tt> methods
+ * and statements makes it much easier to program with monitor locks,
+ * and helps avoid many common programming errors involving locks,
+ * there are occasions where you need to work with locks in a more
+ * flexible way. For example, some algorithms for traversing
+ * concurrently accessed data structures require the use of
+ * &quot;hand-over-hand&quot; or &quot;chain locking&quot;: you
+ * acquire the lock of node A, then node B, then release A and acquire
+ * C, then release B and acquire D and so on.  Implementations of the
+ * <tt>Lock</tt> interface enable the use of such techniques by
+ * allowing a lock to be acquired and released in different scopes,
+ * and allowing multiple locks to be acquired and released in any
+ * order.
+ *
+ * <p>With this increased flexibility comes additional
+ * responsibility. The absence of block-structured locking removes the
+ * automatic release of locks that occurs with <tt>synchronized</tt>
+ * methods and statements. In most cases, the following idiom
+ * should be used:
+ *
+ * <pre><tt>     Lock l = ...;
+ *     l.lock();
+ *     try {
+ *         // access the resource protected by this lock
+ *     } finally {
+ *         l.unlock();
+ *     }
+ * </tt></pre>
+ *
+ * When locking and unlocking occur in different scopes, care must be
+ * taken to ensure that all code that is executed while the lock is
+ * held is protected by try-finally or try-catch to ensure that the
+ * lock is released when necessary.
+ *
+ * <p><tt>Lock</tt> implementations provide additional functionality
+ * over the use of <tt>synchronized</tt> methods and statements by
+ * providing a non-blocking attempt to acquire a lock ({@link
+ * #tryLock()}), an attempt to acquire the lock that can be
+ * interrupted ({@link #lockInterruptibly}, and an attempt to acquire
+ * the lock that can timeout ({@link #tryLock(long, TimeUnit)}).
+ *
+ * <p>A <tt>Lock</tt> class can also provide behavior and semantics
+ * that is quite different from that of the implicit monitor lock,
+ * such as guaranteed ordering, non-reentrant usage, or deadlock
+ * detection. If an implementation provides such specialized semantics
+ * then the implementation must document those semantics.
+ *
+ * <p>Note that <tt>Lock</tt> instances are just normal objects and can
+ * themselves be used as the target in a <tt>synchronized</tt> statement.
+ * Acquiring the
+ * monitor lock of a <tt>Lock</tt> instance has no specified relationship
+ * with invoking any of the {@link #lock} methods of that instance.
+ * It is recommended that to avoid confusion you never use <tt>Lock</tt>
+ * instances in this way, except within their own implementation.
+ *
+ * <p>Except where noted, passing a <tt>null</tt> value for any
+ * parameter will result in a {@link NullPointerException} being
+ * thrown.
+ *
+ * <h3>Memory Synchronization</h3>
+ * <p>All <tt>Lock</tt> implementations <em>must</em> enforce the same
+ * memory synchronization semantics as provided by the built-in monitor
+ * lock, as described in <a href="http://java.sun.com/docs/books/jls/">
+ * The Java Language Specification, Third Edition (17.4 Memory Model)</a>:
+ * <ul>
+ * <li>A successful <tt>lock</tt> operation has the same memory
+ * synchronization effects as a successful <em>Lock</em> action.
+ * <li>A successful <tt>unlock</tt> operation has the same
+ * memory synchronization effects as a successful <em>Unlock</em> action.
+ * </ul>
+ *
+ * Unsuccessful locking and unlocking operations, and reentrant
+ * locking/unlocking operations, do not require any memory
+ * synchronization effects.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p> The three forms of lock acquisition (interruptible,
+ * non-interruptible, and timed) may differ in their performance
+ * characteristics, ordering guarantees, or other implementation
+ * qualities.  Further, the ability to interrupt the <em>ongoing</em>
+ * acquisition of a lock may not be available in a given <tt>Lock</tt>
+ * class.  Consequently, an implementation is not required to define
+ * exactly the same guarantees or semantics for all three forms of
+ * lock acquisition, nor is it required to support interruption of an
+ * ongoing lock acquisition.  An implementation is required to clearly
+ * document the semantics and guarantees provided by each of the
+ * locking methods. It must also obey the interruption semantics as
+ * defined in this interface, to the extent that interruption of lock
+ * acquisition is supported: which is either totally, or only on
+ * method entry.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action may have unblocked
+ * the thread. An implementation should document this behavior.
+ *
+ *
+ * @see ReentrantLock
+ * @see Condition
+ * @see ReadWriteLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ *
+ */
+public interface Lock {
+    /**
+     * Acquires the lock.
+     * <p>If the lock is not available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until the lock has been acquired.
+     * <p><b>Implementation Considerations</b>
+     * <p>A <tt>Lock</tt> implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would cause
+     * deadlock, and may throw an (unchecked) exception in such circumstances.
+     * The circumstances and the exception type must be documented by that
+     * <tt>Lock</tt> implementation.
+     */
+    void lock();
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@link Thread#interrupt interrupted}.
+     * <p>Acquires the lock if it is available and returns immediately.
+     * <p>If the lock is not available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of two things happens:
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@link Thread#interrupt interrupts} the current
+     * thread, and interruption of lock acquisition is supported.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@link Thread#interrupt interrupted} while acquiring
+     * the lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some
+     * implementations may not be possible, and if possible may be an
+     * expensive operation.  The programmer should be aware that this
+     * may be the case. An implementation should document when this is
+     * the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over
+     * normal method return.
+     *
+     * <p>A <tt>Lock</tt> implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would
+     * cause deadlock, and may throw an (unchecked) exception in such
+     * circumstances.  The circumstances and the exception type must
+     * be documented by that <tt>Lock</tt> implementation.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     * while acquiring the lock (and interruption of lock acquisition is
+     * supported).
+     *
+     * @see Thread#interrupt
+     */
+    void lockInterruptibly() throws InterruptedException;
+
+    /**
+     * Acquires the lock only if it is free at the time of invocation.
+     * <p>Acquires the lock if it is available and returns immediately
+     * with the value <tt>true</tt>.
+     * If the lock is not available then this method will return
+     * immediately with the value <tt>false</tt>.
+     * <p>A typical usage idiom for this method would be:
+     * <pre>
+     *      Lock lock = ...;
+     *      if (lock.tryLock()) {
+     *          try {
+     *              // manipulate protected state
+     *          } finally {
+     *              lock.unlock();
+     *          }
+     *      } else {
+     *          // perform alternative actions
+     *      }
+     * </pre>
+     * This usage ensures that the lock is unlocked if it was acquired, and
+     * doesn't try to unlock if the lock was not acquired.
+     *
+     * @return <tt>true</tt> if the lock was acquired and <tt>false</tt>
+     * otherwise.
+     */
+    boolean tryLock();
+
+    /**
+     * Acquires the lock if it is free within the given waiting time and the
+     * current thread has not been {@link Thread#interrupt interrupted}.
+     *
+     * <p>If the lock is available this method returns immediately
+     * with the value <tt>true</tt>.
+     * If the lock is not available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@link Thread#interrupt interrupts} the current
+     * thread, and interruption of lock acquisition is supported; or
+     * <li>The specified waiting time elapses
+     * </ul>
+     * <p>If the lock is acquired then the value <tt>true</tt> is returned.
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@link Thread#interrupt interrupted} while acquiring
+     * the lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * <p>If the specified waiting time elapses then the value <tt>false</tt>
+     * is returned.
+     * If the time is
+     * less than or equal to zero, the method will not wait at all.
+     *
+     * <p><b>Implementation Considerations</b>
+     * <p>The ability to interrupt a lock acquisition in some implementations
+     * may not be possible, and if possible may
+     * be an expensive operation.
+     * The programmer should be aware that this may be the case. An
+     * implementation should document when this is the case.
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return, or reporting a timeout.
+     * <p>A <tt>Lock</tt> implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would cause
+     * deadlock, and may throw an (unchecked) exception in such circumstances.
+     * The circumstances and the exception type must be documented by that
+     * <tt>Lock</tt> implementation.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the <tt>time</tt> argument.
+     * @return <tt>true</tt> if the lock was acquired and <tt>false</tt>
+     * if the waiting time elapsed before the lock was acquired.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     * while acquiring the lock (and interruption of lock acquisition is
+     * supported).
+     *
+     * @see Thread#interrupt
+     */
+    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Releases the lock.
+     * <p><b>Implementation Considerations</b>
+     * <p>A <tt>Lock</tt> implementation will usually impose
+     * restrictions on which thread can release a lock (typically only the
+     * holder of the lock can release it) and may throw
+     * an (unchecked) exception if the restriction is violated.
+     * Any restrictions and the exception
+     * type must be documented by that <tt>Lock</tt> implementation.
+     */
+    void unlock();
+
+    /**
+     * Returns a new {@link Condition} instance that is bound to this
+     * <tt>Lock</tt> instance.
+     * <p>Before waiting on the condition the lock must be held by the
+     * current thread.
+     * A call to {@link Condition#await()} will atomically release the lock
+     * before waiting and re-acquire the lock before the wait returns.
+     * <p><b>Implementation Considerations</b>
+     * <p>The exact operation of the {@link Condition} instance depends on the
+     * <tt>Lock</tt> implementation and must be documented by that
+     * implementation.
+     *
+     * @return A new {@link Condition} instance for this <tt>Lock</tt>
+     * instance.
+     * @throws UnsupportedOperationException if this <tt>Lock</tt>
+     * implementation does not support conditions.
+     */
+    Condition newCondition();
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/Lock.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/NanoTimer.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/NanoTimer.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/NanoTimer.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/NanoTimer.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * Written by Dawid Kurzyniec and released to the public domain, as explained
+ * at http://creativecommons.org/licenses/publicdomain
+ */
+package org.apache.openjpa.lib.util.concurrent;
+
+
+/**
+ * Interface to specify custom implementation of precise timer.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.0
+ */
+public interface NanoTimer {
+    /**
+     * Returns the current value of the most precise available system timer,
+     * in nanoseconds. This method can only be used to measure elapsed time and
+     * is not related to any other notion of system or wall-clock time. The
+     * value returned represents nanoseconds since some fixed but arbitrary
+     * time (perhaps in the future, so values may be negative). This method
+     * provides nanosecond precision, but not necessarily nanosecond accuracy.
+     * No guarantees are made about how frequently values change. Differences
+     * in successive calls that span greater than approximately 292 years
+     * (263 nanoseconds) will not accurately compute elapsed time due to
+     * numerical overflow.
+     *
+     * @return The current value of the system timer, in nanoseconds.
+     */
+    long nanoTime();
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/concurrent/NanoTimer.java
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message