cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ntimof...@apache.org
Subject [5/9] cayenne git commit: CAY-2351 Remove commons-collections usage completely own ReferenceMap implementation copy of CompositeCollection
Date Mon, 21 Aug 2017 09:29:18 GMT
CAY-2351 Remove commons-collections usage completely
  own ReferenceMap implementation
  copy of CompositeCollection


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/e70c5a51
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/e70c5a51
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/e70c5a51

Branch: refs/heads/master
Commit: e70c5a51174e63e4a36f83fb6aa877c3f85e0729
Parents: 10e0706
Author: Nikita Timofeev <stariy95@gmail.com>
Authored: Fri Aug 4 17:58:18 2017 +0300
Committer: Nikita Timofeev <stariy95@gmail.com>
Committed: Thu Aug 17 12:41:57 2017 +0300

----------------------------------------------------------------------
 .../access/DefaultObjectMapRetainStrategy.java  |  15 +-
 .../org/apache/cayenne/event/EventSubject.java  |   6 +-
 .../org/apache/cayenne/map/MappingCache.java    |  14 +-
 .../org/apache/cayenne/util/ReferenceMap.java   | 242 ++++++++++++++
 .../org/apache/cayenne/util/SoftValueMap.java   |  64 ++++
 .../org/apache/cayenne/util/WeakValueMap.java   |  63 ++++
 .../util/commons/CompositeCollection.java       | 328 +++++++++++++++++++
 .../cayenne/util/commons/IteratorChain.java     | 195 +++++++++++
 .../cayenne/wocompat/EOModelProcessor.java      |  45 +--
 9 files changed, 925 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
index 7fe338c..9e8213f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.access;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.cayenne.CayenneRuntimeException;
@@ -25,8 +26,8 @@ import org.apache.cayenne.Persistent;
 import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.configuration.RuntimeProperties;
 import org.apache.cayenne.di.Inject;
-import org.apache.commons.collections.map.AbstractReferenceMap;
-import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.cayenne.util.SoftValueMap;
+import org.apache.cayenne.util.WeakValueMap;
 
 /**
  * Default implementation of {@link ObjectMapRetainStrategy}.
@@ -45,17 +46,15 @@ public class DefaultObjectMapRetainStrategy implements ObjectMapRetainStrategy
{
         this.runtimeProperties = runtimeProperties;
     }
 
-    @SuppressWarnings("unchecked")
     public Map<Object, Persistent> createObjectMap() {
-        String strategy = runtimeProperties
-                .get(Constants.SERVER_OBJECT_RETAIN_STRATEGY_PROPERTY);
+        String strategy = runtimeProperties.get(Constants.SERVER_OBJECT_RETAIN_STRATEGY_PROPERTY);
 
         if (strategy == null || WEAK_RETAIN_STRATEGY.equals(strategy)) {
-            return new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
+            return new WeakValueMap<>();
         } else if (SOFT_RETAIN_STRATEGY.equals(strategy)) {
-            return new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT);
+            return new SoftValueMap<>();
         } else if (HARD_RETAIN_STRATEGY.equals(strategy)) {
-            return new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.HARD);
+            return new HashMap<>();
         } else {
             throw new CayenneRuntimeException("Unsupported retain strategy %s", strategy);
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/event/EventSubject.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/event/EventSubject.java b/cayenne-server/src/main/java/org/apache/cayenne/event/EventSubject.java
index 4122e12..fe90b58 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/event/EventSubject.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/event/EventSubject.java
@@ -23,7 +23,7 @@ import java.io.Serializable;
 import java.util.Map;
 
 import org.apache.cayenne.util.HashCodeBuilder;
-import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.cayenne.util.WeakValueMap;
 
 /**
  * This class encapsulates the String that is used to identify the <em>subject</em>
that
@@ -41,9 +41,7 @@ public class EventSubject implements Serializable {
 
     // a Map that will allow the values to be GC'ed
     @SuppressWarnings("unchecked")
-    private static Map<String, EventSubject> _registeredSubjects = new ReferenceMap(
-            ReferenceMap.HARD,
-            ReferenceMap.WEAK);
+    private static Map<String, EventSubject> _registeredSubjects = new WeakValueMap<>();
 
     // Subject identifier in the form "com.foo.bar/SubjectName"
     private String _fullyQualifiedSubjectName;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/map/MappingCache.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/MappingCache.java b/cayenne-server/src/main/java/org/apache/cayenne/map/MappingCache.java
index c8b2b2c..f5c0d12 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/MappingCache.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/MappingCache.java
@@ -26,7 +26,7 @@ import java.util.Map;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
-import org.apache.commons.collections.collection.CompositeCollection;
+import org.apache.cayenne.util.commons.CompositeCollection;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -206,7 +206,7 @@ class MappingCache implements MappingNamespace {
             return maps.iterator().next().getDbEntities();
         }
 
-        CompositeCollection c = new CompositeCollection();
+        CompositeCollection<DbEntity> c = new CompositeCollection<>();
         for (DataMap map : maps) {
             c.addComposited(map.getDbEntities());
         }
@@ -228,7 +228,7 @@ class MappingCache implements MappingNamespace {
             return maps.iterator().next().getProcedures();
         }
         
-        CompositeCollection c = new CompositeCollection();
+        CompositeCollection<Procedure> c = new CompositeCollection<>();
         for (DataMap map : maps) {
             c.addComposited(map.getProcedures());
         }
@@ -250,7 +250,7 @@ class MappingCache implements MappingNamespace {
             return maps.iterator().next().getQueryDescriptors();
         }
 
-        CompositeCollection c = new CompositeCollection();
+        CompositeCollection<QueryDescriptor> c = new CompositeCollection<>();
         for (DataMap map : maps) {
             c.addComposited(map.getQueryDescriptors());
         }
@@ -272,7 +272,7 @@ class MappingCache implements MappingNamespace {
             return maps.iterator().next().getObjEntities();
         }
         
-        CompositeCollection c = new CompositeCollection();
+        CompositeCollection<ObjEntity> c = new CompositeCollection<>();
         for (DataMap map : maps) {
             c.addComposited(map.getObjEntities());
         }
@@ -294,7 +294,7 @@ class MappingCache implements MappingNamespace {
             return maps.iterator().next().getEmbeddables();
         }
         
-        CompositeCollection c = new CompositeCollection();
+        CompositeCollection<Embeddable> c = new CompositeCollection<>();
         for (DataMap map : maps) {
             c.addComposited(map.getEmbeddables());
         }
@@ -317,7 +317,7 @@ class MappingCache implements MappingNamespace {
             return maps.iterator().next().getResults();
         }
         
-        CompositeCollection c = new CompositeCollection();
+        CompositeCollection<SQLResult> c = new CompositeCollection<>();
         for (DataMap map : maps) {
             c.addComposited(map.getResults());
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/util/ReferenceMap.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/ReferenceMap.java b/cayenne-server/src/main/java/org/apache/cayenne/util/ReferenceMap.java
new file mode 100644
index 0000000..e441f86
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/ReferenceMap.java
@@ -0,0 +1,242 @@
+/*****************************************************************
+ *   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.cayenne.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Map that transparently stores values as references and resolves them as needed.
+ * <p>
+ * This implementation supports serialization.
+ * <p>
+ * Internally data stored in HashMap thus this class and all implementations are not thread
safe.
+ *
+ * @see WeakValueMap
+ * @see SoftValueMap
+ *
+ * @since 4.1
+ */
+public abstract class ReferenceMap<K, V, R extends Reference<V>> implements Map<K,
V>, Serializable {
+
+    private static final long serialVersionUID = -3365744592038165092L;
+
+    protected transient Map<K, R> map;
+
+    protected transient Map<R, K> reverseMap;
+
+    protected transient ReferenceQueue<V> referenceQueue;
+
+    public ReferenceMap() {
+        map = new HashMap<>();
+        reverseMap = new HashMap<>();
+        referenceQueue = new ReferenceQueue<>();
+    }
+
+    public ReferenceMap(int initialCapacity) {
+        map = new HashMap<>(initialCapacity);
+        reverseMap = new HashMap<>(initialCapacity);
+        referenceQueue = new ReferenceQueue<>();
+    }
+
+    public ReferenceMap(Map<? extends K, ? extends V> m) {
+        this(m.size());
+        putAll(m);
+    }
+
+    @Override
+    public int size() {
+        checkReferenceQueue();
+        return map.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        checkReferenceQueue();
+        return map.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        checkReferenceQueue();
+        return map.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        checkReferenceQueue();
+        for(R ref : map.values()) {
+            if(ref != null) {
+                V v = ref.get();
+                if(v != null) {
+                    if(v.equals(value)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public V get(Object key) {
+        checkReferenceQueue();
+        R ref = map.get(key);
+        if(ref == null) {
+            return null;
+        }
+        return ref.get();
+    }
+
+    @Override
+    public V put(K key, V value) {
+        checkReferenceQueue();
+        R refValue = newReference(value);
+        R oldValue = map.put(key, refValue);
+        reverseMap.put(refValue, key);
+        if(oldValue == null) {
+            return null;
+        }
+        return oldValue.get();
+    }
+
+    @Override
+    public V remove(Object key) {
+        checkReferenceQueue();
+        R oldValue = map.remove(key);
+        if(oldValue == null) {
+            return null;
+        }
+        reverseMap.remove(oldValue);
+        return oldValue.get();
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+        checkReferenceQueue();
+        for(Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
+            R value = newReference(entry.getValue());
+            map.put(entry.getKey(), value);
+            reverseMap.put(value, entry.getKey());
+        }
+    }
+
+    @Override
+    public void clear() {
+        map.clear();
+        reverseMap.clear();
+        resetReferenceQueue();
+    }
+
+    @Override
+    public Set<K> keySet() {
+        checkReferenceQueue();
+        return map.keySet();
+    }
+
+    @Override
+    public Collection<V> values() {
+        checkReferenceQueue();
+        Collection<V> values = new ArrayList<>();
+        for(R v : map.values()) {
+            if(v != null) {
+                V value = v.get();
+                if(value != null) {
+                    values.add(value);
+                }
+            }
+        }
+        return values;
+    }
+
+    @Override
+    public Set<Entry<K, V>> entrySet() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Cleanup all collected references
+     */
+    protected void checkReferenceQueue() {
+        Reference<? extends V> reference;
+
+        while((reference = referenceQueue.poll()) != null) {
+            K keyToRemove = reverseMap.remove(reference);
+            if(keyToRemove != null) {
+                map.remove(keyToRemove);
+            }
+        }
+    }
+
+    private void resetReferenceQueue() {
+        while(referenceQueue.poll() != null) {
+            // just purge this queue
+        }
+    }
+
+    /**
+     * This method should be implemented by concrete implementations of this abstract class.
+     *
+     * @param value to be wrapped into reference
+     * @return new reference to the value
+     */
+    abstract R newReference(V value);
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeObjectInternal(out);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
+        readObjectInternal(in);
+    }
+
+    protected void writeObjectInternal(ObjectOutputStream out) throws IOException {
+        checkReferenceQueue();
+        Map<K, V> replacementMap = new HashMap<>();
+        for(Entry<K, R> entry : map.entrySet()) {
+            if(entry.getValue() != null) {
+                replacementMap.put(entry.getKey(), entry.getValue().get());
+            }
+        }
+        out.writeObject(replacementMap);
+    }
+
+    protected void readObjectInternal(ObjectInputStream in) throws IOException, ClassNotFoundException
{
+        @SuppressWarnings("unchecked")
+        Map<K, V> replacement = (Map<K, V>) in.readObject();
+        map = new HashMap<>(replacement.size());
+        reverseMap = new HashMap<>(replacement.size());
+        referenceQueue = new ReferenceQueue<>();
+        putAll(replacement);
+        map.forEach((k, v) -> {
+            reverseMap.put(v, k);
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/util/SoftValueMap.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/SoftValueMap.java b/cayenne-server/src/main/java/org/apache/cayenne/util/SoftValueMap.java
new file mode 100644
index 0000000..6955a56
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/SoftValueMap.java
@@ -0,0 +1,64 @@
+/*****************************************************************
+ *   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.cayenne.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.Map;
+
+/**
+ * Map that stores values wrapped into {@link WeakReference}
+ *
+ * @since 4.1
+ */
+public class SoftValueMap<K, V> extends ReferenceMap<K, V, SoftReference<V>>
implements Serializable {
+
+    private static final long serialVersionUID = 8146103761927411986L;
+
+    public SoftValueMap() {
+        super();
+    }
+
+    public SoftValueMap(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    public SoftValueMap(Map<? extends K, ? extends V> m) {
+        super(m);
+    }
+
+    @Override
+    SoftReference<V> newReference(V value) {
+        return new SoftReference<>(value, referenceQueue);
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeObjectInternal(out);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
+        readObjectInternal(in);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/util/WeakValueMap.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/WeakValueMap.java b/cayenne-server/src/main/java/org/apache/cayenne/util/WeakValueMap.java
new file mode 100644
index 0000000..76a1610
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/WeakValueMap.java
@@ -0,0 +1,63 @@
+/*****************************************************************
+ *   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.cayenne.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.Map;
+
+/**
+ * Map that stores values wrapped into {@link WeakReference}
+ *
+ * @since 4.1
+ */
+public class WeakValueMap<K, V> extends ReferenceMap<K, V, WeakReference<V>>
implements Serializable {
+
+    private static final long serialVersionUID = -6911881597843322446L;
+
+    public WeakValueMap() {
+        super();
+    }
+
+    public WeakValueMap(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    public WeakValueMap(Map<? extends K, ? extends V> m) {
+        super(m);
+    }
+
+    @Override
+    WeakReference<V> newReference(V value) {
+        return new WeakReference<>(value, referenceQueue);
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeObjectInternal(out);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
+        readObjectInternal(in);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/util/commons/CompositeCollection.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/commons/CompositeCollection.java
b/cayenne-server/src/main/java/org/apache/cayenne/util/commons/CompositeCollection.java
new file mode 100644
index 0000000..6b5fb36
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/commons/CompositeCollection.java
@@ -0,0 +1,328 @@
+/*****************************************************************
+ *   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.cayenne.util.commons;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * Decorates a collection of other collections to provide a single unified view.
+ * <p>
+ * Changes made to this collection will actually be made on the decorated collection.
+ * Add and remove operations require the use of a pluggable strategy. If no
+ * strategy is provided then add and remove are unsupported.
+ *
+ * @author Brian McCallister
+ * @author Stephen Colebourne
+ * @author Phil Steitz
+ *
+ * @since 4.1
+ *
+ * NOTE: this is a simplified and type-safe version of CompositeCollection found in commons-collections
v3.2.1
+ */
+public class CompositeCollection<E> implements Collection<E> {
+
+    /** Collections in the composite */
+    protected ArrayList<Collection<E>> all;
+
+    /**
+     * Create an empty CompositeCollection.
+     */
+    public CompositeCollection() {
+        super();
+        this.all = new ArrayList<>();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the size of this composite collection.
+     * <p>
+     * This implementation calls <code>size()</code> on each collection.
+     *
+     * @return total number of elements in all contained containers
+     */
+    @Override
+    public int size() {
+        int size = 0;
+        for(Collection<E> collection : this.all) {
+            size += collection.size();
+        }
+        return size;
+    }
+
+    /**
+     * Checks whether this composite collection is empty.
+     * <p>
+     * This implementation calls <code>isEmpty()</code> on each collection.
+     *
+     * @return true if all of the contained collections are empty
+     */
+    @Override
+    public boolean isEmpty() {
+        for(Collection<E> collection : this.all) {
+            if(!collection.isEmpty()){
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks whether this composite collection contains the object.
+     * <p>
+     * This implementation calls <code>contains()</code> on each collection.
+     *
+     * @param obj  the object to search for
+     * @return true if obj is contained in any of the contained collections
+     */
+    @Override
+    public boolean contains(Object obj) {
+        for(Collection<E> collection : this.all) {
+            if(!collection.contains(obj)){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Gets an iterator over all the collections in this composite.
+     * <p>
+     * This implementation uses an <code>IteratorChain</code>.
+     *
+     * @return an <code>IteratorChain</code> instance which supports
+     *  <code>remove()</code>. Iteration occurs over contained collections in
+     *  the order they were added, but this behavior should not be relied upon.
+     * @see IteratorChain
+     */
+    @Override
+    public Iterator<E> iterator() {
+        if (this.all.isEmpty()) {
+            return Collections.emptyIterator();
+        }
+        IteratorChain<E> chain = new IteratorChain<>();
+        for (Collection<E> collection : this.all) {
+            chain.addIterator(collection.iterator());
+        }
+        return chain;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this composite.
+     *
+     * @return an object array of all the elements in the collection
+     */
+    @Override
+    public Object[] toArray() {
+        final Object[] result = new Object[this.size()];
+        int i = 0;
+        for (Collection<E> collection : this.all) {
+            for(E o : collection) {
+                result[i++] = o;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns an object array, populating the supplied array if possible.
+     * See <code>Collection</code> interface for full details.
+     *
+     * @param array  the array to use, populating if possible
+     * @return an array of all the elements in the collection
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T[] toArray(T[] array) {
+        int size = this.size();
+        Object[] result;
+        if (array.length >= size) {
+            result = array;
+        } else {
+            result = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
+        }
+
+        int offset = 0;
+        for (Collection<E> collection : this.all) {
+            for (E e : collection) {
+                result[offset++] = e;
+            }
+        }
+        if (result.length > size) {
+            result[size] = null;
+        }
+        return (T[])result;
+    }
+
+    /**
+     * Adds an object to the collection, throwing UnsupportedOperationException
+     * unless a CollectionMutator strategy is specified.
+     *
+     * @param obj  the object to add
+     * @return true if the collection was modified
+     * @throws UnsupportedOperationException if CollectionMutator hasn't been set
+     * @throws UnsupportedOperationException if add is unsupported
+     * @throws ClassCastException if the object cannot be added due to its type
+     * @throws NullPointerException if the object cannot be added because its null
+     * @throws IllegalArgumentException if the object cannot be added
+     */
+    @Override
+    public boolean add(Object obj) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Removes an object from the collection, throwing UnsupportedOperationException
+     * unless a CollectionMutator strategy is specified.
+     *
+     * @param obj  the object being removed
+     * @return true if the collection is changed
+     * @throws UnsupportedOperationException if removed is unsupported
+     * @throws ClassCastException if the object cannot be removed due to its type
+     * @throws NullPointerException if the object cannot be removed because its null
+     * @throws IllegalArgumentException if the object cannot be removed
+     */
+    @Override
+    public boolean remove(Object obj) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Checks whether this composite contains all the elements in the specified collection.
+     * <p>
+     * This implementation calls <code>contains()</code> for each element in
the
+     * specified collection.
+     *
+     * @param coll  the collection to check for
+     * @return true if all elements contained
+     */
+    @Override
+    public boolean containsAll(Collection<?> coll) {
+        for (Object o : coll) {
+            if (!this.contains(o)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Adds a collection of elements to this collection, throwing
+     * UnsupportedOperationException unless a CollectionMutator strategy is specified.
+     *
+     * @param coll  the collection to add
+     * @return true if the collection was modified
+     * @throws UnsupportedOperationException if CollectionMutator hasn't been set
+     * @throws UnsupportedOperationException if add is unsupported
+     * @throws ClassCastException if the object cannot be added due to its type
+     * @throws NullPointerException if the object cannot be added because its null
+     * @throws IllegalArgumentException if the object cannot be added
+     */
+    @Override
+    public boolean addAll(Collection<? extends E> coll) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Removes the elements in the specified collection from this composite collection.
+     * <p>
+     * This implementation calls <code>removeAll</code> on each collection.
+     *
+     * @param coll  the collection to remove
+     * @return true if the collection was modified
+     * @throws UnsupportedOperationException if removeAll is unsupported
+     */
+    @Override
+    public boolean removeAll(Collection<?> coll) {
+        if (coll.size() == 0) {
+            return false;
+        }
+        boolean changed = false;
+        for(Collection<E> collection : this.all) {
+            changed = (collection.removeAll(coll) || changed);
+        }
+        return changed;
+    }
+
+    /**
+     * Retains all the elements in the specified collection in this composite collection,
+     * removing all others.
+     * <p>
+     * This implementation calls <code>retainAll()</code> on each collection.
+     *
+     * @param coll  the collection to remove
+     * @return true if the collection was modified
+     * @throws UnsupportedOperationException if retainAll is unsupported
+     */
+    @Override
+    public boolean retainAll(final Collection<?> coll) {
+        boolean changed = false;
+        for(Collection<E> collection : this.all) {
+            changed = (collection.retainAll(coll) || changed);
+        }
+        return changed;
+    }
+
+    /**
+     * Removes all of the elements from this collection .
+     * <p>
+     * This implementation calls <code>clear()</code> on each collection.
+     *
+     * @throws UnsupportedOperationException if clear is unsupported
+     */
+    @Override
+    public void clear() {
+        for (Collection<E> collection : this.all) {
+            collection.clear();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Add an additional collection to this composite.
+     *
+     * @param c  the collection to add
+     */
+    public void addComposited(Collection<E> c) {
+        all.add(c);
+    }
+
+    /**
+     * Removes a collection from the those being decorated in this composite.
+     *
+     * @param coll  collection to be removed
+     */
+    public void removeComposited(Collection<E> coll) {
+        all.remove(coll);
+    }
+
+    /**
+     * Gets the collections being decorated.
+     *
+     * @return Unmodifiable collection of all collections in this composite.
+     */
+    public Collection<Collection<E>> getCollections() {
+        return Collections.unmodifiableCollection(this.all);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/cayenne-server/src/main/java/org/apache/cayenne/util/commons/IteratorChain.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/commons/IteratorChain.java
b/cayenne-server/src/main/java/org/apache/cayenne/util/commons/IteratorChain.java
new file mode 100644
index 0000000..05b1f2e
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/commons/IteratorChain.java
@@ -0,0 +1,195 @@
+/*
+ *  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.cayenne.util.commons;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * An IteratorChain is an Iterator that wraps a number of Iterators.
+ * <p>
+ * This class makes multiple iterators look like one to the caller
+ * When any method from the Iterator interface is called, the IteratorChain
+ * will delegate to a single underlying Iterator. The IteratorChain will
+ * invoke the Iterators in sequence until all Iterators are exhausted.
+ * <p>
+ * Under many circumstances, linking Iterators together in this manner is
+ * more efficient (and convenient) than reading out the contents of each
+ * Iterator into a List and creating a new Iterator.
+ * <p>
+ * Calling a method that adds new Iterator<i>after a method in the Iterator
+ * interface has been called</i> will result in an UnsupportedOperationException.
+ * Subclasses should <i>take care</i> to not alter the underlying List of Iterators.
+ * <p>
+ *
+ * @since 4.1
+ *
+ * @author Morgan Delagrange
+ * @author Stephen Colebourne
+ *
+ * NOTE: this is a simplified version of ItertatorChain class found in commons-collections
v3.2.1
+ * used only by {@link CompositeCollection}.
+ */
+class IteratorChain<E> implements Iterator<E> {
+
+    /** The chain of iterators */
+    protected final List<Iterator<E>> iteratorChain = new ArrayList<>();
+    /** The index of the current iterator */
+    protected int currentIteratorIndex = 0;
+    /** The current iterator */
+    protected Iterator<E> currentIterator = null;
+    /**
+     * The "last used" Iterator is the Iterator upon which
+     * next() or hasNext() was most recently called
+     * used for the remove() operation only
+     */
+    protected Iterator<E> lastUsedIterator = null;
+    /**
+     * ComparatorChain is "locked" after the first time
+     * compare(Object,Object) is called
+     */
+    protected boolean isLocked = false;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Construct an IteratorChain with no Iterators.
+     * <p>
+     * You will normally use {@link #addIterator(Iterator)} to add
+     * some iterators after using this constructor.
+     */
+    public IteratorChain() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Add an Iterator to the end of the chain
+     *
+     * @param iterator Iterator to add
+     * @throws IllegalStateException if I've already started iterating
+     * @throws NullPointerException if the iterator is null
+     */
+    public void addIterator(Iterator<E> iterator) {
+        checkLocked();
+        iteratorChain.add(Objects.requireNonNull(iterator));
+    }
+
+    /**
+     * Number of Iterators in the current IteratorChain.
+     *
+     * @return Iterator count
+     */
+    public int size() {
+        return iteratorChain.size();
+    }
+
+    /**
+     * Checks whether the iterator chain is now locked and in use.
+     */
+    private void checkLocked() {
+        if (isLocked) {
+            throw new UnsupportedOperationException("IteratorChain cannot be changed after
the first use of a method from the Iterator interface");
+        }
+    }
+
+    /**
+     * Lock the chain so no more iterators can be added.
+     * This must be called from all Iterator interface methods.
+     */
+    private void lockChain() {
+        if (!isLocked) {
+            isLocked = true;
+        }
+    }
+
+    /**
+     * Updates the current iterator field to ensure that the current Iterator
+     * is not exhausted
+     */
+    protected void updateCurrentIterator() {
+        if (currentIterator == null) {
+            if (iteratorChain.isEmpty()) {
+                currentIterator = Collections.emptyIterator();
+            } else {
+                currentIterator = iteratorChain.get(0);
+            }
+            // set last used iterator here, in case the user calls remove
+            // before calling hasNext() or next() (although they shouldn't)
+            lastUsedIterator = currentIterator;
+        }
+
+        while (!currentIterator.hasNext() && currentIteratorIndex < iteratorChain.size()
- 1) {
+            currentIteratorIndex++;
+            currentIterator = iteratorChain.get(currentIteratorIndex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Return true if any Iterator in the IteratorChain has a remaining element.
+     *
+     * @return true if elements remain
+     */
+    public boolean hasNext() {
+        lockChain();
+        updateCurrentIterator();
+        lastUsedIterator = currentIterator;
+
+        return currentIterator.hasNext();
+    }
+
+    /**
+     * Returns the next Object of the current Iterator
+     *
+     * @return Object from the current Iterator
+     * @throws java.util.NoSuchElementException if all the Iterators are exhausted
+     */
+    public E next() {
+        lockChain();
+        updateCurrentIterator();
+        lastUsedIterator = currentIterator;
+
+        return currentIterator.next();
+    }
+
+    /**
+     * Removes from the underlying collection the last element
+     * returned by the Iterator.  As with next() and hasNext(),
+     * this method calls remove() on the underlying Iterator.
+     * Therefore, this method may throw an
+     * UnsupportedOperationException if the underlying
+     * Iterator does not support this method.
+     *
+     * @throws UnsupportedOperationException
+     *   if the remove operator is not supported by the underlying Iterator
+     * @throws IllegalStateException
+     *   if the next method has not yet been called, or the remove method has
+     *   already been called after the last call to the next method.
+     */
+    public void remove() {
+        lockChain();
+        if (currentIterator == null) {
+            updateCurrentIterator();
+        }
+        lastUsedIterator.remove();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e70c5a51/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
index d320559..ac2e9f0 100644
--- a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
+++ b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java
@@ -35,9 +35,6 @@ import org.apache.cayenne.query.Ordering;
 import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.wocompat.parser.Parser;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.Predicate;
-import org.apache.commons.collections.PredicateUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,6 +51,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * Class for converting stored Apple EOModel mapping files to Cayenne DataMaps.
@@ -62,21 +61,15 @@ public class EOModelProcessor {
 
 	private static final Logger logger = LoggerFactory.getLogger(EOModelProcessor.class);
 
-	protected Predicate prototypeChecker;
+	protected Predicate<String> prototypeChecker;
 
 	public EOModelProcessor() {
-		prototypeChecker = new Predicate() {
-
-			@Override
-			public boolean evaluate(Object object) {
-				if (object == null) {
-					return false;
-				}
-
-				String entityName = object.toString();
-				return entityName.startsWith("EO") && entityName.endsWith("Prototypes");
-			}
-		};
+		prototypeChecker = entityName -> {
+            if (entityName == null) {
+                return false;
+            }
+            return entityName.startsWith("EO") && entityName.endsWith("Prototypes");
+        };
 	}
 
 	/**
@@ -154,24 +147,20 @@ public class EOModelProcessor {
 		DataMap dataMap = helper.getDataMap();
 
 		// process enitities ... throw out prototypes ... for now
-		List modelNames = new ArrayList(helper.modelNamesAsList());
-		CollectionUtils.filter(modelNames, PredicateUtils.notPredicate(prototypeChecker));
-
-		Iterator it = modelNames.iterator();
-		while (it.hasNext()) {
-			String name = (String) it.next();
-
+		List<String> modelNames = new ArrayList<>(helper.modelNamesAsList());
+		modelNames = modelNames.stream().filter(prototypeChecker.negate()).collect(Collectors.toList());
+		modelNames.forEach( name -> {
 			// create and register entity
 			makeEntity(helper, name, generateClientClass);
-		}
+		});
 
 		// now sort following inheritance hierarchy
-		Collections.sort(modelNames, new InheritanceComparator(dataMap));
+		modelNames.sort(new InheritanceComparator(dataMap));
 
 		// after all entities are loaded, process attributes
-		it = modelNames.iterator();
+		Iterator<String> it = modelNames.iterator();
 		while (it.hasNext()) {
-			String name = (String) it.next();
+			String name = it.next();
 
 			EOObjEntity e = (EOObjEntity) dataMap.getObjEntity(name);
 			// process entity attributes
@@ -228,7 +217,7 @@ public class EOModelProcessor {
 	 * @since 1.1
 	 */
 	protected boolean isPrototypesEntity(String entityName) {
-		return prototypeChecker.evaluate(entityName);
+		return prototypeChecker.test(entityName);
 	}
 
 	/**


Mime
View raw message