Revision: 17177
          http://sourceforge.net/p/gate/code/17177
Author:   markagreenwood
Date:     2013-12-18 10:24:36 +0000 (Wed, 18 Dec 2013)
Log Message:
-----------
more work on wiring in the listeners for changes to the annotation sets; now 
when you delete an annotation (or relation) relations which contain them are 
deleted to maintain consistency (this is a recursive operation so relations 
referencing relations etc. get handled properly). Also the internal data 
structures of the relation set are now much simpler and smaller

Modified Paths:
--------------
    gate/trunk/src/main/gate/relations/RelationSet.java

Modified: gate/trunk/src/main/gate/relations/RelationSet.java
===================================================================
--- gate/trunk/src/main/gate/relations/RelationSet.java 2013-12-18 04:10:22 UTC 
(rev 17176)
+++ gate/trunk/src/main/gate/relations/RelationSet.java 2013-12-18 10:24:36 UTC 
(rev 17177)
@@ -27,14 +27,13 @@
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 import java.util.regex.Matcher;
 
-import org.apache.log4j.Logger;
-
 /**
  * Utility class for managing a set of GATE relations (usually each
  * annotation set of a document will have one set of associated
@@ -44,8 +43,6 @@
 
   private static final long serialVersionUID = 8552798130184595465L;
 
-  private static final Logger log = Logger.getLogger(RelationSet.class);
-
   /**
    * Annotation ID used when calling {@link #getRelations(int...)} for
    * positions with no restrictions.
@@ -53,11 +50,6 @@
   public static final int ANY = -1;
 
   /**
-   * The list of all relations.
-   */
-  protected List<Relation> relations;
-
-  /**
    * Index for relations by type.
    */
   protected Map<String, BitSet> indexByType;
@@ -68,12 +60,6 @@
   protected Map<Integer, Relation> indexById;
 
   /**
-   * Keeps the indexes (in {@link #relations}) for relations that have
-   * been deleted.
-   */
-  protected BitSet deleted;
-
-  /**
    * Indexes for relations by member. Each element in the list refers to
    * a given position in the members array: the element at position zero
    * refers to the first member of all relations.
@@ -88,23 +74,37 @@
 
   /**
    * The {@link AnnotationSet} this set of relations relates to. The
-   * assumption (which is not currently enforced) is that all members of
-   * this RelationSet will be either {@link Annotation} instances from
-   * this {@link AnnotationSet} or other {@link Relation} instances
-   * within this set.
+   * assumption (which is actively enforced) is that all members of this
+   * RelationSet will be either {@link Annotation} instances from this
+   * {@link AnnotationSet} or other {@link Relation} instances within
+   * this set.
    */
   protected AnnotationSet annSet;
 
   private Vector<RelationSetListener> listeners = null;
 
+  /**
+   * The max ID of any relation within this set which is needed for some
+   * of the index access operations
+   */
   private int maxID = 0;
 
+  /**
+   * The {@link AnnotationSet} which this instance belongs to.
+   * 
+   * @return the AnnotationSet which this instance belongs to.
+   */
   public AnnotationSet getAnnotationSet() {
     return annSet;
   }
 
+  /**
+   * An unmodifiable view of the contents of this RelationSet.
+   * 
+   * @return an unmodifiable view of the contents of this RelationSet.
+   */
   public Collection<Relation> get() {
-    return indexById.values();
+    return Collections.unmodifiableCollection(indexById.values());
   }
 
   /**
@@ -113,11 +113,9 @@
    */
   public RelationSet(AnnotationSet annSet) {
     this.annSet = annSet;
-    relations = new ArrayList<Relation>();
     indexByType = new HashMap<String, BitSet>();
     indexesByMember = new ArrayList<Map<Integer, BitSet>>();
     indexById = new HashMap<Integer, Relation>();
-    deleted = new BitSet();
 
     annSet.addAnnotationSetListener(this);
   }
@@ -126,11 +124,9 @@
    * Empties the relation set
    */
   public void clear() {
-    relations.clear();
     indexByType.clear();
     indexesByMember.clear();
     indexById.clear();
-    deleted.clear();
   }
 
   /**
@@ -139,9 +135,6 @@
    * @return the number of relations in this set.
    */
   public int size() {
-    // return the size of the by ID index as this is the only place that
-    // actually tracks the size accurately once a relation has been
-    // deleted from the set
     return indexById.size();
   }
 
@@ -157,8 +150,9 @@
   public Relation addRelation(String type, int... members)
           throws IllegalArgumentException {
 
-    if(members.length == 0)
-      throw new IllegalArgumentException("A relation can't have zero members");
+    if(members.length < 2)
+      throw new IllegalArgumentException(
+              "A relation needs to have atleast two members");
 
     for(int member : members) {
       if(!indexById.containsKey(member) && annSet.get(member) == null)
@@ -166,11 +160,19 @@
                 "Member must be from within this annotation set");
     }
 
+    if(type == null || type.trim().equals(""))
+      throw new IllegalArgumentException("A relation must have a type");
+
+    // now we have sanity checked the params create the relation
     Relation rel =
             new SimpleRelation(
                     ((DocumentImpl)annSet.getDocument()).getNextAnnotationId(),
                     type, members);
+
+    // add the relation to the set
     addRelation(rel);
+
+    // return the relation to the calling method
     return rel;
   }
 
@@ -180,11 +182,10 @@
    * @param rel the {@link Relation} to be added.
    */
   public void addRelation(Relation rel) {
+
+    // keep a track of the max ID we now of to support the index access
     maxID = Math.max(maxID, rel.getId());
 
-    int relIdx = relations.size();
-    relations.add(rel);
-
     /** index by ID **/
     indexById.put(rel.getId(), rel);
 
@@ -196,6 +197,7 @@
     }
     sameType.set(rel.getId());
 
+    /** index by member **/
     // widen the index by member list, if needed
     for(int i = indexesByMember.size(); i < rel.getMembers().length; i++) {
       indexesByMember.add(new HashMap<Integer, BitSet>());
@@ -206,12 +208,13 @@
       Map<Integer, BitSet> indexByMember = indexesByMember.get(memeberPos);
       BitSet sameMember = indexByMember.get(member);
       if(sameMember == null) {
-        sameMember = new BitSet(relations.size());
+        sameMember = new BitSet(maxID);
         indexByMember.put(member, sameMember);
       }
-      sameMember.set(relIdx);
+      sameMember.set(rel.getId());
     }
 
+    // notify anyone who cares that a new relation has been added
     fireRelationAdded(new RelationSetEvent(this,
             RelationSetEvent.RELATION_ADDED, rel));
   }
@@ -237,7 +240,7 @@
     List<Relation> res = new ArrayList<Relation>();
     BitSet rels = indexByType.get(type);
     if(rels != null) {
-      for(int relPos = 0; relPos < maxID; relPos++) {
+      for(int relPos = 0; relPos <= maxID; relPos++) {
         if(rels.get(relPos)) res.add(indexById.get(relPos));
       }
     }
@@ -259,28 +262,26 @@
    */
   public List<Relation> getRelations(int... members) {
     // get the lists of relations for each member
-    BitSet[] postingLists = new BitSet[indexesByMember.size()];
-    for(int i = 0; i < postingLists.length; i++) {
-      if(i < members.length && members[i] >= 0) {
-        postingLists[i] = indexesByMember.get(i).get(members[i]);
-      } else {
-        postingLists[i] = null;
-      }
-    }
-    return intersection(postingLists);
+    return getRelations(null, members);
   }
 
   public List<Relation> getRelations(String type, int... members) {
     // get the lists of relations for each member
-    BitSet[] postingLists = new BitSet[indexesByMember.size() + 1];
+    BitSet[] postingLists =
+            new BitSet[getMaximumArity() + (type != null ? 1 : 0)];
     for(int i = 0; i < postingLists.length; i++) {
       if(i < members.length && members[i] >= 0) {
         postingLists[i] = indexesByMember.get(i).get(members[i]);
       } else {
         postingLists[i] = null;
       }
+
     }
-    postingLists[postingLists.length - 1] = indexByType.get(type);
+
+    if(type != null) {
+      postingLists[postingLists.length - 1] = indexByType.get(type);
+    }
+
     return intersection(postingLists);
   }
 
@@ -292,45 +293,100 @@
    *         <code>false</code> if it was not found.
    */
   public boolean deleteRelation(Relation relation) {
-    int relIdx = relations.indexOf(relation);
-    if(relIdx >= 0) {
 
-      // delete this relation from the type index
-      indexByType.get(relation.getType()).clear(relation.getId());
+    if(!indexById.containsValue(relation)) return false;
 
-      deleted.set(relIdx);
-      relations.set(relIdx, null);
-      indexById.remove(relation.getId());
-      fireRelationRemoved(new RelationSetEvent(this,
-              RelationSetEvent.RELATION_REMOVED, relation));
-      return true;
-    } else {
-      return false;
+    // find all relations which include the annotation and remove them
+    for(Relation r : getReferencing(relation.getId())) {
+      deleteRelation(r);
     }
+
+    // delete this relation from the type index
+    indexByType.get(relation.getType()).clear(relation.getId());
+
+    // delete this relation from the ID index
+    indexById.remove(relation.getId());
+
+    // delete from the member index
+    for(int memeberPos = 0; memeberPos < relation.getMembers().length; 
memeberPos++) {
+      int member = relation.getMembers()[memeberPos];
+
+      Map<Integer, BitSet> indexByMember = indexesByMember.get(memeberPos);
+      BitSet sameMember = indexByMember.get(member);
+      if(sameMember == null) {
+        sameMember = new BitSet(maxID);
+        indexByMember.put(member, sameMember);
+      }
+      sameMember.clear(relation.getId());
+    }
+
+    // TODO find any other relations that referenced this one and delete
+    // those as well
+
+    // notify anyone who cares enough to listen that we have deleted a
+    // relation
+    fireRelationRemoved(new RelationSetEvent(this,
+            RelationSetEvent.RELATION_REMOVED, relation));
+    return true;
+
   }
 
   /**
+   * Returns a list of all {@link Relation} instances within this set
+   * which include the specified {@link Annotaiton} or {@link Relation}
+   * 
+   * @param id the ID of the {@link Annotation} or {@link Relation} to
+   *          look for
+   * @return a list of all {@link Relation} instances within this set
+   *         which include the specified id
+   */
+  public List<Relation> getReferencing(int id) {
+
+    List<Relation> relations = new ArrayList<Relation>();
+    for(int pos = 0; pos < getMaximumArity(); pos++) {
+      int[] constraint = new int[pos + 1];
+      for(int i = 0; i < pos; i++)
+        constraint[i] = RelationSet.ANY;
+      constraint[pos] = id;
+      relations.addAll(getRelations(null, constraint));
+    }
+
+    return relations;
+  }
+
+  /**
    * Calculates the intersection of a set of lists containing relation
-   * indexes.
+   * IDs
    * 
    * @param indexLists the list to be intersected.
    * @return the list of relations contained in all the supplied index
    *         lists.
    */
   protected List<Relation> intersection(BitSet... indexLists) {
-    BitSet relIds = new BitSet(relations.size());
-    relIds.set(0, relations.size() - 1);
-    relIds.andNot(deleted);
+
+    List<Relation> res = new ArrayList<Relation>();
+
+    BitSet relIds = new BitSet(maxID + 1);
+    relIds.set(0, maxID + 1);
+
+    boolean found = false;
+
     for(BitSet aList : indexLists) {
       if(aList != null) {
+        found = true;
         relIds.and(aList);
-        if(relIds.isEmpty()) break;
+
+        // if there is no intersection then return the empty list
+        if(relIds.isEmpty()) return res;
       }
     }
 
-    List<Relation> res = new ArrayList<Relation>();
-    for(int relIdx = 0; relIdx < relations.size(); relIdx++) {
-      if(relIds.get(relIdx)) res.add(relations.get(relIdx));
+    if(!found) return res;
+
+    for(int relIdx = 0; relIdx < (maxID + 1); relIdx++) {
+      if(relIds.get(relIdx)) {
+        res.add(indexById.get(relIdx));
+      }
     }
     return res;
   }
@@ -342,23 +398,23 @@
    */
   @Override
   public String toString() {
+
     StringBuilder str = new StringBuilder();
     str.append("[");
     boolean first = true;
-    for(int i = 0; i < relations.size(); i++) {
-      if(!deleted.get(i)) {
-        if(first) {
-          first = false;
-        } else {
-          str.append("; ");
-        }
-        String relStr = relations.get(i).toString();
-        relStr = relStr.replaceAll(";", Matcher.quoteReplacement("\\;"));
-        if(!relations.get(i).getClass().equals(SimpleRelation.class)) {
-          relStr = "(" + relations.get(i).getClass().getName() + ")" + relStr;
-        }
-        str.append(relStr);
+    for(Relation r : indexById.values()) {
+      if(first) {
+        first = false;
+      } else {
+        str.append("; ");
       }
+      String relStr = r.toString();
+      relStr = relStr.replaceAll(";", Matcher.quoteReplacement("\\;"));
+      if(!r.getClass().equals(SimpleRelation.class)) {
+        relStr = "(" + r.getClass().getName() + ")" + relStr;
+      }
+      str.append(relStr);
+
     }
     str.append("]");
     return str.toString();
@@ -375,9 +431,9 @@
     Annotation a = e.getAnnotation();
 
     // find all relations which include the annotation and remove them
-
-    // may need to be an iterative method as we may remove relations
-    // which are themselves in a relation
+    for(Relation r : getReferencing(a.getId())) {
+      deleteRelation(r);
+    }
   }
 
   public synchronized void removeRelationSetListener(RelationSetListener l) {

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
GATE-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gate-cvs

Reply via email to