code: package com.quui.tm2;
  
  import java.io.BufferedInputStream;
  import java.io.BufferedReader;
  import java.io.ByteArrayInputStream;
  import java.io.File;
  import java.io.FileNotFoundException;
  import java.io.FileReader;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.Serializable;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
  import java.math.BigInteger;
  import java.net.MalformedURLException;
  import java.net.URISyntaxException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.xml.stream.FactoryConfigurationError;
  import javax.xml.stream.XMLInputFactory;
  import javax.xml.stream.XMLStreamException;
  import javax.xml.stream.XMLStreamReader;
  import javax.xml.transform.Source;
  import javax.xml.transform.stream.StreamSource;
  import javax.xml.validation.Schema;
  import javax.xml.validation.SchemaFactory;
  import javax.xml.validation.Validator;
  
  import org.apache.commons.codec.binary.Base64;
  import org.xml.sax.ErrorHandler;
  import org.xml.sax.SAXException;
  import org.xml.sax.SAXParseException;
  
  /**
   * @author Fabian Steeg (fsteeg)
   */
  public/* yes? */class AnnotationReader {
      /***/
      private XMLStreamReader reader;
      /***/
      private String location;
      /***/
      private String data;
      private boolean validating;
  
      /**
       * @param location The location of the XML file containing the annotations
       *            to read
       */
      public AnnotationReader(final String location) {
          this.location = location;
          this.validating = true;
          init();
      }
  
      /**
     * 
     */
      private void init() {
          try {
              File f = new File(new URL(this.location).toURI());
              if (!f.exists()) {
                  throw new IllegalStateException("File does not exist: "
                          + this.location);
              }
              this.reader = createReader(this.location, validating);
          } catch (FileNotFoundException e) {
              e.printStackTrace();
          } catch (FactoryConfigurationError e) {
              e.printStackTrace();
          } catch (XMLStreamException e) {
              e.printStackTrace();
          } catch (MalformedURLException e) {
              e.printStackTrace();
          } catch (URISyntaxException e) {
              e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  
      /**
       * @param <T> The value type of the annotations to read
       * @param agentClass The class of the agent whose annotation to read
       * @return Returns the annotations that were written by the specified agent
       */
      public final <T extends Comparable<T> & Serializable> List<Annotation<T>> readAnnotations(
              final Class<? extends Agent<?, T>> agentClass) {
          init();
          List<Annotation<T>> result = new ArrayList<Annotation<T>>();
          try {
              boolean read = false;
              while (reader.hasNext()) {
                  if (reader.isStartElement()) {
                      if (reader.getLocalName().equals("agent")
                              && agentClass == null
                              || reader.getAttributeValue(0).equals(
                                      agentClass.getName())) {
                          /* We want to read the annotations of this agent: */
                          read = true;
                      }
                  }
                  if (reader.isStartElement()) {
                      /* And this is where we do it: */
                      if (reader.getLocalName().equals("a") && read) {
  
                          // old approach, when passing the class of T
                          // Class<T> tClass = new Class<T>();
                          /*
                           * What we'd want is something like: Class<T> tClass =
                           * T.class; to use further down when creating the
                           * annotation. But as generic types are not reified in
                           * Java, this is not possible. Instead... we find the
                           * generic interface implemented by our agent (as the
                           * types of subclasses or interface implementations of
                           * generic classes or interfaces are reifiable):
                           */
                          // Type[] genericInterfaces =
                          // agentClass.getGenericInterfaces();
                          @SuppressWarnings("unchecked")
  						Class<T> annotationClass = getAgentClass(agentClass);
                          /*
                           * This class object is then used to instantiate a
                           * type-safe annotation object from the XML file
                           */
                          /*
                           * To instantiate an annotation object from the XML, the
                           * value of an annotation needs to have a constructor
                           * with a single String parameter (as common Java
                           * classes like String, Integer and Double have)
                           */
  
                          String attributeValue = reader.getAttributeValue("",
                                  "object");
                          T value = null;
                          /*
                           * If we have a serialized form, we instantiate from
                           * that:
                           */
                          if (attributeValue != null) {
                              /*
                               * Using decode(...) non-qualified/generic here does
                               * not work; it does compile fine in Eclipse, but
                               * not with current Sun Java; cf.
                               */
                              // https://bugs.eclipse.org/bugs/show_bug.cgi?id=98379
                              // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
                              value = this.<T> decode(attributeValue);
                          } else {
                              /*
                               * Else, we try to instantiate from the string
                               * representation, using the string constructor
                               * (this works by default for the data types
                               * included in Java, like String, Integer, etc.)
                               */
                              attributeValue = reader.getAttributeValue("", //$NON-NLS-1$
                                      "label");
                              Constructor<T> constructor = annotationClass
                                      .getConstructor(String.class);
                              if (constructor == null) {
                                  /*
                                   * TODO Is there any way to enforce this at
                                   * compile time? We can't demand an interface,
                                   * as we want library classes as String, Double
                                   * etc. to be supported...
                                   */
                                  throw new IllegalArgumentException(
                                          "Can't instantiate annotation value of type "
                                                  + annotationClass
                                                  + ": does not have a constructor taking a single string");
                              }
                              value = constructor.newInstance(attributeValue);
                          }
                          Annotation<T> annotation = null;
                          try {
                              annotation = ImmutableAnnotation
                                      .getInstance(agentClass, value,
                                              new BigInteger(reader
                                                      .getAttributeValue(0)),
                                              new BigInteger(reader
                                                      .getAttributeValue(1)));
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                          result.add(annotation);
                      }
                  }
                  if (reader.isStartElement()
                          && reader.getLocalName().equals("agent")
                          && !reader.getAttributeValue(0).equals(
                                  agentClass.getName()) && read) {
                      /* We only read annotation for one agent in one go: */
                      return result;
                  }
                  reader.next();
              }
          } catch (XMLStreamException e) {
              e.printStackTrace();
          } catch (SecurityException e) {
              e.printStackTrace();
          } catch (NoSuchMethodException e) {
              e.printStackTrace();
          } catch (IllegalArgumentException e) {
              e.printStackTrace();
          } catch (InstantiationException e) {
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              e.printStackTrace();
          } catch (InvocationTargetException e) {
              e.printStackTrace();
          }
          return result;
      }
  
  	static <T extends Comparable<T> & Serializable> Class<T> getAgentClass(final Class<? extends Agent<?, T>> agentClass) {
  		/*
  		 * TODO we need to search for the interface in the type
  		 * hierarchy... or supply a method that does let you
  		 * specify the classes...
  		 */
  		Type agentInterface = findAgentInterface(agentClass);
  		if(agentInterface==null){
  			 Exception e = new IllegalArgumentException(
               "Only direct implementations of the Agent interface are supported!");
  			 System.err.println(e.getMessage());
         return null;
  		}
  
  		/*
  		 * If we are a skeletal implementation and no direct
  		 * implementor, get the superclasses interface TODO this
  		 * is not very robust... what if the implementor does
  		 * implement some other interface? We should check if it
  		 * is the agent interface... and it is not even working
  		 * like this...
  		 */
  
  		/* We have only one interface: */
  		ParameterizedType t = (ParameterizedType) agentInterface;
  		/* The second parameter is the agent's output: */
  		Type output = t.getActualTypeArguments()[1];
  		/* ...and that must be a class of T: */
  		/*
  		 * This one unsafe cast is the price we pay for cutting
  		 * the redundancy of supplying the class as a parameter;
  		 * but this should not ever go wrong, as we get it from
  		 * the original class... T is the second parameter of
  		 * the given agent class, then we get the second actual
  		 * parameter above, so now we can cast it to a class of
  		 * T:
  		 */
  		@SuppressWarnings("unchecked") Class<T> annotationClass = (Class<T>) output;
  		return annotationClass;
  	}
  
      /**
       * @param <T> The type of the object to be desialized
       * @param string The serialized, Base64 encoded form of the object
       * @return Retruns an instance of type T created from the serialized form
       */
      private <T> T decode(final String string) {
          if (string == null) {
              throw new NullPointerException("Can't decode a null string;");
          }
          try {
              byte[] decodeBuffer = Base64.decodeBase64(string.getBytes());
              ObjectInputStream inStream = new ObjectInputStream(
                      new BufferedInputStream(new ByteArrayInputStream(
                              decodeBuffer)));
              /*
               * We only read annotations produced by the agent producing type T,
               * so at this point the serialized form must be of type T
               */
              @SuppressWarnings("unchecked") T value = (T) inStream.readObject();
              return value;
          } catch (IOException e) {
              e.printStackTrace();
          } catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
          throw new IllegalStateException("Could not deserialize value object");
      }
  
      /**
       * @param <T> The type created by the agent
       * @param agentClass The concrete agent class
       * @return Returns the type created by the given agent
       */
      public static <T extends Comparable<T> & Serializable> Type findAgentInterface(
              final Class<? extends Agent<?, T>> agentClass) {
          Type[] genericInterfaces = agentClass.getGenericInterfaces();
          if (genericInterfaces.length < 1) {
          	return null;
          }
          for (Type type : genericInterfaces) {
            if(type.toString().contains(Agent.class.getName()))
              return type;
          }
          // FIXME does not work for agents that implement Agent indirectly, impl rec. search?
          IllegalStateException e = new IllegalStateException("No agent interface found for: " + agentClass);
          System.err.println(e.getMessage());
          return null;
      }
  
      /**
       * @return Returns a list of all agents that wrote Annotations
       */
      public final List<String> readAgents() {
          init();
          List<String> result = new ArrayList<String>();
          try {
              while (this.reader.hasNext()) {
                  if (reader.isStartElement()) {
                      if (reader.getLocalName().equals("agent")) {
                          result.add(reader.getAttributeValue(0));
                      }
                  }
                  reader.next();
              }
          } catch (XMLStreamException e) {
              e.printStackTrace();
          } catch (SecurityException e) {
              e.printStackTrace();
          } catch (IllegalArgumentException e) {
              e.printStackTrace();
          }
          return result;
  
      }
  
      /**
       * @param fileLocation The location of the annotations file
       * @param validating
       * @return Returns the reader for the location
       * @throws XMLStreamException while reading
       * @throws URISyntaxException
       * @throws IOException
       */
      private XMLStreamReader createReader(final String fileLocation,
              boolean validating) throws XMLStreamException, URISyntaxException,
              IOException {
          BufferedReader bufferedReader = new BufferedReader(new FileReader(
                  new File(new URL(fileLocation).toURI())));
          XMLInputFactory factory = XMLInputFactory.newInstance();
  
          factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,
                  Boolean.FALSE);
  
          SchemaFactory schemaFactory = SchemaFactory
                  .newInstance("http://www.w3.org/2001/XMLSchema");
  
          Source source = new StreamSource(new URL(fileLocation).openStream());
  
          XMLStreamReader newReader;
          System.setProperty("javax.xml.stream.isCoalescing", "true");
          newReader = factory.createXMLStreamReader(source);
  
          if (validating) {
              try {
                  URL resource = this.getClass().getResource("tm2.xsd");
                  if (resource == null) {
                      throw new IllegalStateException("Could not load XSD");
                  }
                  Schema schemaGrammar = schemaFactory.newSchema(resource);
  
                  Validator schemaValidator = schemaGrammar.newValidator();
                  schemaValidator.setErrorHandler(new ErrorHandler() {
  
  					public void warning(SAXParseException exception)
  							throws SAXException {
  						System.out.println(exception.getMessage());
  					}
  
                      public void fatalError(SAXParseException exception)
                              throws SAXException {
                      	System.out.println(exception.getMessage());
                      }
  
                      public void error(SAXParseException exception)
                              throws SAXException {
                      	System.out.println(exception.getMessage());
                      }
                  });
                  schemaValidator.validate(new StreamSource(bufferedReader));
              } catch (SAXException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
          while (newReader.hasNext()) {
              if (newReader.isStartElement()) {
                  if (newReader.getLocalName().equals("experiment")) {
                      this.data = newReader.getAttributeValue(0);
                      return newReader;
                  }
              }
              newReader.next();
          }
          return newReader;
      }
  
      /**
       * @return Returns the data, the actual XML string of annotations
       */
      public final String getData() {
          // TODO We should find a different solution for this
          return data;
      }
  
  }
  