Revision: 17173
http://sourceforge.net/p/gate/code/17173
Author: markagreenwood
Date: 2013-12-15 18:54:25 +0000 (Sun, 15 Dec 2013)
Log Message:
-----------
relations are now first class citizens; although possibly not the most well
behaved
Modified Paths:
--------------
gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/CorefBase.java
gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/LegacyCorefDataWriter.java
gate/trunk/src/main/gate/SimpleAnnotationSet.java
gate/trunk/src/main/gate/annotation/AnnotationSetImpl.java
gate/trunk/src/main/gate/corpora/DocumentStaxUtils.java
gate/trunk/src/main/gate/creole/annotdelete/AnnotationDeletePR.java
gate/trunk/src/main/gate/relations/Relation.java
gate/trunk/src/main/gate/relations/RelationSet.java
gate/trunk/src/main/gate/relations/SimpleRelation.java
gate/trunk/src/main/gate/resources/creole/creole.xml
Added Paths:
-----------
gate/trunk/src/main/gate/gui/docview/RelationSetView.java
Modified: gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/CorefBase.java
===================================================================
--- gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/CorefBase.java
2013-12-14 09:08:07 UTC (rev 17172)
+++ gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/CorefBase.java
2013-12-15 18:54:25 UTC (rev 17173)
@@ -206,9 +206,9 @@
* @return the {@link RelationSet} used during the {@link #execute()} call.
*/
public RelationSet getRelationSet() {
- return RelationSet.getRelations(
- (annotationSetName == null || annotationSetName.trim().length() == 0) ?
- document.getAnnotations() :
document.getAnnotations(annotationSetName));
+ return (annotationSetName == null || annotationSetName.trim().length() ==
0)
+ ? document.getAnnotations().getRelations()
+ : document.getAnnotations(annotationSetName).getRelations();
}
@Override
Modified:
gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/LegacyCorefDataWriter.java
===================================================================
---
gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/LegacyCorefDataWriter.java
2013-12-14 09:08:07 UTC (rev 17172)
+++
gate/trunk/plugins/Coref_Tools/src/gate/creole/coref/LegacyCorefDataWriter.java
2013-12-15 18:54:25 UTC (rev 17173)
@@ -85,7 +85,7 @@
(annotationSetName == null || annotationSetName.trim().length() == 0) ?
document.getAnnotations() :
document.getAnnotations(annotationSetName);
// get the relations set
- RelationSet relSet = RelationSet.getRelations(inputAnnSet);
+ RelationSet relSet = inputAnnSet.getRelations();
// now create the annotation and document features from the relations
Map<String, List<List<Integer>>> docCorefMap;
Modified: gate/trunk/src/main/gate/SimpleAnnotationSet.java
===================================================================
--- gate/trunk/src/main/gate/SimpleAnnotationSet.java 2013-12-14 09:08:07 UTC
(rev 17172)
+++ gate/trunk/src/main/gate/SimpleAnnotationSet.java 2013-12-15 18:54:25 UTC
(rev 17173)
@@ -16,12 +16,13 @@
package gate;
+import gate.relations.RelationSet;
+import gate.util.InvalidOffsetException;
+
import java.io.Serializable;
import java.util.Iterator;
import java.util.Set;
-import gate.util.InvalidOffsetException;
-
/**
* <p>
* A set of annotations on a document. Simple annotation sets support
@@ -170,5 +171,7 @@
* be attached to a document.
*/
public Document getDocument();
+
+ public RelationSet getRelations();
} // interface SimpleAnnotationSet
Modified: gate/trunk/src/main/gate/annotation/AnnotationSetImpl.java
===================================================================
--- gate/trunk/src/main/gate/annotation/AnnotationSetImpl.java 2013-12-14
09:08:07 UTC (rev 17172)
+++ gate/trunk/src/main/gate/annotation/AnnotationSetImpl.java 2013-12-15
18:54:25 UTC (rev 17173)
@@ -31,17 +31,41 @@
*/
package gate.annotation;
-import java.io.*;
-import java.util.*;
+import gate.Annotation;
+import gate.AnnotationSet;
+import gate.Document;
+import gate.DocumentContent;
+import gate.FeatureMap;
+import gate.Gate;
+import gate.GateConstants;
+import gate.Node;
+import gate.corpora.DocumentImpl;
+import gate.event.AnnotationSetEvent;
+import gate.event.AnnotationSetListener;
+import gate.event.GateEvent;
+import gate.event.GateListener;
+import gate.relations.RelationSet;
+import gate.util.InvalidOffsetException;
+import gate.util.RBTreeMap;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+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;
+import java.util.Vector;
+
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
-import gate.*;
-import gate.corpora.DocumentImpl;
-import gate.event.*;
-import gate.util.*;
-
/**
* Implementation of AnnotationSet. Has a number of indices, all bar one of
* which are null by default and are only constructed when asked for. Has lots
@@ -103,6 +127,8 @@
* needs to.
*/
protected transient Long longestAnnot = 0l;
+
+ protected RelationSet relations = null;
// Empty AnnotationSet to be returned instead of null
public final static AnnotationSet emptyAnnotationSet;
@@ -1262,4 +1288,11 @@
}
annotations = null;
}
+
+ public RelationSet getRelations() {
+ if (relations == null) {
+ relations = new RelationSet(this);
+ }
+ return relations;
+ }
} // AnnotationSetImpl
Modified: gate/trunk/src/main/gate/corpora/DocumentStaxUtils.java
===================================================================
--- gate/trunk/src/main/gate/corpora/DocumentStaxUtils.java 2013-12-14
09:08:07 UTC (rev 17172)
+++ gate/trunk/src/main/gate/corpora/DocumentStaxUtils.java 2013-12-15
18:54:25 UTC (rev 17173)
@@ -15,6 +15,23 @@
*/
package gate.corpora;
+import gate.Annotation;
+import gate.AnnotationSet;
+import gate.Document;
+import gate.DocumentContent;
+import gate.Factory;
+import gate.FeatureMap;
+import gate.Gate;
+import gate.TextualDocument;
+import gate.event.StatusListener;
+import gate.relations.Relation;
+import gate.relations.RelationSet;
+import gate.relations.SimpleRelation;
+import gate.util.GateException;
+import gate.util.GateRuntimeException;
+import gate.util.InvalidOffsetException;
+import gate.util.Out;
+
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
@@ -46,20 +63,6 @@
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
-import gate.Annotation;
-import gate.AnnotationSet;
-import gate.Document;
-import gate.DocumentContent;
-import gate.Factory;
-import gate.FeatureMap;
-import gate.Gate;
-import gate.TextualDocument;
-import gate.event.StatusListener;
-import gate.util.GateException;
-import gate.util.GateRuntimeException;
-import gate.util.InvalidOffsetException;
-import gate.util.Out;
-
/**
* This class provides support for reading and writing GATE XML format
* using StAX (the Streaming API for XML).
@@ -154,7 +157,7 @@
// not
Boolean requireAnnotationIds = null;
int eventType = xsr.nextTag();
- while(eventType == XMLStreamConstants.START_ELEMENT) {
+ while(eventType == XMLStreamConstants.START_ELEMENT &&
xsr.getLocalName().equals("AnnotationSet")) {
xsr.require(XMLStreamConstants.START_ELEMENT, null, "AnnotationSet");
String annotationSetName = xsr.getAttributeValue(null, "Name");
AnnotationSet annotationSet = null;
@@ -183,10 +186,43 @@
numAnnots += annotIdsInSet.size();
// readAnnotationSet leaves reader positioned on the
// </AnnotationSet> tag, so nextTag takes us to either the next
- // <AnnotationSet> or to the </GateDocument>
+ // <AnnotationSet>, a <RelationSet>, or </GateDocument>
eventType = xsr.nextTag();
}
+ while(eventType == XMLStreamConstants.START_ELEMENT
+ && xsr.getLocalName().equals("RelationSet")) {
+ xsr.require(XMLStreamConstants.START_ELEMENT, null, "RelationSet");
+ String relationSetName = xsr.getAttributeValue(null, "Name");
+ RelationSet relations = null;
+ if(relationSetName == null) {
+ if(statusListener != null) {
+ statusListener
+ .statusChanged("Reading relation set for default
annotation set");
+ }
+ relations = doc.getAnnotations().getRelations();
+ } else {
+ if(statusListener != null) {
+ statusListener.statusChanged("Reading relation set for \""
+ + relationSetName + "\" annotation set");
+ }
+ relations = doc.getAnnotations(relationSetName).getRelations();
+ }
+
+ SortedSet<Integer> relIdsInSet = new TreeSet<Integer>();
+ readRelationSet(xsr, relations, relIdsInSet);
+ if(relIdsInSet.size() > 0
+ && (maxAnnotId == null || relIdsInSet.last().intValue() >
maxAnnotId
+ .intValue())) {
+ maxAnnotId = relIdsInSet.last();
+ }
+ numAnnots += relIdsInSet.size();
+ // readAnnotationSet leaves reader positioned on the
+ // </RelationSet> tag, so nextTag takes us to either the next
+ // <RelationSet> or to the </GateDocument>
+ eventType = xsr.nextTag();
+ }
+
// check we are on the end document tag
xsr.require(XMLStreamConstants.END_ELEMENT, null, "GateDocument");
@@ -369,7 +405,72 @@
}
return requireAnnotationIds;
}
+
+ public static void readRelationSet(XMLStreamReader xsr,
+ RelationSet relations, Set<Integer> allAnnotIds)
+ throws XMLStreamException {
+ while(xsr.nextTag() == XMLStreamConstants.START_ELEMENT) {
+ xsr.require(XMLStreamConstants.START_ELEMENT, null, "Relation");
+ String type = xsr.getAttributeValue(null, "Type");
+ String idString = xsr.getAttributeValue(null, "Id");
+ String memberString = xsr.getAttributeValue(null, "Members");
+
+ if(memberString == null)
+ throw new XMLStreamException("A relation must have members");
+ if (type == null)
+ throw new XMLStreamException("A relation must have a type");
+ if (idString == null)
+ throw new XMLStreamException("A relation must have an id");
+
+ String[] memberStrings = memberString.split(";");
+ int[] members = new int[memberStrings.length];
+ for(int i = 0; i < members.length; ++i) {
+ members[i] = Integer.parseInt(memberStrings[i]);
+ }
+ xsr.nextTag();
+ xsr.require(XMLStreamConstants.START_ELEMENT, null, "UserData");
+
+ // get the string representation of the user data
+ StringBuilder stringRep = new StringBuilder(1024);
+ int eventType;
+ while((eventType = xsr.next()) != XMLStreamConstants.END_ELEMENT) {
+ switch(eventType) {
+ case XMLStreamConstants.CHARACTERS:
+ stringRep.append(xsr.getTextCharacters(), xsr.getTextStart(),
+ xsr.getTextLength());
+ break;
+
+ case XMLStreamConstants.CDATA:
+ stringRep.append(xsr.getTextCharacters(), xsr.getTextStart(),
+ xsr.getTextLength());
+ break;
+
+ case XMLStreamConstants.START_ELEMENT:
+ throw new XMLStreamException("Elements not allowed within "
+ + "user data.", xsr.getLocation());
+
+ default:
+ // do nothing - ignore comments, PIs, etc.
+ }
+ }
+
+ xsr.require(XMLStreamConstants.END_ELEMENT, null, "UserData");
+
+ FeatureMap features = readFeatureMap(xsr);
+
+ Relation r = new SimpleRelation(Integer.valueOf(idString), type,
members);
+ r.setFeatures(features);
+
+ if(stringRep.length() > 0) {
+ ObjectWrapper wrapper = new ObjectWrapper(stringRep.toString());
+ r.setUserData(wrapper.getValue());
+ }
+
+ relations.addRelation(r);
+ }
+ }
+
/**
* Processes the TextWithNodes element from this XMLStreamReader,
* returning the text content of the document. The supplied map is
@@ -964,6 +1065,13 @@
newLine(xsw);
}// End if
}// End while
+
+ iter = annotationSets.keySet().iterator();
+ while(iter.hasNext()) {
+
+ writeRelationSet(doc.getAnnotations(iter.next()).getRelations(), xsw,
+ namespaceURI);
+ }
// close the GateDocument element
xsw.writeEndElement();
@@ -1046,7 +1154,60 @@
xsw.writeEndElement();
newLine(xsw);
}
+
+ public static void writeRelationSet(RelationSet relations,
+ XMLStreamWriter xsw, String namespaceURI) throws XMLStreamException {
+ // if there are no relations then don't write the set, this means
+ // that docs without relations will remain compatible with earlier
+ // versions of GATE
+ if(relations == null || relations.size() == 0) return;
+
+ xsw.writeComment(" Relation Set for "
+ + relations.getAnnotationSet().getName() + " ");
+ newLine(xsw);
+ newLine(xsw);
+
+ xsw.writeStartElement(namespaceURI, "RelationSet");
+
+ if(relations.getAnnotationSet().getName() != null) {
+ xsw.writeAttribute("Name", relations.getAnnotationSet().getName());
+ }
+ newLine(xsw);
+
+ for(Relation relation : relations.get()) {
+
+ StringBuilder str = new StringBuilder();
+ int[] members = relation.getMembers();
+ for(int i = 0; i < members.length; i++) {
+ if(i > 0) str.append(";");
+ str.append(members[i]);
+ }
+ xsw.writeStartElement(namespaceURI, "Relation");
+ xsw.writeAttribute("Id", String.valueOf(relation.getId()));
+ xsw.writeAttribute("Type", relation.getType());
+ xsw.writeAttribute("Members", str.toString());
+ newLine(xsw);
+
+ xsw.writeStartElement(namespaceURI, "UserData");
+ if(relation.getUserData() != null) {
+ ObjectWrapper userData = new ObjectWrapper(relation.getUserData());
+ writeCharactersOrCDATA(xsw,
+ replaceXMLIllegalCharactersInString(userData.toString()));
+ }
+ xsw.writeEndElement();
+ newLine(xsw);
+
+ writeFeatures(relation.getFeatures(), xsw, namespaceURI);
+ xsw.writeEndElement();
+ newLine(xsw);
+ }
+
+ // end RelationSet element
+ xsw.writeEndElement();
+ newLine(xsw);
+ }
+
/**
* Retained for binary compatibility, new code should call the
* <code>Collection<Annotation></code> version instead.
Modified: gate/trunk/src/main/gate/creole/annotdelete/AnnotationDeletePR.java
===================================================================
--- gate/trunk/src/main/gate/creole/annotdelete/AnnotationDeletePR.java
2013-12-14 09:08:07 UTC (rev 17172)
+++ gate/trunk/src/main/gate/creole/annotdelete/AnnotationDeletePR.java
2013-12-15 18:54:25 UTC (rev 17173)
@@ -122,6 +122,9 @@
} else {
removeSubSet(document.getAnnotations(), matchesMap);
}
+
+ //empty the relation set associated with the annotation set
+ document.getAnnotations().getRelations().clear();
} else {
// remove this named set
if (annotationTypes == null || annotationTypes.isEmpty()) {
@@ -157,6 +160,8 @@
} else {
removeSubSet(document.getAnnotations(), matchesMap);
}
+ //empty the relation set associated with the annotation set
+ document.getAnnotations().getRelations().clear();
}
//get the names of all sets
Added: gate/trunk/src/main/gate/gui/docview/RelationSetView.java
===================================================================
--- gate/trunk/src/main/gate/gui/docview/RelationSetView.java
(rev 0)
+++ gate/trunk/src/main/gate/gui/docview/RelationSetView.java 2013-12-15
18:54:25 UTC (rev 17173)
@@ -0,0 +1,94 @@
+/*
+ * RelationSetView.java
+ *
+ * Copyright (c) 1995-2013, The University of Sheffield. See the file
+ * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
+ *
+ * This file is part of GATE (see http://gate.ac.uk/), and is free
+ * software, licenced under the GNU Library General Public License,
+ * Version 2, June 1991 (in the distribution as file licence.html,
+ * and also available at http://gate.ac.uk/gate/licence.html).
+ *
+ * Mark A. Greenwood, 15th December 2013
+ */
+package gate.gui.docview;
+
+import gate.Document;
+import gate.Resource;
+import gate.creole.AbstractVisualResource;
+import gate.creole.metadata.CreoleResource;
+import gate.creole.metadata.GuiType;
+import gate.gui.MainFrame;
+import gate.relations.RelationSet;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JTextPane;
+import javax.swing.JToolBar;
+
+@CreoleResource(name = "Relation Viewer", guiType = GuiType.LARGE,
resourceDisplayed = "gate.Document")
+public class RelationSetView extends AbstractVisualResource {
+
+ private static final long serialVersionUID = 2976754146115707386L;
+
+ private JTextPane text = new JTextPane();
+
+ private Document doc = null;
+
+ @Override
+ public Resource init() {
+ setLayout(new BorderLayout());
+
+ text.setEditable(false);
+
+ add(text, BorderLayout.CENTER);
+
+ JButton btnRefresh = new JButton("Refresh",MainFrame.getIcon("Refresh"));
+ btnRefresh.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ refresh();
+ }
+ });
+
+ JToolBar toolbar = new JToolBar(JToolBar.HORIZONTAL);
+ toolbar.setFloatable(false);
+
+ toolbar.add(btnRefresh);
+ toolbar.addSeparator();
+ toolbar.add(new JLabel("Currently this view is not automatically
updated"));
+
+ add(toolbar, BorderLayout.NORTH);
+
+ return this;
+ }
+
+ private void refresh() {
+ StringBuilder builder = new StringBuilder();
+
+ RelationSet relations = doc.getAnnotations().getRelations();
+ if(relations.size() > 0) {
+ builder.append(relations).append("\n\n");
+ }
+
+ for(String name : doc.getAnnotationSetNames()) {
+ relations = doc.getAnnotations(name).getRelations();
+ if(relations.size() > 0) {
+ builder.append(name).append(":\n").append(relations).append("\n\n");
+ }
+ }
+
+ text.setText(builder.toString());
+ }
+
+ @Override
+ public void setTarget(Object target) {
+ doc = (Document)target;
+ refresh();
+ }
+}
Modified: gate/trunk/src/main/gate/relations/Relation.java
===================================================================
--- gate/trunk/src/main/gate/relations/Relation.java 2013-12-14 09:08:07 UTC
(rev 17172)
+++ gate/trunk/src/main/gate/relations/Relation.java 2013-12-15 18:54:25 UTC
(rev 17173)
@@ -15,42 +15,48 @@
*/
package gate.relations;
+import gate.util.FeatureBearer;
+import gate.util.IdBearer;
+
import java.io.Serializable;
/**
* Interface representing a relation between GATE annotations.
*/
-public interface Relation extends Serializable {
-
+public interface Relation extends Serializable, IdBearer, FeatureBearer {
+
/**
* Get the type of the relation (e.g. {@link #COREF}).
- * @return the relation type.
+ *
+ * @return the relation type.
*/
public String getType();
-
+
/**
- * Gets the members of the relation.
+ * Gets the members of the relation.
+ *
* @return an array containing annotation IDs.
*/
public int[] getMembers();
-
+
/**
- * Some relations may have associated arbitrary data; this method can be
used
- * to retrieve it.
- * @return the user data that was previously added to this relation.
+ * Gets the arbitrary data associated with this relation
+ *
+ * @return the arbitrary data associated with this relation
*/
- public Serializable getUserData();
-
+ public Object getUserData();
+
/**
- * Associates some arbitrary user data to this relation.
- * @param data the user data value.
+ * Sets the arbitrary data associated with this relation
+ *
+ * @param data the arbitrary data associated with this
+ * relation
*/
- public void setUserData(Serializable data);
-
-
+ public void setUserData(Object data);
+
/**
- * Relation type for co-reference relations.
+ * Relation type for co-reference relations.
*/
public static final String COREF = "coref";
-
+
}
Modified: gate/trunk/src/main/gate/relations/RelationSet.java
===================================================================
--- gate/trunk/src/main/gate/relations/RelationSet.java 2013-12-14 09:08:07 UTC
(rev 17172)
+++ gate/trunk/src/main/gate/relations/RelationSet.java 2013-12-15 18:54:25 UTC
(rev 17173)
@@ -15,15 +15,14 @@
*/
package gate.relations;
+import gate.Annotation;
import gate.AnnotationSet;
-import gate.Document;
-import gate.Gate;
+import gate.corpora.DocumentImpl;
import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -32,142 +31,147 @@
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 relations).
+ * Utility class for managing a set of GATE relations (usually each
+ * annotation set of a document will have one set of associated
+ * relations).
*/
public class RelationSet implements Serializable {
-
+
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.
+ * Annotation ID used when calling {@link #getRelations(int...)} for
+ * positions with no restrictions.
*/
public static final int ANY = -1;
-
+
/**
- * Name used for a {@link Document} feature holding a {@link Map} from
- * {@link String} name to {@link RelationSet}. By convention, the relation
set
- * associated with an {@link AnnotationSet} used the annotation set name as
a
- * key.
- */
- public static final String RELATIONS_MAP_DOCUMENT_FEATURE_NAME =
"gate.relations";
-
- /**
* The list of all relations.
*/
protected List<Relation> relations;
-
+
/**
* Index for relations by type.
*/
protected Map<String, BitSet> indexByType;
-
+
/**
- * Keeps the indexes (in {@link #relations}) for relations that have been
- * deleted.
+ * Index for relations by id.
*/
+ 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.
+ * 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.
*
- * The element at position <code>pos</code> is a map from annotation ID
- * (representing a relation member) to a {@link BitSet} indicating which of
- * the relation indexes (in {@link #relations}) correspond to relations that
- * contain the given annotation (i.e. member) on the position
- * <code>pos</code>.
+ * The element at position <code>pos</code> is a map from annotation
+ * ID (representing a relation member) to a {@link BitSet} indicating
+ * which of the relation indexes (in {@link #relations}) correspond to
+ * relations that contain the given annotation (i.e. member) on the
+ * position <code>pos</code>.
*/
protected List<Map<Integer, BitSet>> indexesByMember;
-
+
/**
- * Factory method that gets a named {@link RelationSet} from a document.
- * {@link RelationSet}s are stored inside a special document feature, which
is
- * where this method retrieves them from. If no relation set is associated
- * with the given name, then a new one is created and returned.
- *
- * To get the relation set associated with a given annotation set use
- * {@link #getRelations(AnnotationSet)} instead.
- *
- * @param document the document for which the relations are being requested.
- * @param name the name for the relation set. This can be any arbitrary
- * {@link String} or even <code>null</code>. However, by convention, names
of
- * annotation sets (and <code>null</code> for the default annotation set) are
- * used to name the <i>principal</i> relation set for each annotation set.
- * @return the {@link RelationSet} requested.
+ * 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.
*/
- public static RelationSet getRelations(Document document, String name) {
- Object relMapObj = document.getFeatures().get(
- RELATIONS_MAP_DOCUMENT_FEATURE_NAME);
- Map<String, RelationSet> relationsMap = null;
- if(relMapObj != null) {
- if(relMapObj instanceof Map) {
- relationsMap = (Map)relMapObj;
- } else {
- document.getFeatures().remove(RELATIONS_MAP_DOCUMENT_FEATURE_NAME);
- log.warn("Invalid value for feature \"" +
- RELATIONS_MAP_DOCUMENT_FEATURE_NAME + "\" on document \"" +
- document.getName() + "\" has been removed.");
- }
- }
- if(relationsMap == null) {
- relationsMap = new HashMap<String, RelationSet>();
- document.getFeatures().put(RELATIONS_MAP_DOCUMENT_FEATURE_NAME,
- relationsMap);
- }
- RelationSet relSet = relationsMap.get(name);
- if(relSet == null) {
- relSet = new RelationSet();
- relationsMap.put(name, relSet);
- }
- return relSet;
+ protected AnnotationSet annSet;
+
+ public AnnotationSet getAnnotationSet() {
+ return annSet;
}
-
+
+ public Collection<Relation> get() {
+ return indexById.values();
+ }
+
/**
- * Factory method that gets the {@link RelationSet} associated with an
- * {@link AnnotationSet}.
- * @param annSet the annotation set for which the relations are being
- * requested.
- * @return the requested relation set. If none exists, a new one is created
- * and returned.
+ * You should never create a RelationSet directly, instead get if via
+ * the AnnotationSet
*/
- public static RelationSet getRelations(AnnotationSet annSet) {
- return getRelations(annSet.getDocument(), annSet.getName());
- }
-
- protected RelationSet() {
+ public RelationSet(AnnotationSet annSet) {
+ this.annSet = annSet;
relations = new ArrayList<Relation>();
indexByType = new HashMap<String, BitSet>();
- indexesByMember = new ArrayList<Map<Integer,BitSet>>();
+ indexesByMember = new ArrayList<Map<Integer, BitSet>>();
+ indexById = new HashMap<Integer, Relation>();
deleted = new BitSet();
}
+
+ /**
+ * Empties the relation set
+ */
+ public void clear() {
+ relations.clear();
+ indexByType.clear();
+ indexesByMember.clear();
+ indexById.clear();
+ deleted.clear();
+ }
/**
- * Creates a new {@link Relation} and adds it to this set. Uses the default
- * relation implementation at {@link SimpleRelation}.
+ * The number of relations in this set.
+ *
+ * @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();
+ }
+
+ /**
+ * Creates a new {@link Relation} and adds it to this set. Uses the
+ * default relation implementation at {@link SimpleRelation}.
+ *
* @param type the type for the new relation.
- * @param members the annotation IDs for the annotations that are members in
- * this relation.
+ * @param members the annotation IDs for the annotations that are
+ * members in this relation.
* @return the newly created {@link Relation} instance.
*/
- public Relation addRelation(String type, int... members) {
- Relation rel = new SimpleRelation(type, members);
+ public Relation addRelation(String type, int... members)
+ throws IllegalArgumentException {
+
+ if(members.length == 0)
+ throw new IllegalArgumentException("A relation can't have zero members");
+
+ for(int member : members) {
+ if(!indexById.containsKey(member) && annSet.get(member) == null)
+ throw new IllegalArgumentException(
+ "Member must be from within this annotation set");
+ }
+
+ Relation rel =
+ new SimpleRelation(
+ ((DocumentImpl)annSet.getDocument()).getNextAnnotationId(),
+ type, members);
addRelation(rel);
return rel;
}
-
-
+
/**
* Adds an externally-created {@link Relation} instance.
+ *
* @param rel the {@link Relation} to be added.
*/
public void addRelation(Relation rel) {
int relIdx = relations.size();
relations.add(rel);
+ indexById.put(rel.getId(), rel);
BitSet sameType = indexByType.get(rel.getType());
if(sameType == null) {
sameType = new BitSet(relations.size());
@@ -190,45 +194,53 @@
sameMember.set(relIdx);
}
}
-
+
/**
- * Returns the maximum arity for any relation in this {@link RelationSet}.
+ * Returns the maximum arity for any relation in this
+ * {@link RelationSet}.
+ *
* @return an int value.
*/
public int getMaximumArity() {
return indexesByMember.size();
}
-
+
/**
* Finds relations based on their type.
+ *
* @param type the type of relation being sought.
- * @return the list of all relations in this {@link RelationSet} that have
the
- * required type.
+ * @return the list of all relations in this {@link RelationSet} that
+ * have the required type.
*/
public List<Relation> getRelations(String type) {
List<Relation> res = new ArrayList<Relation>();
BitSet rels = indexByType.get(type);
if(rels != null) {
rels.andNot(deleted);
- for(int relPos = 0; relPos < relations.size(); relPos++){
- if(rels.get(relPos)) res.add(relations.get(relPos));
+ for(int relPos = 0; relPos < relations.size(); relPos++) {
+ if(rels.get(relPos)) res.add(relations.get(relPos));
}
}
return res;
}
-
+
+ public Relation get(Integer id) {
+ return indexById.get(id);
+ }
+
/**
* Finds relations based on their members.
- * @param members an array containing annotation IDs. If a constraint is not
- * required for a given member position, then the {@link #ANY}. value should
- * be used.
- * @return all the relations that have the given annotation IDs (members)
- * on the specified positions.
+ *
+ * @param members an array containing annotation IDs. If a constraint
+ * is not required for a given member position, then the
+ * {@link #ANY}. value should be used.
+ * @return all the relations that have the given annotation IDs
+ * (members) on the specified positions.
*/
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++) {
+ for(int i = 0; i < postingLists.length; i++) {
if(i < members.length && members[i] >= 0) {
postingLists[i] = indexesByMember.get(i).get(members[i]);
} else {
@@ -237,11 +249,11 @@
}
return intersection(postingLists);
}
-
+
public List<Relation> getRelations(String type, int... members) {
// get the lists of relations for each member
BitSet[] postingLists = new BitSet[indexesByMember.size() + 1];
- for(int i = 0; i < postingLists.length; i++) {
+ for(int i = 0; i < postingLists.length; i++) {
if(i < members.length && members[i] >= 0) {
postingLists[i] = indexesByMember.get(i).get(members[i]);
} else {
@@ -251,28 +263,33 @@
postingLists[postingLists.length - 1] = indexByType.get(type);
return intersection(postingLists);
}
-
+
/**
* Deletes the specified relation.
+ *
* @param relation the relation to be deleted.
- * @return <code>true</code> if the given relation was deleted, or
- * <code>false</code> if it was not found.
+ * @return <code>true</code> if the given relation was deleted, or
+ * <code>false</code> if it was not found.
*/
public boolean deleteRelation(Relation relation) {
int relIdx = relations.indexOf(relation);
- if(relIdx >= 0){
+ if(relIdx >= 0) {
deleted.set(relIdx);
relations.set(relIdx, null);
+ indexById.remove(relation.getId());
return true;
} else {
return false;
}
}
-
+
/**
- * Calculates the intersection of a set of lists containing relation indexes.
+ * Calculates the intersection of a set of lists containing relation
+ * indexes.
+ *
* @param indexLists the list to be intersected.
- * @return the list of relations contained in all the supplied index lists.
+ * @return the list of relations contained in all the supplied index
+ * lists.
*/
protected List<Relation> intersection(BitSet... indexLists) {
BitSet relIds = new BitSet(relations.size());
@@ -284,15 +301,17 @@
if(relIds.isEmpty()) break;
}
}
-
+
List<Relation> res = new ArrayList<Relation>();
- for(int relIdx = 0; relIdx < relations.size(); relIdx++){
+ for(int relIdx = 0; relIdx < relations.size(); relIdx++) {
if(relIds.get(relIdx)) res.add(relations.get(relIdx));
}
return res;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see java.lang.Object#toString()
*/
@Override
@@ -300,17 +319,17 @@
StringBuilder str = new StringBuilder();
str.append("[");
boolean first = true;
- for(int i = 0; i < relations.size(); i++) {
+ for(int i = 0; i < relations.size(); i++) {
if(!deleted.get(i)) {
if(first) {
first = false;
- } else{
+ } 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;
+ relStr = "(" + relations.get(i).getClass().getName() + ")" + relStr;
}
str.append(relStr);
}
@@ -318,5 +337,4 @@
str.append("]");
return str.toString();
}
-
}
Modified: gate/trunk/src/main/gate/relations/SimpleRelation.java
===================================================================
--- gate/trunk/src/main/gate/relations/SimpleRelation.java 2013-12-14
09:08:07 UTC (rev 17172)
+++ gate/trunk/src/main/gate/relations/SimpleRelation.java 2013-12-15
18:54:25 UTC (rev 17173)
@@ -15,7 +15,9 @@
*/
package gate.relations;
-import java.io.Serializable;
+import gate.Factory;
+import gate.FeatureMap;
+
import java.util.Arrays;
import java.util.regex.Matcher;
@@ -23,23 +25,36 @@
* A simple implementation for the {@link Relation} interface.
*/
public class SimpleRelation implements Relation {
-
+
private static final long serialVersionUID = 6866132107461267866L;
protected String type;
-
+
protected int[] members;
-
- protected Serializable userData;
-
- public SimpleRelation(String type, int[] members) {
+
+ protected int id;
+
+ protected FeatureMap features;
+
+ protected Object userData;
+
+ /**
+ * You should never create instances of this class directly, you
+ * should create new relations via the appropriate methods of
+ * {@link RelationSet}. This method is only publicly available to
+ * support persistence.
+ */
+ public SimpleRelation(int id, String type, int[] members) {
super();
+ this.id = id;
this.type = type;
this.members = members;
+ features = Factory.newFeatureMap();
}
-
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see gate.relations.Relation#getType()
*/
@Override
@@ -47,7 +62,9 @@
return type;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see gate.relations.Relation#getMembers()
*/
@Override
@@ -55,65 +72,53 @@
return members;
}
- /* (non-Javadoc)
- * @see gate.relations.Relation#getUserData()
- */
- @Override
- public Serializable getUserData() {
- return userData;
- }
-
- /* (non-Javadoc)
- * @see gate.relations.Relation#setUserData(java.io.Serializable)
- */
- @Override
- public void setUserData(Serializable data) {
- this.userData = data;
- }
-
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder str = new StringBuilder();
- String typeOut = type.replaceAll("\\(",
- Matcher.quoteReplacement("\\(")).replaceAll("\\)",
- Matcher.quoteReplacement("\\)"));
+ str.append(id).append(": ");
+ String typeOut =
+ type.replaceAll("\\(", Matcher.quoteReplacement("\\(")).replaceAll(
+ "\\)", Matcher.quoteReplacement("\\)"));
str.append(typeOut).append("(");
for(int i = 0; i < members.length; i++) {
if(i > 0) str.append(", ");
str.append(members[i]);
}
str.append(")");
+ if(features != null) {
+ str.append("#").append(features.toString());
+ }
if(userData != null) {
str.append("#").append(userData.toString());
}
return str.toString();
}
- /* (non-Javadoc)
- * @see java.lang.Object#hashCode()
- */
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
+ result = prime * result + ((features == null) ? 0 : features.hashCode());
result = prime * result + Arrays.hashCode(members);
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((userData == null) ? 0 : userData.hashCode());
return result;
}
- /* (non-Javadoc)
- * @see java.lang.Object#equals(java.lang.Object)
- */
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
- if(!(obj instanceof SimpleRelation)) return false;
+ if(getClass() != obj.getClass()) return false;
SimpleRelation other = (SimpleRelation)obj;
+ if(features == null) {
+ if(other.features != null) return false;
+ } else if(!features.equals(other.features)) return false;
if(!Arrays.equals(members, other.members)) return false;
if(type == null) {
if(other.type != null) return false;
@@ -123,6 +128,29 @@
} else if(!userData.equals(other.userData)) return false;
return true;
}
-
-
+
+ @Override
+ public Integer getId() {
+ return id;
+ }
+
+ @Override
+ public FeatureMap getFeatures() {
+ return features;
+ }
+
+ @Override
+ public void setFeatures(FeatureMap features) {
+ this.features = features;
+ }
+
+ @Override
+ public Object getUserData() {
+ return userData;
+ }
+
+ @Override
+ public void setUserData(Object data) {
+ userData = data;
+ }
}
Modified: gate/trunk/src/main/gate/resources/creole/creole.xml
===================================================================
--- gate/trunk/src/main/gate/resources/creole/creole.xml 2013-12-14
09:08:07 UTC (rev 17172)
+++ gate/trunk/src/main/gate/resources/creole/creole.xml 2013-12-15
18:54:25 UTC (rev 17173)
@@ -134,6 +134,10 @@
<RESOURCE>
<CLASS>gate.gui.ControllerMetadataViewer</CLASS>
</RESOURCE>
+
+ <RESOURCE>
+ <CLASS>gate.gui.docview.RelationSetView</CLASS>
+ </RESOURCE>
</CREOLE>
</CREOLE-DIRECTORY>
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