Author: aadamchik
Date: Mon Aug 30 16:49:58 2010
New Revision: 990859

URL: http://svn.apache.org/viewvc?rev=990859&view=rev
Log:
CAY-1479 EntitySorter refactoring: make it DI-based, internalize Ashowood lib

* more generics cleanup
* removing synchronized blocks from AshwoodEntitySorter. It is using double 
check locking now instead

Modified:
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/IndegreeTopologicalSort.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/StrongConnection.java

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java?rev=990859&r1=990858&r2=990859&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java
 Mon Aug 30 16:49:58 2010
@@ -63,7 +63,6 @@ public class AshwoodEntitySorter impleme
 
     protected Collection<DataMap> dataMaps;
     protected Map<DbEntity, Table> dbEntityToTableMap;
-    protected Digraph<Collection<Table>, List<ForeignKey>> 
contractedReferentialDigraph;
     protected Map<Table, ComponentRecord> components;
     protected Map<DbEntity, List<DbRelationship>> reflexiveDbEntities;
 
@@ -71,8 +70,7 @@ public class AshwoodEntitySorter impleme
     protected DbEntityComparator dbEntityComparator;
     protected ObjEntityComparator objEntityComparator;
 
-    // used for lazy initialization
-    protected boolean dirty;
+    private volatile boolean dirty;
 
     public AshwoodEntitySorter() {
         tableComparator = new TableComparator();
@@ -88,12 +86,28 @@ public class AshwoodEntitySorter impleme
     }
 
     /**
-     * Reindexes internal sorter.
+     * Reindexes internal sorter in a thread-safe manner.
      */
-    protected synchronized void _indexSorter() {
-        if (!dirty) {
-            return;
+    protected void indexSorter() {
+
+        // correct double check locking per Joshua Bloch
+        // 
http://java.sun.com/developer/technicalArticles/Interviews/bloch_effective_08_qa.html
+        // (maybe we should use something like CountDownLatch or a Cyclic 
barrier
+        // instead?)
+
+        boolean localDirty = dirty;
+        if (localDirty) {
+            synchronized (this) {
+                localDirty = dirty;
+                if (localDirty) {
+                    doIndexSorter();
+                    dirty = false;
+                }
+            }
         }
+    }
+
+    private void doIndexSorter() {
 
         Collection<Table> tables = new ArrayList<Table>(64);
         dbEntityToTableMap = new HashMap<DbEntity, Table>(64);
@@ -112,15 +126,17 @@ public class AshwoodEntitySorter impleme
         Digraph<Table, List<ForeignKey>> referentialDigraph = new 
MapDigraph<Table, List<ForeignKey>>();
         DbUtils.buildReferentialDigraph(referentialDigraph, tables);
 
-        StrongConnection contractor = new StrongConnection(referentialDigraph);
+        StrongConnection<Table, List<ForeignKey>> contractor = new 
StrongConnection<Table, List<ForeignKey>>(
+                referentialDigraph);
 
-        contractedReferentialDigraph = new MapDigraph<Collection<Table>, 
List<ForeignKey>>();
+        Digraph<Collection<Table>, Collection<List<ForeignKey>>> 
contractedReferentialDigraph = new MapDigraph<Collection<Table>, 
Collection<List<ForeignKey>>>();
         contractor.contract(contractedReferentialDigraph);
 
-        IndegreeTopologicalSort<Collection<Table>, List<ForeignKey>> sorter = 
new IndegreeTopologicalSort<Collection<Table>, List<ForeignKey>>(
+        IndegreeTopologicalSort<Collection<Table>> sorter = new 
IndegreeTopologicalSort<Collection<Table>>(
                 contractedReferentialDigraph);
 
-        components = new HashMap(contractedReferentialDigraph.order());
+        components = new HashMap<Table, 
ComponentRecord>(contractedReferentialDigraph
+                .order());
         int componentIndex = 0;
         while (sorter.hasNext()) {
             Collection<Table> component = sorter.next();
@@ -130,36 +146,34 @@ public class AshwoodEntitySorter impleme
                 components.put(table, rec);
             }
         }
-
-        // clear dirty flag
-        this.dirty = false;
     }
 
     /**
      * @since 1.1
      */
-    public synchronized void setDataMaps(Collection<DataMap> dataMaps) {
-        this.dirty = true;
+    public void setDataMaps(Collection<DataMap> dataMaps) {
         this.dataMaps = dataMaps != null ? dataMaps : Collections.EMPTY_LIST;
+        this.dirty = true;
     }
 
     public void sortDbEntities(List<DbEntity> dbEntities, boolean deleteOrder) 
{
-        _indexSorter();
+        indexSorter();
         Collections.sort(dbEntities, getDbEntityComparator(deleteOrder));
     }
 
     public void sortObjEntities(List<ObjEntity> objEntities, boolean 
deleteOrder) {
-        _indexSorter();
+        indexSorter();
         Collections.sort(objEntities, getObjEntityComparator(deleteOrder));
     }
 
     public void sortObjectsForEntity(
             ObjEntity objEntity,
-            List objects,
+            List<?> objects,
             boolean deleteOrder) {
 
-        // don't forget to index the sorter
-        _indexSorter();
+        indexSorter();
+
+        List<Persistent> persistent = (List<Persistent>) objects;
 
         DbEntity dbEntity = objEntity.getDbEntity();
 
@@ -168,12 +182,13 @@ public class AshwoodEntitySorter impleme
             return;
         }
 
-        int size = objects.size();
+        int size = persistent.size();
         if (size == 0) {
             return;
         }
 
-        EntityResolver resolver = ((Persistent) objects.get(0))
+        EntityResolver resolver = persistent
+                .get(0)
                 .getObjectContext()
                 .getEntityResolver();
         ClassDescriptor descriptor = 
resolver.getClassDescriptor(objEntity.getName());
@@ -187,9 +202,9 @@ public class AshwoodEntitySorter impleme
             reflexiveRelNames[i] = (objRel != null ? objRel.getName() : null);
         }
 
-        List<Object> sorted = new ArrayList<Object>(size);
+        List<Persistent> sorted = new ArrayList<Persistent>(size);
 
-        Digraph objectDependencyGraph = new MapDigraph();
+        Digraph<Persistent, Boolean> objectDependencyGraph = new 
MapDigraph<Persistent, Boolean>();
         Object[] masters = new Object[reflexiveRelNames.length];
         for (int i = 0; i < size; i++) {
             Persistent current = (Persistent) objects.get(i);
@@ -224,7 +239,7 @@ public class AshwoodEntitySorter impleme
                     continue;
                 }
 
-                Object masterCandidate = objects.get(j);
+                Persistent masterCandidate = persistent.get(j);
                 for (Object master : masters) {
                     if (masterCandidate.equals(master)) {
                         objectDependencyGraph.putArc(
@@ -237,11 +252,11 @@ public class AshwoodEntitySorter impleme
             }
         }
 
-        IndegreeTopologicalSort sorter = new IndegreeTopologicalSort(
+        IndegreeTopologicalSort<Persistent> sorter = new 
IndegreeTopologicalSort<Persistent>(
                 objectDependencyGraph);
 
         while (sorter.hasNext()) {
-            Object o = sorter.next();
+            Persistent o = sorter.next();
             if (o == null)
                 throw new CayenneRuntimeException("Sorting objects for "
                         + objEntity.getClassName()
@@ -252,11 +267,11 @@ public class AshwoodEntitySorter impleme
         // since API requires sorting within the same array,
         // simply replace all objects with objects in the right order...
         // may come up with something cleaner later
-        objects.clear();
-        objects.addAll(sorted);
+        persistent.clear();
+        persistent.addAll(sorted);
 
         if (deleteOrder) {
-            Collections.reverse(objects);
+            Collections.reverse(persistent);
         }
     }
 
@@ -330,8 +345,8 @@ public class AshwoodEntitySorter impleme
         return (id != null) ? context.localObject(id, null) : null;
     }
 
-    protected Comparator getDbEntityComparator(boolean dependantFirst) {
-        Comparator c = dbEntityComparator;
+    protected Comparator<DbEntity> getDbEntityComparator(boolean 
dependantFirst) {
+        Comparator<DbEntity> c = dbEntityComparator;
         if (dependantFirst) {
             c = new ReverseComparator(c);
         }
@@ -392,8 +407,8 @@ public class AshwoodEntitySorter impleme
             else if (t2 == null)
                 result = 1;
             else {
-                ComponentRecord rec1 = (ComponentRecord) components.get(t1);
-                ComponentRecord rec2 = (ComponentRecord) components.get(t2);
+                ComponentRecord rec1 = components.get(t1);
+                ComponentRecord rec2 = components.get(t2);
                 int index1 = rec1.index;
                 int index2 = rec2.index;
                 result = (index1 > index2 ? 1 : (index1 < index2 ? -1 : 0));

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/IndegreeTopologicalSort.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/IndegreeTopologicalSort.java?rev=990859&r1=990858&r2=990859&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/IndegreeTopologicalSort.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/IndegreeTopologicalSort.java
 Mon Aug 30 16:49:58 2010
@@ -66,14 +66,14 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 
-public class IndegreeTopologicalSort<E, V> extends Algorithm<E> {
+public class IndegreeTopologicalSort<E> extends Algorithm<E> {
 
-    private Digraph<E, V> digraph;
+    private Digraph<E, ?> digraph;
     private List<E> vertices = new LinkedList<E>();
     private Map<E, InDegree> inDegrees = new HashMap<E, InDegree>();
     private ListIterator<E> current;
 
-    public IndegreeTopologicalSort(Digraph<E, V> digraph) {
+    public IndegreeTopologicalSort(Digraph<E, ?> digraph) {
         this.digraph = digraph;
         for (Iterator<E> i = digraph.vertexIterator(); i.hasNext();) {
             E vertex = i.next();
@@ -110,7 +110,7 @@ public class IndegreeTopologicalSort<E, 
     }
 
     private void removeVertex(E vertex) {
-        for (ArcIterator<E, V> i = digraph.outgoingIterator(vertex); 
i.hasNext();) {
+        for (ArcIterator<E, ?> i = digraph.outgoingIterator(vertex); 
i.hasNext();) {
             i.next();
             E dst = i.getDestination();
             InDegree indegree = inDegrees.get(dst);

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/StrongConnection.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/StrongConnection.java?rev=990859&r1=990858&r2=990859&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/StrongConnection.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ashwood/graph/StrongConnection.java
 Mon Aug 30 16:49:58 2010
@@ -65,7 +65,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -74,11 +73,11 @@ import org.apache.commons.collections.Co
 import org.apache.commons.collections.Predicate;
 import org.apache.commons.collections.functors.TruePredicate;
 
-public class StrongConnection<E> extends Algorithm<Collection<E>> {
+public class StrongConnection<E, V> extends Algorithm<Collection<E>> {
 
-    private DigraphIteration digraph;
-    private DigraphIteration reverseDigraph;
-    private DigraphIteration filteredDigraph;
+    private DigraphIteration<E, V> digraph;
+    private DigraphIteration<E, V> reverseDigraph;
+    private DigraphIteration<E, V> filteredDigraph;
     private DepthFirstStampSearch directDfs;
     private DepthFirstSearch reverseDfs;
     private Set seen = new HashSet();
@@ -86,7 +85,7 @@ public class StrongConnection<E> extends
     private ArrayStack dfsStack = new ArrayStack();
     private DFSSeenVerticesPredicate reverseDFSFilter = new 
DFSSeenVerticesPredicate();
 
-    public StrongConnection(DigraphIteration digraph) {
+    public StrongConnection(DigraphIteration<E, V> digraph) {
         this.digraph = digraph;
         filteredDigraph = new FilterIteration(
                 digraph,
@@ -100,10 +99,12 @@ public class StrongConnection<E> extends
         runDirectDFS();
     }
 
+    @Override
     public boolean hasNext() {
         return !dfsStack.isEmpty();
     }
 
+    @Override
     public Collection<E> next() {
         Collection component = buildStronglyConnectedComponent();
         if (dfsStack.isEmpty())
@@ -111,38 +112,41 @@ public class StrongConnection<E> extends
         return component;
     }
 
-    public Digraph contract(Digraph contractedDigraph) {
-        List components = new ArrayList();
+    public Digraph<Collection<E>, Collection<V>> 
contract(Digraph<Collection<E>, Collection<V>> contractedDigraph) {
+
+        Collection<Collection<E>> components = new ArrayList<Collection<E>>();
         CollectionUtils.addAll(components, this);
-        Map memberToComponent = new HashMap();
-        for (Iterator i = components.iterator(); i.hasNext();) {
-            Collection c = (Collection) i.next();
-            for (Iterator j = c.iterator(); j.hasNext();)
-                memberToComponent.put(j.next(), c);
+
+        Map<E, Collection<E>> memberToComponent = new HashMap<E, 
Collection<E>>();
+
+        for (Collection<E> c : components) {
+            for (E e : c) {
+                memberToComponent.put(e, c);
+            }
         }
-        for (Iterator i = components.iterator(); i.hasNext();) {
-            Collection origin = (Collection) i.next();
+
+        for (Collection<E> origin : components) {
+
             contractedDigraph.addVertex(origin);
-            for (Iterator j = origin.iterator(); j.hasNext();) {
-                Object member = j.next();
-                for (ArcIterator k = digraph.outgoingIterator(member); 
k.hasNext();) {
-                    Object arc = k.next();
-                    Object dst = k.getDestination();
+
+            for (E member : origin) {
+
+                for (ArcIterator<E, V> k = digraph.outgoingIterator(member); 
k.hasNext();) {
+                    V arc = k.next();
+                    E dst = k.getDestination();
                     if (origin.contains(dst))
                         continue;
-                    Collection destination = (Collection) 
memberToComponent.get(dst);
+                    Collection<E> destination = memberToComponent.get(dst);
 
-                    Collection contractedArc = (Collection) 
contractedDigraph.getArc(
-                            origin,
-                            destination);
+                    Collection<V> contractedArc = 
contractedDigraph.getArc(origin, destination);
                     if (contractedArc == null) {
                         contractedArc = Collections.singletonList(arc);
                         contractedDigraph.putArc(origin, destination, 
contractedArc);
                     }
                     else {
                         if (contractedArc.size() == 1) {
-                            Collection tmp = contractedArc;
-                            contractedArc = new ArrayList<E>();
+                            Collection<V> tmp = contractedArc;
+                            contractedArc = new ArrayList<V>();
                             contractedArc.addAll(tmp);
                             contractedDigraph.putArc(origin, destination, 
contractedArc);
                         }
@@ -156,10 +160,6 @@ public class StrongConnection<E> extends
     }
 
     private Object nextDFSRoot() {
-        /*
-         * while (vertexIterator.hasNext()) { Object vertex = 
vertexIterator.next(); if
-         * (!seen.contains(vertex)) return vertex; } return null;
-         */
         return (vertexIterator.hasNext() ? vertexIterator.next() : null);
     }
 


Reply via email to