package gate.alignment; import gate.Annotation; import gate.Document; import gate.compound.CompoundDocument; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * This class stores all the alignment information about a document. It * provides various methods to know which annotation is aligned with * which annotations and what is the source document of each annotation. * * @author niraj */ public class Alignment implements Serializable { private static final long serialVersionUID = 3977299936398488370L; public static int counter = 0; /** * a map that stores information about annotation alignment. As a key, * a source annotation and as value, a set of aligned annotations to * the source annotation are stored. */ protected Map<Annotation, Set<Annotation>> alignmentMatrix; /** * For each annotation we store the information about its annotation * set. This is used for letting the user know which annotation set * the given annotation belongs to. */ protected Map<Annotation, String> annotation2Document; /** * which annotation belongs to what annotation set */ protected Map<Annotation, String> annotation2AS; /** * all the alignment listeners that wish to listen to vairous * alignment events */ protected transient List<AlignmentListener> listeners = new ArrayList<AlignmentListener>(); /** * the document this alignment object belongs to. */ protected transient CompoundDocument compoundDocument; /** * A feature that PRs can use to specify which method was used to align that particular annotation. */ public static final String ALIGNMENT_METHOD_FEATURE_NAME = "align-method"; /** * Constructor */ public Alignment(CompoundDocument compoundDocument) { this.compoundDocument = compoundDocument; alignmentMatrix = new HashMap<Annotation, Set<Annotation>>(); annotation2Document = new HashMap<Annotation, String>(); annotation2AS = new HashMap<Annotation, String>(); counter++; } /** * Sets the source document, this alignment object belongs to. * * @param cd */ public void setSourceDocument(CompoundDocument cd) { this.compoundDocument = cd; } /** * Returns if two annotations are aligned with each other. * * @param srcAnnotation * @param targetAnnotation * @return */ public boolean areTheyAligned(Annotation srcAnnotation, Annotation targetAnnotation) { Set<Annotation> alignedTo = alignmentMatrix.get(srcAnnotation); if(alignedTo == null || alignedTo.isEmpty()) return false; else return alignedTo.contains(targetAnnotation); } /** * Aligns the given source annotation with the given target * annotation. * * @param srcAnnotation * @param srcDocument * @param targetAnnotation * @param targetDocument */ public void align(Annotation srcAnnotation, String srcAS, Document srcDocument, Annotation targetAnnotation, String tgtAS, Document targetDocument) { if(srcAnnotation == null || targetAnnotation == null) return; if(areTheyAligned(srcAnnotation, targetAnnotation)) return; Set<Annotation> alignedToT = alignmentMatrix.get(srcAnnotation); if(alignedToT == null) { alignedToT = new HashSet<Annotation>(); alignmentMatrix.put(srcAnnotation, alignedToT); } Set<Annotation> alignedToS = alignmentMatrix.get(targetAnnotation); if(alignedToS == null) { alignedToS = new HashSet<Annotation>(); alignmentMatrix.put(targetAnnotation, alignedToS); } alignedToT.add(targetAnnotation); annotation2Document.put(srcAnnotation, srcDocument.getName()); annotation2AS.put(srcAnnotation, srcAS); alignedToS.add(srcAnnotation); annotation2Document.put(targetAnnotation, targetDocument.getName()); annotation2AS.put(targetAnnotation, tgtAS); fireAnnotationsAligned(srcAnnotation, srcAS, srcDocument, targetAnnotation, tgtAS, targetDocument); } /** * Aligns the given source annotation with the given target * annotation. * * @param srcAnnotation * @param srcDocument * @param targetAnnotation * @param targetDocument */ public void unalign(Annotation srcAnnotation, String srcAS, Document srcDocument, Annotation targetAnnotation, String tgtAS, Document targetDocument) { if(srcAnnotation == null || targetAnnotation == null) return; if(!areTheyAligned(srcAnnotation, targetAnnotation)) return; Set<Annotation> alignedToT = alignmentMatrix.get(srcAnnotation); Set<Annotation> alignedToS = alignmentMatrix.get(targetAnnotation); if(alignedToT != null) { alignedToT.remove(targetAnnotation); if(alignedToT.isEmpty()) { alignmentMatrix.remove(srcAnnotation); annotation2Document.remove(srcAnnotation); annotation2AS.remove(srcAnnotation); } else { alignmentMatrix.put(srcAnnotation, alignedToT); } } if(alignedToS != null) { alignedToS.remove(srcAnnotation); if(alignedToS.isEmpty()) { alignmentMatrix.remove(targetAnnotation); annotation2Document.remove(targetAnnotation); annotation2AS.remove(targetAnnotation); } else { alignmentMatrix.put(targetAnnotation, alignedToS); } } fireAnnotationsUnAligned(srcAnnotation, srcAS, srcDocument, targetAnnotation, tgtAS, targetDocument); } /** * Returns a set of aligned annotations. * * @return */ public Set<Annotation> getAlignedAnnotations() { Set<Annotation> annots = alignmentMatrix.keySet(); if(annots == null) return new HashSet<Annotation>(); else { return new HashSet<Annotation>(annots); } } /** * This method tells which document the given annotation belongs to. * * @param annotation * @return */ public Document getDocument(Annotation annotation) { return compoundDocument.getDocument(annotation2Document.get(annotation)); } public String getAnnotationSetName(Annotation annotation) { return annotation2AS.get(annotation); } /** * Given the annotation, this method returns a set of the aligned * annotations to that annotation. * * @param srcAnnotation * @return */ public Set<Annotation> getAlignedAnnotations(Annotation srcAnnotation) { Set<Annotation> annots = alignmentMatrix.get(srcAnnotation); if(annots != null) return new HashSet<Annotation>(annots); else return new HashSet<Annotation>(); } /** * This method tells whether the given annotation is aligned or not. * * @param srcAnnotation * @return */ public boolean isAnnotationAligned(Annotation srcAnnotation) { Set<Annotation> alignedTo = alignmentMatrix.get(srcAnnotation); if(alignedTo == null || alignedTo.isEmpty()) return false; else { return !alignedTo.isEmpty(); } } /** * adds a new member who wants to listens to alignment events * * @param listener */ public void addAlignmentListener(AlignmentListener listener) { if(this.listeners == null) { this.listeners = new ArrayList<AlignmentListener>(); } if(listener != null) this.listeners.add(listener); } /** * removes the given listener from the list of listeners who want to * listens to alignment events * * @param listener */ public void removeAlignmentListener(AlignmentListener listener) { if(this.listeners == null) { this.listeners = new ArrayList<AlignmentListener>(); } if(listener != null) this.listeners.remove(listener); } /** * calls the annotationsAligned(...) method on each of the registered listeners * @param srcAnnotation * @param srcAS * @param srcDocument * @param targetAnnotation * @param tgtAS * @param targetDocument */ protected void fireAnnotationsAligned(Annotation srcAnnotation, String srcAS, Document srcDocument, Annotation targetAnnotation, String tgtAS, Document targetDocument) { if(listeners == null) { listeners = new ArrayList<AlignmentListener>(); } for(AlignmentListener aListener : listeners) { aListener.annotationsAligned(srcAnnotation, srcAS, srcDocument, targetAnnotation, tgtAS, targetDocument); } } /** * calls the annotationsUnaligned(...) method on each of the resitered listeners * @param srcAnnotation * @param srcAS * @param srcDocument * @param targetAnnotation * @param tgtAS * @param targetDocument */ protected void fireAnnotationsUnAligned(Annotation srcAnnotation, String srcAS, Document srcDocument, Annotation targetAnnotation, String tgtAS, Document targetDocument) { if(listeners == null) { listeners = new ArrayList<AlignmentListener>(); } for(AlignmentListener aListener : listeners) { aListener.annotationsUnaligned(srcAnnotation, srcAS, srcDocument, targetAnnotation, tgtAS, targetDocument); } } /** * Returns a list of registered listeners * @return */ public List<AlignmentListener> getAlignmentListeners() { if(listeners == null) { listeners = new ArrayList<AlignmentListener>(); } return new ArrayList<AlignmentListener>(this.listeners); } }