/*
* Copyright (c) 2005, The University of Sheffield.
*
* This file is part of the GATE/UIMA integration layer, and is free
* software, released under the terms of the GNU Lesser General Public
* Licence, version 2.1 (or any later version). A copy of this licence
* is provided in the file LICENCE in the distribution.
*
* UIMA is a product of IBM, details are available from
* http://alphaworks.ibm.com/tech/uima
*/
package gate.uima.mapping;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.CAS;
import gate.Document;
import gate.Annotation;
import gate.AnnotationSet;
import gate.FeatureMap;
import gate.Factory;
import gate.util.InvalidOffsetException;
import org.apache.uima.cas.FeatureStructure;
import org.jdom.Element;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
/**
* An ObjectBuilder that creates a GATE annotation in the given annotation set.
*/
public class GateAnnotationBuilder implements ObjectBuilder {
/**
* The type of GATE annotation to create.
*/
protected String annotationType;
/**
* The UIMA annotation type that this annotation is to be based on.
*/
protected Type uimaType;
/**
* UIMA feature object for the begin feature of an annotation.
*/
protected Feature uimaAnnotationBeginFeature;
/**
* UIMA feature object for the end feature of an annotation.
*/
protected Feature uimaAnnotationEndFeature;
/**
* Feature definitions for the annotation.
*/
protected List featureDefs;
/**
* Should this builder index the generated annotations, so that changes to
* their features can be propagated back into GATE? Default is false.
*/
private boolean indexed;
public boolean isIndexed() { return indexed; }
/**
* Returns the UIMA type that this annotation is to be based on.
*/
public Type getUimaType() {
return uimaType;
}
/**
* Returns the GATE annotation type to be created.
*/
public String getGateType() {
return annotationType;
}
/**
* Configure this ObjectBuilder by extracting the GATE and UIMA types and the
* feature definitions from the XML element.
*/
public void configure(Element elt, TypeSystem typeSystem)
throws MappingException {
annotationType = elt.getAttributeValue("type");
if(annotationType == null) {
throw new MappingException("No \"type\" attribute specified for "
+ "gateAnnotation");
}
String uimaTypeString = elt.getAttributeValue("uimaType");
if(uimaTypeString == null) {
throw new MappingException("No \"uimaType\" attribute specified for "
+ "gateAnnotation");
}
uimaType = typeSystem.getType(uimaTypeString);
if(uimaType == null) {
throw new MappingException("Type " + uimaTypeString
+ " not found in UIMA type system");
}
if(!typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_ANNOTATION),
uimaType)) {
throw new MappingException("Type " + uimaTypeString
+ " is not an annotation type");
}
uimaAnnotationBeginFeature = typeSystem.getFeatureByFullName(
CAS.FEATURE_FULL_NAME_BEGIN);
if(uimaAnnotationBeginFeature == null) {
throw new MappingException(CAS.FEATURE_FULL_NAME_BEGIN + " feature not "
+ "found in type system - are you sure CAS is a CAS?");
}
uimaAnnotationEndFeature = typeSystem.getFeatureByFullName(
CAS.FEATURE_FULL_NAME_END);
if(uimaAnnotationEndFeature == null) {
throw new MappingException(CAS.FEATURE_FULL_NAME_END + " feature not "
+ "found in type system - are you sure CAS is a CAS?");
}
String indexedString = elt.getAttributeValue("indexed");
indexed = Boolean.valueOf(indexedString).booleanValue();
// build the list of feature definitions
List featureElements = elt.getChildren("feature");
featureDefs = new ArrayList(featureElements.size());
Iterator featureElementsIt = featureElements.iterator();
while(featureElementsIt.hasNext()) {
Element featureElt = (Element)featureElementsIt.next();
String featureName = featureElt.getAttributeValue("name");
if(featureName == null) {
throw new MappingException("feature element must have \"name\" "
+ "attribute specified");
}
List children = featureElt.getChildren();
if(children.isEmpty()) {
throw new MappingException("feature element must have a child element "
+ "specifying its value");
}
Element valueElement = (Element)children.get(0);
// create the object builder that gives this feature's value
ObjectBuilder valueBuilder = ObjectManager.createBuilder(valueElement,
typeSystem);
featureDefs.add(new FeatureDefinition(featureName, valueBuilder));
}
}
/**
* Create a GATE annotation in the given annotation set and return its ID.
*/
public Object buildObject(CAS cas, Document doc, AnnotationSet annSet,
Annotation currentAnn, FeatureStructure currentFS)
throws MappingException {
//if(!(currentFS instanceof AnnotationFS)) {
// throw new MappingException("GATE annotations can only be created from "
// + "UIMA annotations, and not from arbitrary feature structures.");
//}
//AnnotationFS uimaAnnot = (AnnotationFS)currentFS;
FeatureMap annotFeatures = Factory.newFeatureMap();
applyFeatureDefs(annotFeatures, cas, doc, annSet, currentAnn, currentFS);
int annotStart = currentFS.getIntValue(uimaAnnotationBeginFeature);
int annotEnd = currentFS.getIntValue(uimaAnnotationEndFeature);
// add returns the Integer ID
try {
return annSet.add(new Long(annotStart), new Long(annotEnd),
annotationType, annotFeatures);
}
catch(InvalidOffsetException ioe) {
throw new MappingException("Unexpected error creating annotation", ioe);
}
}
/**
* Updates the features of an existing annotation based on this builder's
* list of feature definitions.
*/
public void updateFeatures(CAS cas, Document doc, AnnotationSet annSet,
Annotation currentAnn, FeatureStructure currentFS)
throws MappingException {
//if(!(currentFS instanceof AnnotationFS)) {
// throw new MappingException("GATE annotations can only be created from "
// + "UIMA annotations, and not from arbitrary feature structures.");
//}
//AnnotationFS uimaAnnot = (AnnotationFS)currentFS;
FeatureMap features = currentAnn.getFeatures();
applyFeatureDefs(features, cas, doc, annSet, currentAnn, currentFS);
}
/**
* Removes the current annotation from the annotation set.
*/
public void removeAnnotation(CAS cas, Document doc, AnnotationSet annSet,
Annotation currentAnn, FeatureStructure currentFS)
throws MappingException {
annSet.remove(currentAnn);
}
/**
* Use the set of feature definitions on this builder to update the given
* feature map. If the value builder for a given feature returns the value
* <code>null</code> the corresponding feature will be removed from the map
* if it is present.
*/
protected void applyFeatureDefs(FeatureMap features, CAS cas, Document doc,
AnnotationSet annSet, Annotation currentGateAnn,
FeatureStructure currentUimaAnn) throws MappingException {
Iterator featuresIt = featureDefs.iterator();
while(featuresIt.hasNext()) {
FeatureDefinition def = (FeatureDefinition)featuresIt.next();
// build the feature value
ObjectBuilder valueBuilder = def.getValueBuilder();
Object featureValue = valueBuilder.buildObject(cas, doc, annSet,
currentGateAnn, currentUimaAnn);
if(featureValue == null) {
if(features.containsKey(def.getFeatureName())) {
features.remove(def.getFeatureName());
}
}
else {
features.put(def.getFeatureName(), featureValue);
}
}
}
}