code: package com.quui.tm2.ui;
  
  import java.io.Serializable;
  import java.util.List;
  
  import com.quui.tm2.Agent;
  import com.quui.tm2.Annotation;
  import com.quui.tm2.Retrieval;
  
  public class ConsoleRetrieval {
    private static final String SYNTAX = "Synatx: file [ list (agent) | find \"term\" agent1 agent2]";
  
    public static void main(String[] args) {
      if (args.length < 2) {
        System.out.println(SYNTAX);
        System.exit(-1);
      }
      Retrieval r = new Retrieval(args[0]);
      if (args[1].equals("list")) {
        if (args.length == 2) {
          System.out.println("Available agents:");
          List<String> agents = r.getAgents();
          for (String string : agents) {
            System.out.println(string);
          }
        } else {
          System.out.println("Annotations for agent " + args[2] + ":");
          List<Annotation<String>> annotations = getAnnotations(args[2], r);
          for (Annotation<String> annotation : annotations) {
            System.out.println(annotation.getValue());
          }
        }
      } else if (args[1].equals("find")) {
        if (args.length < 5) {
          System.out.println(SYNTAX);
          System.exit(-1);
        }
        List<Annotation<String>> search = search(args[3], args[2], args[4], r);
        System.out.println("Annotations of " + args[3] + " matching '" + args[2]
            + "' by " + args[4]);
        boolean context = true;
        for (Annotation<String> annotation : search) {
          System.out.println(annotation.getValue()
              + (context ? " in context: " + context(annotation, 20, r.getData())
                  : ""));
        }
      } else {
        System.out.println(SYNTAX);
      }
    }
  
    public static <T extends Comparable<T> & Serializable> List<Annotation<T>> getAnnotations(
        String agentName, Retrieval r) {
      List<Annotation<T>> l;
      Class<? extends Agent<?, T>> agentClass = null;
      try {
        /* TODO Can we avoid this cast? I don't think so. */
        agentClass = (Class<? extends Agent<?, T>>) Class.forName(agentName);
      } catch (ClassNotFoundException e) {
        throw wrap(agentName, e);
      }
      if (agentClass != null) {
        l = r.annotationsOf(agentClass);
        return l;
      }
      return null;
    }
  
    public static <S extends Comparable<S> & Serializable, R extends Comparable<R> & Serializable> List<Annotation<R>> search(
        String searchIn, S searchValue, String returnFrom, Retrieval r) {
      /* TODO test this for non-string-producing agents */
      Class<Agent<?, S>> searchInC = reflectiveInstantiation(searchIn);
      Class<Agent<?, R>> returnFromC = reflectiveInstantiation(returnFrom);
      List<Annotation<R>> result = r.search(searchInC, searchValue, returnFromC);
      return result;
    }
  
    private static <T extends Comparable<T> & Serializable> Class<Agent<?, T>> reflectiveInstantiation(
        String agentName) {
      try {
        /* TODO Can we avoid this cast? I don't think so. */
        return (Class<Agent<?, T>>) Class.forName(agentName);
      } catch (ClassNotFoundException e) {
        throw wrap(agentName, e);
      }
    }
  
    private static String context(Annotation<?> annotation, int window,
        String data) {
      String result = data.substring(Math.max(annotation.getStart().intValue()
          - window, 0), annotation.getStart().intValue())
          + "["
          + data.substring(annotation.getStart().intValue(), annotation.getEnd()
              .intValue())
          + "]"
          + data.substring(annotation.getEnd().intValue(), Math.min(annotation
              .getEnd().intValue()
              + window, data.length() - 1));
      return "..." + result + "...";
    }
  
    private static IllegalArgumentException wrap(String name,
        ClassNotFoundException e) {
      IllegalArgumentException exception = new IllegalArgumentException(
          "Unknown Agent: " + name);
      exception.initCause(e);
      return exception;
    }
  }
  