You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ctakes.apache.org by st...@apache.org on 2012/11/16 17:39:22 UTC

svn commit: r1410447 - in /incubator/ctakes/trunk/ctakes-core: pom.xml src/main/java/org/apache/ctakes/core/ae/SHARPKnowtatorXMLReader.java

Author: stevenbethard
Date: Fri Nov 16 16:39:21 2012
New Revision: 1410447

URL: http://svn.apache.org/viewvc?rev=1410447&view=rev
Log:
Updates SHARPKnowtatorXMLReader. It now runs to completion on the current UMLS_CEM data from the cloud. But there are many TODOs where it is impossible to load the annotations given the current type system.

Modified:
    incubator/ctakes/trunk/ctakes-core/pom.xml
    incubator/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/ae/SHARPKnowtatorXMLReader.java

Modified: incubator/ctakes/trunk/ctakes-core/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ctakes/trunk/ctakes-core/pom.xml?rev=1410447&r1=1410446&r2=1410447&view=diff
==============================================================================
--- incubator/ctakes/trunk/ctakes-core/pom.xml (original)
+++ incubator/ctakes/trunk/ctakes-core/pom.xml Fri Nov 16 16:39:21 2012
@@ -38,7 +38,15 @@
 			<groupId>org.apache.ctakes</groupId>
 			<artifactId>ctakes-utils</artifactId>
 		</dependency>
-
+		<dependency>
+			<groupId>org.uimafit</groupId>
+			<artifactId>uimafit</artifactId>
+		</dependency>
+		<dependency>
+			<!-- needed for uimafit, but excluded in parent pom -->
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+		</dependency>
 		<dependency>
 			<groupId>jdom</groupId>
 			<artifactId>jdom</artifactId>

Modified: incubator/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/ae/SHARPKnowtatorXMLReader.java
URL: http://svn.apache.org/viewvc/incubator/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/ae/SHARPKnowtatorXMLReader.java?rev=1410447&r1=1410446&r2=1410447&view=diff
==============================================================================
--- incubator/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/ae/SHARPKnowtatorXMLReader.java (original)
+++ incubator/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/ae/SHARPKnowtatorXMLReader.java Fri Nov 16 16:39:21 2012
@@ -18,6 +18,7 @@
  */
 package org.apache.ctakes.core.ae;
 
+import java.io.File;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -28,7 +29,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.logging.Logger;
 
 import org.apache.ctakes.core.knowtator.KnowtatorAnnotation;
 import org.apache.ctakes.core.knowtator.KnowtatorXMLParser;
@@ -37,7 +37,16 @@ import org.apache.ctakes.typesystem.type
 import org.apache.ctakes.typesystem.type.refsem.Course;
 import org.apache.ctakes.typesystem.type.refsem.Event;
 import org.apache.ctakes.typesystem.type.refsem.EventProperties;
+import org.apache.ctakes.typesystem.type.refsem.LabValue;
+import org.apache.ctakes.typesystem.type.refsem.MedicationDosage;
+import org.apache.ctakes.typesystem.type.refsem.MedicationDuration;
+import org.apache.ctakes.typesystem.type.refsem.MedicationForm;
+import org.apache.ctakes.typesystem.type.refsem.MedicationFrequency;
+import org.apache.ctakes.typesystem.type.refsem.MedicationRoute;
+import org.apache.ctakes.typesystem.type.refsem.MedicationStatusChange;
+import org.apache.ctakes.typesystem.type.refsem.MedicationStrength;
 import org.apache.ctakes.typesystem.type.refsem.OntologyConcept;
+import org.apache.ctakes.typesystem.type.refsem.ProcedureMethod;
 import org.apache.ctakes.typesystem.type.refsem.Severity;
 import org.apache.ctakes.typesystem.type.refsem.UmlsConcept;
 import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
@@ -47,6 +56,8 @@ import org.apache.ctakes.typesystem.type
 import org.apache.ctakes.typesystem.type.textsem.EventMention;
 import org.apache.ctakes.typesystem.type.textsem.Modifier;
 import org.apache.ctakes.typesystem.type.textsem.TimeMention;
+import org.apache.log4j.Logger;
+import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.cas.FSArray;
@@ -54,17 +65,22 @@ import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.tcas.Annotation;
 import org.jdom2.JDOMException;
 import org.uimafit.component.JCasAnnotator_ImplBase;
+import org.uimafit.factory.AnalysisEngineFactory;
 import org.uimafit.util.JCasUtil;
 
 public class SHARPKnowtatorXMLReader extends JCasAnnotator_ImplBase {
+  static Logger LOGGER = Logger.getLogger(SHARPKnowtatorXMLReader.class);
+  
+  private static String getJCasURIString(JCas jCas) {
+    return JCasUtil.selectSingle(jCas, DocumentID.class).getDocumentID();
+  }
   
   /**
    * Given the URI of the plain text file, determines the URI of the Knowtator XML file
    */
   protected URI getKnowtatorXML(JCas jCas) throws AnalysisEngineProcessException {
-    String textURI = JCasUtil.selectSingle(jCas, DocumentID.class).getDocumentID();
+    String textURI = getJCasURIString(jCas);
     String xmlURI = textURI.replaceAll("Knowtator/text", "Knowtator_XML") + ".knowtator.xml";
-    System.err.println(xmlURI);
     try {
       return new URI(xmlURI);
     } catch (URISyntaxException e) {
@@ -82,7 +98,13 @@ public class SHARPKnowtatorXMLReader ext
   @Override
   public void process(JCas jCas) throws AnalysisEngineProcessException {
     // determine Knowtator XML file from the CAS
+    String uriString = getJCasURIString(jCas);
+    LOGGER.info("processing " + uriString);
     URI knowtatorXML = this.getKnowtatorXML(jCas);
+    if (!new File(knowtatorXML).exists()) {
+      LOGGER.fatal("no such Knowtator XML file " + knowtatorXML);
+      return;
+    }
 
     // parse the Knowtator XML file into annotation objects
     KnowtatorXMLParser parser = new KnowtatorXMLParser(this.getAnnotatorNames());
@@ -97,17 +119,24 @@ public class SHARPKnowtatorXMLReader ext
 
     // the relation types
     Set<String> entityRelationTypes = new HashSet<String>();
-    entityRelationTypes.add("location_of");
-    entityRelationTypes.add("degree_of");
+    entityRelationTypes.add("affects");
     entityRelationTypes.add("causes/brings_about");
+    entityRelationTypes.add("complicates/disrupts");
+    entityRelationTypes.add("contraindicates");
+    entityRelationTypes.add("degree_of");
+    entityRelationTypes.add("diagnoses");
     entityRelationTypes.add("indicates");
+    entityRelationTypes.add("is_indicated_for");
+    entityRelationTypes.add("location_of");
+    entityRelationTypes.add("manages/treats");
+    entityRelationTypes.add("manifestation_of"); // TODO: is this an error/misspelling in the data?
+    entityRelationTypes.add("result_of");
     Set<String> eventRelationTypes = new HashSet<String>();
     eventRelationTypes.add("TLINK");
     eventRelationTypes.add("ALINK");
 
     // create a CAS object for each annotation
     Map<String, Annotation> idAnnotationMap = new HashMap<String, Annotation>();
-    Map<String, TOP> idTopMap = new HashMap<String, TOP>();
     List<DelayedRelation> delayedRelations = new ArrayList<DelayedRelation>();
     List<DelayedFeature<?>> delayedFeatures = new ArrayList<DelayedFeature<?>>();
     for (KnowtatorAnnotation annotation : annotations) {
@@ -131,24 +160,38 @@ public class SHARPKnowtatorXMLReader ext
             annotationSlots,
             idAnnotationMap,
             delayedFeatures);
-        KnowtatorAnnotation bodySide = annotationSlots.remove("body_side");
-        if (bodySide != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, bodySide) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setBodySide(...)
-            }
-          });
-        }
         KnowtatorAnnotation bodyLaterality = annotationSlots.remove("body_laterality");
-        if (bodyLaterality != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, bodyLaterality) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setBodyLaterality(...)
-            }
-          });
-        }
+        delayedFeatures.add(new BodyLateralityFeature(entityMention, bodyLaterality));
+        KnowtatorAnnotation bodyLocation = annotationSlots.remove("body_location");
+        delayedFeatures.add(new BodyLocationFeature(entityMention, bodyLocation));
+        KnowtatorAnnotation bodySide = annotationSlots.remove("body_side");
+        delayedFeatures.add(new BodySideFeature(entityMention, bodySide));
+
+      } else if ("Clinical_attribute".equals(annotation.type)) {
+        EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
+        addEntityMentionFeatures(
+            annotation,
+            entityMention,
+            jCas,
+            CONST.NE_TYPE_ID_UNKNOWN /* TODO: is this the correct type? */,
+            stringSlots,
+            booleanSlots,
+            annotationSlots,
+            idAnnotationMap,
+            delayedFeatures);
+
+      } else if ("Devices".equals(annotation.type)) {
+        EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
+        addEntityMentionFeatures(
+            annotation,
+            entityMention,
+            jCas,
+            CONST.NE_TYPE_ID_UNKNOWN /* TODO: is this the correct type? */,
+            stringSlots,
+            booleanSlots,
+            annotationSlots,
+            idAnnotationMap,
+            delayedFeatures);
 
       } else if ("Disease_Disorder".equals(annotation.type)) {
         EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
@@ -162,24 +205,41 @@ public class SHARPKnowtatorXMLReader ext
             annotationSlots,
             idAnnotationMap,
             delayedFeatures);
+        KnowtatorAnnotation alleviatingFactor = annotationSlots.remove("alleviating_factor");
+        delayedFeatures.add(new AlleviatingFactorFeature(entityMention, alleviatingFactor));
+        KnowtatorAnnotation signOrSymptom = annotationSlots.remove("associated_sign_or_symptom");
+        delayedFeatures.add(new AssociatedSignOrSymptomFeature(entityMention, signOrSymptom));
+        KnowtatorAnnotation bodyLaterality = annotationSlots.remove("body_laterality");
+        delayedFeatures.add(new BodyLateralityFeature(entityMention, bodyLaterality));
         KnowtatorAnnotation bodyLocation = annotationSlots.remove("body_location");
-        if (bodyLocation != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, bodyLocation) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setBodyLocation(...)
-            }
-          });
-        }
+        delayedFeatures.add(new BodyLocationFeature(entityMention, bodyLocation));
+        KnowtatorAnnotation bodySide = annotationSlots.remove("body_side");
+        delayedFeatures.add(new BodySideFeature(entityMention, bodySide));
+        KnowtatorAnnotation course = annotationSlots.remove("course");
+        delayedFeatures.add(new CourseFeature(entityMention, course));
+        KnowtatorAnnotation exacerbatingFactor = annotationSlots.remove("exacerbating_factor");
+        delayedFeatures.add(new ExacerbatingFactorFeature(entityMention, exacerbatingFactor));
         KnowtatorAnnotation severity = annotationSlots.remove("severity");
-        if (severity != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, severity) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setSeverity(...)
-            }
-          });
-        }
+        delayedFeatures.add(new SeverityFeature(entityMention, severity));
+
+      } else if ("Lab".equals(annotation.type)) {
+        EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
+        addEntityMentionFeatures(
+            annotation,
+            entityMention,
+            jCas,
+            CONST.NE_TYPE_ID_UNKNOWN /* TODO: is this the correct type? */,
+            stringSlots,
+            booleanSlots,
+            annotationSlots,
+            idAnnotationMap,
+            delayedFeatures);
+        KnowtatorAnnotation ordinal = annotationSlots.remove("ordinal_interpretation");
+        delayedFeatures.add(new LabOrdinalFeature(entityMention, ordinal));
+        KnowtatorAnnotation referenceRange = annotationSlots.remove("reference_range_narrative");
+        delayedFeatures.add(new LabReferenceRangeFeature(entityMention, referenceRange));
+        KnowtatorAnnotation value = annotationSlots.remove("lab_value");
+        delayedFeatures.add(new LabValueFeature(entityMention, value));
 
       } else if ("Medications/Drugs".equals(annotation.type)) {
         EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
@@ -193,6 +253,24 @@ public class SHARPKnowtatorXMLReader ext
             annotationSlots,
             idAnnotationMap,
             delayedFeatures);
+        KnowtatorAnnotation allergy = annotationSlots.remove("allergy_indicator");
+        delayedFeatures.add(new MedicationAllergyFeature(entityMention, allergy));
+        KnowtatorAnnotation changeStatus = annotationSlots.remove("change_status_model");
+        delayedFeatures.add(new MedicationDurationFeature(entityMention, changeStatus));
+        KnowtatorAnnotation dosage = annotationSlots.remove("dosage_model");
+        delayedFeatures.add(new MedicationDosageFeature(entityMention, dosage));
+        KnowtatorAnnotation duration = annotationSlots.remove("duration_model");
+        delayedFeatures.add(new MedicationStatusChangeFeature(entityMention, duration));
+        KnowtatorAnnotation form = annotationSlots.remove("form_model");
+        delayedFeatures.add(new MedicationFormFeature(entityMention, form));
+        KnowtatorAnnotation frequency = annotationSlots.remove("frequency_model");
+        delayedFeatures.add(new MedicationFrequencyFeature(entityMention, frequency));
+        KnowtatorAnnotation route = annotationSlots.remove("route_model");
+        delayedFeatures.add(new MedicationRouteFeature(entityMention, route));
+        KnowtatorAnnotation startDate = annotationSlots.remove("start_date");
+        delayedFeatures.add(new MedicationStartDateFeature(entityMention, startDate));
+        KnowtatorAnnotation strength = annotationSlots.remove("strength_model");
+        delayedFeatures.add(new MedicationStrengthFeature(entityMention, strength));
 
       } else if ("Phenomena".equals(annotation.type)) {
         EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
@@ -219,24 +297,16 @@ public class SHARPKnowtatorXMLReader ext
             annotationSlots,
             idAnnotationMap,
             delayedFeatures);
+        KnowtatorAnnotation bodyLaterality = annotationSlots.remove("body_laterality");
+        delayedFeatures.add(new BodyLateralityFeature(entityMention, bodyLaterality));
         KnowtatorAnnotation bodyLocation = annotationSlots.remove("body_location");
-        if (bodyLocation != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, bodyLocation) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setBodyLocation(...)
-            }
-          });
-        }
-        KnowtatorAnnotation historyOf = annotationSlots.remove("historyOf_CU");
-        if (historyOf != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, historyOf) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setHistoryOf(...)
-            }
-          });
-        }
+        delayedFeatures.add(new BodyLocationFeature(entityMention, bodyLocation));
+        KnowtatorAnnotation bodySide = annotationSlots.remove("body_side");
+        delayedFeatures.add(new BodySideFeature(entityMention, bodySide));
+        KnowtatorAnnotation device = annotationSlots.remove("device");
+        delayedFeatures.add(new ProcedureDeviceFeature(entityMention, device));
+        KnowtatorAnnotation method = annotationSlots.remove("method");
+        delayedFeatures.add(new ProcedureMethodFeature(entityMention, method));
 
       } else if ("Sign_symptom".equals(annotation.type)) {
         EntityMention entityMention = new EntityMention(jCas, coveringSpan.begin, coveringSpan.end);
@@ -250,24 +320,20 @@ public class SHARPKnowtatorXMLReader ext
             annotationSlots,
             idAnnotationMap,
             delayedFeatures);
+        KnowtatorAnnotation alleviatingFactor = annotationSlots.remove("alleviating_factor");
+        delayedFeatures.add(new AlleviatingFactorFeature(entityMention, alleviatingFactor));
+        KnowtatorAnnotation bodyLaterality = annotationSlots.remove("body_laterality");
+        delayedFeatures.add(new BodyLateralityFeature(entityMention, bodyLaterality));
         KnowtatorAnnotation bodyLocation = annotationSlots.remove("body_location");
-        if (bodyLocation != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, bodyLocation) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setBodyLocation(...)
-            }
-          });
-        }
+        delayedFeatures.add(new BodyLocationFeature(entityMention, bodyLocation));
+        KnowtatorAnnotation bodySide = annotationSlots.remove("body_side");
+        delayedFeatures.add(new BodySideFeature(entityMention, bodySide));
+        KnowtatorAnnotation course = annotationSlots.remove("course");
+        delayedFeatures.add(new CourseFeature(entityMention, course));
+        KnowtatorAnnotation exacerbatingFactor = annotationSlots.remove("exacerbating_factor");
+        delayedFeatures.add(new ExacerbatingFactorFeature(entityMention, exacerbatingFactor));
         KnowtatorAnnotation severity = annotationSlots.remove("severity");
-        if (severity != null) {
-          delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, severity) {
-            @Override
-            protected void setValue(TOP valueAnnotation) {
-              // TODO: this.annotation.setSeverity(...)
-            }
-          });
-        }
+        delayedFeatures.add(new SeverityFeature(entityMention, severity));
 
       } else if ("EVENT".equals(annotation.type)) {
 
@@ -343,12 +409,13 @@ public class SHARPKnowtatorXMLReader ext
         timeMention.addToIndexes();
         idAnnotationMap.put(annotation.id, timeMention);
         // TODO
-
+        
       } else if ("generic_class".equals(annotation.type)) {
-        // TODO: there's currently no Generic in the type system
-        boolean value = booleanSlots.remove("generic_normalization");
+        // TODO: unclear where this slot goes
+        Boolean value = booleanSlots.remove("generic_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("severity_class".equals(annotation.type)) {
@@ -357,13 +424,15 @@ public class SHARPKnowtatorXMLReader ext
         severity.addToIndexes();
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
         modifier.setNormalizedForm(severity);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("conditional_class".equals(annotation.type)) {
-        // TODO: there's currently no Conditional in the type system
-        boolean value = booleanSlots.remove("conditional_normalization");
+        // TODO: unclear where this slot goes
+        Boolean value = booleanSlots.remove("conditional_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("course_class".equals(annotation.type)) {
@@ -372,29 +441,32 @@ public class SHARPKnowtatorXMLReader ext
         course.addToIndexes();
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
         modifier.setNormalizedForm(course);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("uncertainty_indicator_class".equals(annotation.type)) {
-        // TODO: there's currently no Uncertainty in the type system
+        // TODO: unclear where this slot goes
         String value = stringSlots.remove("uncertainty_indicator_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("distal_or_proximal".equals(annotation.type)) {
-        // TODO: there's currently no Distal or Proximal in the type system
+        // TODO: unclear where this slot goes
         String value = stringSlots.remove("distal_or_proximal_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("Person".equals(annotation.type)) {
-        // TODO: there's currently no Subject in the type system
+        // TODO: unclear where these slots go
         String value = stringSlots.remove("subject_normalization_CU");
-        // TODO: what does a code mean on a Person?
         String code = stringSlots.remove("associatedCode");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("body_side_class".equals(annotation.type)) {
@@ -403,47 +475,298 @@ public class SHARPKnowtatorXMLReader ext
         bodySide.addToIndexes();
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
         modifier.setNormalizedForm(bodySide);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("negation_indicator_class".equals(annotation.type)) {
-        // TODO: there's currently no Negation in the type system
+        // TODO: unclear where this slot goes
         String value = stringSlots.remove("negation_indicator_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("historyOf_indicator_class".equals(annotation.type)) {
-        // TODO: there's currently no HistoryOf in the type system
+        // TODO: unclear where this slot goes
         String value = stringSlots.remove("historyOf_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("superior_or_inferior".equals(annotation.type)) {
-        // TODO: there's currently no Superior or Inferior in the type system
+        // TODO: unclear where this slot goes
         String value = stringSlots.remove("superior_or_inferior_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("medial_or_lateral".equals(annotation.type)) {
-        // TODO: there's currently no Medial or Lateral in the type system
+        // TODO: unclear where this slot goes
         String value = stringSlots.remove("medial_or_lateral_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("dorsal_or_ventral".equals(annotation.type)) {
+        // TODO: unclear where this slot goes
+        String value = stringSlots.remove("dorsal_or_ventral_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("method_class".equals(annotation.type)) {
+        String code = stringSlots.remove("associatedCode");
+        ProcedureMethod method = new ProcedureMethod(jCas);
+        method.setValue(code);
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.setNormalizedForm(method);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("device_class".equals(annotation.type)) {
+        // TODO: unclear where this slot goes
+        String code = stringSlots.remove("associatedCode");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("allergy_indicator_class".equals(annotation.type)) {
+        // TODO: unclear where this slot goes
+        String code = stringSlots.remove("allergy_indicator_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if ("Route".equals(annotation.type)) {
         // TODO: there's currently no Route in the type system
         String value = stringSlots.remove("route_values");
+        MedicationRoute route = new MedicationRoute(jCas);
+        route.setValue(value);
+        route.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(route);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+        
+      } else if ("Form".equals(annotation.type)) {
+        String value = stringSlots.remove("form_values");
+        MedicationForm form = new MedicationForm(jCas);
+        form.setValue(value);
+        form.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(form);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+        
+      } else if ("Strength".equals(annotation.type)) {
+        KnowtatorAnnotation unit = annotationSlots.remove("strength_unit");
+        KnowtatorAnnotation number = annotationSlots.remove("strength_number");
+        MedicationStrength strength = new MedicationStrength(jCas);
+        strength.addToIndexes();
+        delayedFeatures.add(new DelayedFeature<MedicationStrength>(strength, unit) {
+          @Override
+          protected void setValue(Annotation valueAnnotation) {
+            // TODO: this.annotation.setUnit(...)
+          }
+        });
+        delayedFeatures.add(new DelayedFeature<MedicationStrength>(strength, number) {
+          @Override
+          protected void setValue(Annotation valueAnnotation) {
+            // TODO: this.annotation.setNumber(...)
+          }
+        });
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
-      } else if ("Clinical_attribute".equals(annotation.type)) {
+      } else if ("Strength number".equals(annotation.type)) {
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Strength unit".equals(annotation.type)) {
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Frequency".equals(annotation.type)) {
+        KnowtatorAnnotation unit = annotationSlots.remove("frequency_unit");
+        KnowtatorAnnotation number = annotationSlots.remove("frequency_number");
+        MedicationFrequency frequency = new MedicationFrequency(jCas);
+        frequency.addToIndexes();
+        delayedFeatures.add(new DelayedFeature<MedicationFrequency>(frequency, unit) {
+          @Override
+          protected void setValue(Annotation valueAnnotation) {
+            // TODO: this.annotation.setUnit(...)
+          }
+        });
+        delayedFeatures.add(new DelayedFeature<MedicationFrequency>(frequency, number) {
+          @Override
+          protected void setValue(Annotation valueAnnotation) {
+            // TODO: this.annotation.setNumber(...)
+          }
+        });
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(frequency);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Frequency number".equals(annotation.type)) {
+        String number = stringSlots.remove("frequency_number_normalization");
+        MedicationFrequency frequency = new MedicationFrequency(jCas);
+        frequency.setNumber(number);
+        frequency.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(frequency);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Frequency unit".equals(annotation.type)) {
+        String unit = stringSlots.remove("frequency_unit_values");
+        MedicationFrequency frequency = new MedicationFrequency(jCas);
+        frequency.setUnit(unit);
+        frequency.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(frequency);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Value".equals(annotation.type)) {
+        KnowtatorAnnotation unit = annotationSlots.remove("value_unit");
+        KnowtatorAnnotation number = annotationSlots.remove("value_number");
+        LabValue labValue = new LabValue(jCas);
+        labValue.addToIndexes();
+        delayedFeatures.add(new DelayedFeature<LabValue>(labValue, unit) {
+          @Override
+          protected void setValue(Annotation valueAnnotation) {
+            // TODO: this.annotation.setUnit(...)
+          }
+        });
+        delayedFeatures.add(new DelayedFeature<LabValue>(labValue, number) {
+          @Override
+          protected void setValue(Annotation valueAnnotation) {
+            // TODO: this.annotation.setNumber(...)
+          }
+        });
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(labValue);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Value number".equals(annotation.type)) {
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Value unit".equals(annotation.type)) {
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("lab_interpretation_indicator".equals(annotation.type)) {
+        // TODO: unclear where the slot value goes
+        String value = stringSlots.remove("lab_interpretation_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("estimated_flag_indicator".equals(annotation.type)) {
+        // TODO: unclear where the slot value goes
+        boolean value = booleanSlots.remove("estimated_normalization");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("reference_range".equals(annotation.type)) {
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Date".equals(annotation.type)) {
+        // TODO: unclear where these slot values go
+        String month = stringSlots.remove("month");
+        String day = stringSlots.remove("day");
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Status change".equals(annotation.type)) {
+        String value = stringSlots.remove("change_status_value");
+        MedicationStatusChange statusChange = new MedicationStatusChange(jCas);
+        statusChange.setValue(value);
+        statusChange.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(statusChange);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Duration".equals(annotation.type)) {
+        String value = stringSlots.remove("duration_values");
+        MedicationDuration duration = new MedicationDuration(jCas);
+        duration.setValue(value);
+        duration.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(duration);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Dosage".equals(annotation.type)) {
+        String value = stringSlots.remove("dosage_values");
+        MedicationDosage dosage = new MedicationDosage(jCas);
+        dosage.setValue(value);
+        dosage.addToIndexes();
+        // TODO: set the modifier type (or use an appropriate Modifier sub-type?)
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.setNormalizedForm(dosage);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Attributes_lab".equals(annotation.type)) {
+        // TODO: what does this even mean?
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Temporal".equals(annotation.type)) {
         // TODO: what does this even mean?
         Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
-        // modifier.setNormalizedForm(...);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if (":THING".equals(annotation.type)) {
+        // TODO: what does this even mean?
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
+        idAnnotationMap.put(annotation.id, modifier);
+
+      } else if ("Entities".equals(annotation.type)) {
+        // TODO: what does this even mean?
+        Modifier modifier = new Modifier(jCas, coveringSpan.begin, coveringSpan.end);
+        modifier.addToIndexes();
         idAnnotationMap.put(annotation.id, modifier);
 
       } else if (eventRelationTypes.contains(annotation.type)) {
@@ -463,6 +786,8 @@ public class SHARPKnowtatorXMLReader ext
         relation.annotation = annotation;
         relation.source = annotationSlots.remove("Argument_CU");
         relation.target = annotationSlots.remove("Related_to_CU");
+        relation.conditional = annotationSlots.remove("conditional_CU");
+        relation.negation = annotationSlots.remove("negation_indicator_CU");
         relation.uncertainty = annotationSlots.remove("uncertainty_indicator_CU");
         delayedRelations.add(relation);
 
@@ -491,9 +816,6 @@ public class SHARPKnowtatorXMLReader ext
       }
     }
 
-    // add all annotations to the TOP map
-    idTopMap.putAll(idAnnotationMap);
-
     // all mentions should be added, so add features that required other annotations
     for (DelayedFeature<?> delayedFeature : delayedFeatures) {
       delayedFeature.setValueFrom(idAnnotationMap);
@@ -525,49 +847,19 @@ public class SHARPKnowtatorXMLReader ext
         ? CONST.NE_POLARITY_NEGATION_ABSENT
         : negation == true ? CONST.NE_POLARITY_NEGATION_PRESENT : CONST.NE_POLARITY_NEGATION_ABSENT);
 
-    // negation must be delayed until the Negation annotations are present
-    KnowtatorAnnotation negationIndicator = annotationSlots.remove("negation_indicator_CU");
-    if (negationIndicator != null) {
-      delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, negationIndicator) {
-        @Override
-        protected void setValue(TOP valueAnnotation) {
-          // TODO: this.annotation.setPolarity(...)
-        }
-      });
-    }
-
-    // conditional must be delayed until the Conditional annotations are present
+    // add features for conditional, generic, etc.
     KnowtatorAnnotation conditional = annotationSlots.remove("conditional_CU");
-    if (conditional != null) {
-      delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, conditional) {
-        @Override
-        protected void setValue(TOP valueAnnotation) {
-          // TODO: this.annotation.setConditional(...)
-        }
-      });
-    }
-
-    // uncertainty must be delayed until the Uncertainty annotations are present
-    KnowtatorAnnotation uncertainty = annotationSlots.remove("uncertainty_indicator_CU");
-    if (uncertainty != null) {
-      delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, uncertainty) {
-        @Override
-        protected void setValue(TOP valueAnnotation) {
-          // TODO: this.annotation.setUncertainty(...)
-        }
-      });
-    }
-
-    // subject must be delayed until the Subject annotations are present
+    delayedFeatures.add(new ConditionalFeature(entityMention, conditional));
+    KnowtatorAnnotation generic = annotationSlots.remove("generic_CU");
+    delayedFeatures.add(new GenericFeature(entityMention, generic));
+    KnowtatorAnnotation historyOf = annotationSlots.remove("historyOf_CU");
+    delayedFeatures.add(new HistoryOfFeature(entityMention, historyOf));
+    KnowtatorAnnotation negationIndicator = annotationSlots.remove("negation_indicator_CU");
+    delayedFeatures.add(new NegationFeature(entityMention, negationIndicator));
     KnowtatorAnnotation subject = annotationSlots.remove("subject_CU");
-    if (subject != null) {
-      delayedFeatures.add(new DelayedFeature<EntityMention>(entityMention, subject) {
-        @Override
-        protected void setValue(TOP valueAnnotation) {
-          // TODO: this.annotation.setSubject(...)
-        }
-      });
-    }
+    delayedFeatures.add(new SubjectFeature(entityMention, subject));
+    KnowtatorAnnotation uncertainty = annotationSlots.remove("uncertainty_indicator_CU");
+    delayedFeatures.add(new UncertaintyFeature(entityMention, uncertainty));
 
     // convert status as necessary
     String status = stringSlots.remove("Status");
@@ -607,8 +899,6 @@ public class SHARPKnowtatorXMLReader ext
   }
 
   private static class DelayedRelation {
-    private static Logger LOGGER = Logger.getLogger(DelayedRelation.class.getName());
-
     public URI sourceFile;
 
     public KnowtatorAnnotation annotation;
@@ -619,6 +909,10 @@ public class SHARPKnowtatorXMLReader ext
 
     public String type;
 
+    public KnowtatorAnnotation conditional;
+    
+    public KnowtatorAnnotation negation;
+    
     public KnowtatorAnnotation uncertainty;
     
     public DelayedRelation() {
@@ -627,7 +921,7 @@ public class SHARPKnowtatorXMLReader ext
     public void addToIndexes(JCas jCas, Map<String, Annotation> idAnnotationMap) {
       if (this.source == null) {
         // throw new UnsupportedOperationException(String.format(
-        LOGGER.warning(String.format(
+        LOGGER.error(String.format(
             "no source for '%s' with annotationSlots %s in %s",
             this.annotation.id,
             this.annotation.annotationSlots.keySet(),
@@ -636,7 +930,7 @@ public class SHARPKnowtatorXMLReader ext
       }
       if (this.target == null) {
         // throw new UnsupportedOperationException(String.format(
-        LOGGER.warning(String.format(
+        LOGGER.error(String.format(
             "no target for '%s' with annotationSlots %s in %s",
             this.annotation.id,
             this.annotation.annotationSlots.keySet(),
@@ -647,23 +941,46 @@ public class SHARPKnowtatorXMLReader ext
       // look up the relations in the map and issue an error if they're missing
       Annotation sourceMention = idAnnotationMap.get(this.source.id);
       Annotation targetMention = idAnnotationMap.get(this.target.id);
-      String badId = null;
       if (sourceMention == null) {
-        badId = this.source.id;
+        LOGGER.error(String.format(
+            "no Annotation for source id '%s' in %s",
+            this.source.id,
+            this.sourceFile));
+        return;
       } else if (targetMention == null) {
-        badId = this.target.id;
-      }
-      if (badId != null) {
-        throw new UnsupportedOperationException(String.format(
-            "no annotation with id '%s' in %s",
-            badId,
+        LOGGER.error(String.format(
+            "no Annotation for target id '%s' in %s",
+            this.target.id,
             this.sourceFile));
+        return;
+      }
+
+      // get the conditional
+      if (this.conditional != null) {
+        Annotation conditionalAnnotation = idAnnotationMap.get(this.conditional.id);
+        if (conditionalAnnotation == null) {
+          throw new UnsupportedOperationException(String.format(
+              "no annotation with id '%s' in %s",
+              this.conditional.id,
+              this.sourceFile));
+        }
+      }
+
+      // get the negation
+      if (this.negation != null) {
+        Annotation negationAnnotation = idAnnotationMap.get(this.negation.id);
+        if (negationAnnotation == null) {
+          throw new UnsupportedOperationException(String.format(
+              "no annotation with id '%s' in %s",
+              this.negation.id,
+              this.sourceFile));
+        }
       }
 
       // get the uncertainty
       if (this.uncertainty != null) {
-        Annotation uncertainty = idAnnotationMap.get(this.uncertainty.id);
-        if (uncertainty == null) {
+        Annotation uncertaintyAnnotation = idAnnotationMap.get(this.uncertainty.id);
+        if (uncertaintyAnnotation == null) {
           throw new UnsupportedOperationException(String.format(
               "no annotation with id '%s' in %s",
               this.uncertainty.id,
@@ -698,13 +1015,318 @@ public class SHARPKnowtatorXMLReader ext
 
     public DelayedFeature(ANNOTATION_TYPE annotation, KnowtatorAnnotation featureValue) {
       this.annotation = annotation;
-      this.featureValueID = featureValue.id;
+      this.featureValueID = featureValue == null ? null : featureValue.id;
+    }
+
+    public void setValueFrom(Map<String, ? extends Annotation> idAnnotationMap) {
+      if (this.featureValueID != null) {
+        this.setValue(idAnnotationMap.get(this.featureValueID));
+      }
+    }
+
+    protected abstract void setValue(Annotation valueAnnotation);
+  }
+  
+  private static class AlleviatingFactorFeature extends DelayedFeature<EntityMention> {
+    public AlleviatingFactorFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setAlleviatingFactor(...)
+    }
+  }
+
+  private static class AssociatedSignOrSymptomFeature extends DelayedFeature<EntityMention> {
+    public AssociatedSignOrSymptomFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
     }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setSignOrSymptom(...)
+    }
+  }
+  
+  private static class BodySideFeature extends DelayedFeature<EntityMention> {
+    public BodySideFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setBodySide(...)
+    }
+  }
 
-    public void setValueFrom(Map<String, ? extends TOP> idAnnotationMap) {
-      this.setValue(idAnnotationMap.get(this.featureValueID));
+  private static class BodyLateralityFeature extends DelayedFeature<EntityMention> {
+    public BodyLateralityFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setBodyLaterality(...)
+    }
+  }
+  
+  private static class BodyLocationFeature extends DelayedFeature<EntityMention> {
+    public BodyLocationFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setBodyLocation(...)
+    }
+  }
+  
+  private static class CourseFeature extends DelayedFeature<EntityMention> {
+    public CourseFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setCourse(...)
+    }
+  }
+
+  private static class ConditionalFeature extends DelayedFeature<EntityMention> {
+    public ConditionalFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setConditional(...)
+    }
+  }
+
+  private static class ExacerbatingFactorFeature extends DelayedFeature<EntityMention> {
+    public ExacerbatingFactorFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setExacerbatingFactor(...)
+    }
+  }
+
+  private static class GenericFeature extends DelayedFeature<EntityMention> {
+    public GenericFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setGeneric(...)
+    }
+  }
+  
+  private static class HistoryOfFeature extends DelayedFeature<EntityMention> {
+    public HistoryOfFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setHistoryOf(...)
+    }
+  }
+  
+  private static class LabOrdinalFeature extends DelayedFeature<EntityMention> {
+    public LabOrdinalFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setLabOrdinal(...)
+    }
+  }
+  
+  private static class LabReferenceRangeFeature extends DelayedFeature<EntityMention> {
+    public LabReferenceRangeFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setLabReferenceRange(...)
+    }
+  }
+  
+  private static class LabValueFeature extends DelayedFeature<EntityMention> {
+    public LabValueFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setLabValue(...)
+    }
+  }
+  
+  private static class MedicationAllergyFeature extends DelayedFeature<EntityMention> {
+    public MedicationAllergyFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setAllergy(...)
+    }
+  }
+
+  private static class MedicationDosageFeature extends DelayedFeature<EntityMention> {
+    public MedicationDosageFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setDosage(...)
+    }
+  }
+
+  private static class MedicationDurationFeature extends DelayedFeature<EntityMention> {
+    public MedicationDurationFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setDuration(...)
+    }
+  }
+
+  private static class MedicationFormFeature extends DelayedFeature<EntityMention> {
+    public MedicationFormFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setMedicationForm(...)
+    }
+  }
+  
+  private static class MedicationFrequencyFeature extends DelayedFeature<EntityMention> {
+    public MedicationFrequencyFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setFrequency(...)
+    }
+  }
+  
+  private static class MedicationRouteFeature extends DelayedFeature<EntityMention> {
+    public MedicationRouteFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setRoute(...)
+    }
+  }
+  
+  private static class MedicationStartDateFeature extends DelayedFeature<EntityMention> {
+    public MedicationStartDateFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setStartDate(...)
+    }
+  }
+  
+  private static class MedicationStatusChangeFeature extends DelayedFeature<EntityMention> {
+    public MedicationStatusChangeFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setMedicationStatusChange(...)
+    }
+  }
+  
+  private static class MedicationStrengthFeature extends DelayedFeature<EntityMention> {
+    public MedicationStrengthFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setMedicationStrength(...)
+    }
+  }
+
+  private static class NegationFeature extends DelayedFeature<EntityMention> {
+    public NegationFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setNegation(...)
+    }
+  }
+  
+  private static class ProcedureDeviceFeature extends DelayedFeature<EntityMention> {
+    public ProcedureDeviceFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setProcedureDevice(...)
+    }
+  }
+  
+  private static class ProcedureMethodFeature extends DelayedFeature<EntityMention> {
+    public ProcedureMethodFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setProcedureMethod(...)
+    }
+  }
+  
+  private static class SeverityFeature extends DelayedFeature<EntityMention> {
+    public SeverityFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setSeverity(...)
+    }
+  }
+  
+  private static class SubjectFeature extends DelayedFeature<EntityMention> {
+    public SubjectFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setSubject(...)
+    }
+  }
+  
+  private static class UncertaintyFeature extends DelayedFeature<EntityMention> {
+    public UncertaintyFeature(EntityMention entityMention, KnowtatorAnnotation value) {
+      super(entityMention, value);
+    }
+    @Override
+    protected void setValue(Annotation valueAnnotation) {
+      // TODO: this.annotation.setUncertainty(...)
+    }
+  }
+  
+  /**
+   * This main method is only for testing purposes. It runs the reader on Knowtator directories.
+   */
+  public static void main(String[] args) throws Exception {
+    if (args.length == 0) {
+      throw new IllegalArgumentException(String.format(
+          "usage: java %s path/to/Knowtator/text [path/to/Knowtator/text ...]",
+          SHARPKnowtatorXMLReader.class.getName()));
+    }
+    AnalysisEngine engine = AnalysisEngineFactory.createPrimitive(SHARPKnowtatorXMLReader.class);
+    for (String knowtatorTextDirectoryPath : args) {
+      File knowtatorTextDirectory = new File(knowtatorTextDirectoryPath);
+      for (File textFile : knowtatorTextDirectory.listFiles()) {
+        JCas jCas = engine.newJCas();
+        DocumentID documentID = new DocumentID(jCas);
+        documentID.setDocumentID(textFile.toURI().toString());
+        documentID.addToIndexes();
+        engine.process(jCas);
+      }
     }
 
-    protected abstract void setValue(TOP valueAnnotation);
   }
 }