Log in Help
Print
Homereleasesgate-5.1-beta2-build3402-ALLpluginsUIMAsrcgateuimamapping 〉 UIMAFeatureStructureBuilder.java
 
/*
 *  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 org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.CASRuntimeException;
import org.jdom.Element;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * An ObjectBuilder that creates a UIMA FeatureStructure.
 */
public class UIMAFeatureStructureBuilder implements ObjectBuilder {
  /**
   * The UIMA Type of the feature structure to generate.
   */
  protected Type fsType;

  /**
   * Feature definitions for this feature structure.
   */
  protected List featureDefs;
  
  /**
   * Configure this ObjectBuilder by extracting the FeatureStructure type and
   * feature definitions from the XML element.
   */
  public void configure(Element elt, TypeSystem typeSystem)
        throws MappingException {
    String fsTypeName = elt.getAttributeValue("type");
    if(fsTypeName == null) {
      throw new MappingException("No \"type\" attribute specified for "
          + "featureStructure");
    }

    fsType = typeSystem.getType(fsTypeName);
    if(fsType == null) {
      throw new MappingException("Type " + fsTypeName
          + " not found in UIMA type system");
    }

    // build the list of feature definitions for this FS
    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");
      }

      Feature featureObject = fsType.getFeatureByBaseName(featureName);
      if(featureObject == null) {
        throw new MappingException("feature named \"" + featureName + "\" in "
            + "type \"" + fsTypeName + "\" does not exist in type system");
      }

      String featureKind = featureElt.getAttributeValue("kind");
      if(featureKind == null) {
        throw new MappingException("feature element must have \"kind\" "
            + "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, featureKind,
                                            valueBuilder, featureObject));
    }
  }

  /**
   * Constructs and returns the FeatureStructure.
   */
  public Object buildObject(CAS cas, Document doc, AnnotationSet annSet,
      Annotation currentAnn, FeatureStructure currentFS)
          throws MappingException {
    FeatureStructure newFS = createFS(cas, doc, currentAnn, fsType);

    populateFeatures(newFS, cas, doc, annSet, currentAnn, currentFS);

    return newFS;
  }

  /**
   * Create the feature structure object.  This method may be overridden by
   * subclasses that create more specific types of FS (e.g. annotations).
   */
  protected FeatureStructure createFS(CAS cas, Document doc,
      Annotation currentAnn, Type fsType) {
    return cas.createFS(fsType);
  }


  /**
   * Uses the set of feature definitions to populate the features of the given
   * feature structure.
   */
  public void populateFeatures(FeatureStructure newFS, CAS cas,
            Document doc, AnnotationSet annSet, Annotation currentAnn,
            FeatureStructure currentFS) 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,
                                               currentAnn, currentFS);

      // based on the feature kind, add it to the FS appropriately
      switch(def.getFeatureKind()) {
        // String kind - call toString on the value object and use that
        case FeatureDefinition.STRING_KIND:
          newFS.setStringValue(def.getCASFeatureObject(),
                               String.valueOf(featureValue));
          break;

        // integer kind - if the value object is a Number, call intValue,
        // otherwise try and parse the toString as an integer.  If this fails,
        // give up.
        case FeatureDefinition.INT_KIND:
          if(featureValue instanceof Number) {
            newFS.setIntValue(def.getCASFeatureObject(),
                              ((Number)featureValue).intValue());
          }
          else {
            try {
              newFS.setIntValue(def.getCASFeatureObject(),
                                Integer.parseInt(String.valueOf(featureValue)));
            }
            catch(NumberFormatException nfe) {
              throw new MappingException("Couldn't convert feature value \""
                  + featureValue + "\" to integer", nfe);
            }
          }
          break;

        // float kind - if the value object is a Number, call floatValue,
        // otherwise try and parse the toString as a float.  If this fails,
        // give up.
        case FeatureDefinition.FLOAT_KIND:
          if(featureValue instanceof Number) {
            newFS.setFloatValue(def.getCASFeatureObject(),
                              ((Number)featureValue).floatValue());
          }
          else {
            try {
              newFS.setFloatValue(def.getCASFeatureObject(),
                                Float.parseFloat(String.valueOf(featureValue)));
            }
            catch(NumberFormatException nfe) {
              throw new MappingException("Couldn't convert feature value \""
                  + featureValue + "\" to float", nfe);
            }
          }
          break;

        // feature structure kind - cast the value to a feature structure and
        // hope...
        case FeatureDefinition.FS_KIND:
          if(featureValue instanceof FeatureStructure) {
            newFS.setFeatureValue(def.getCASFeatureObject(),
                                  (FeatureStructure)featureValue);
          }
          else {
            throw new MappingException("Value for feature \"" 
                + def.getCASFeatureObject().getName() + "\" should be "
                + "a FeatureStructure");
          }
          break;

        default:
          throw new MappingException(
              "Unrecognised kind for feature definition");
      }
    }
  }
}