001package org.biojava.bio.program.formats;
002
003import java.util.HashMap;
004import java.util.Iterator;
005import java.util.Map;
006
007import org.biojava.bio.BioException;
008import org.biojava.bio.EcNumber;
009import org.biojava.bio.program.tagvalue.ChangeTable;
010import org.biojava.bio.program.tagvalue.Formats;
011import org.biojava.bio.program.tagvalue.Parser;
012import org.biojava.utils.ClassTools;
013import org.biojava.utils.Services;
014import org.biojava.utils.lsid.LifeScienceIdentifier;
015import org.biojava.utils.lsid.LifeScienceIdentifierParseException;
016
017public class FormatTools {
018  private FormatTools() {}
019
020  private static Map LSID_2_FORMAT;
021
022  public static final ChangeTable.Changer EC_FROM_STRING =
023  new ChangeTable.Changer() {
024    public Object change(Object value) {
025      String sv = (String) value;
026      return EcNumber.Impl.valueOf(sv);
027    }
028  };
029
030  /**
031   * Attempt to find aformat for a format identifer string.
032   *
033   * <p>The string will be resolved in the following way:
034   * <ol>
035   * <li>Treat the name as an LSID and search for a format class with that
036   * LSID.</li>
037   * <li>Load a class of that name</li>
038   * <li>Load a class in the package
039   * <code>org.biojava.bio.program.formats</code> with that name</li>
040   * <li>Load a class in that package after replacing each '.' in the name with
041   * "$" so that a search is made of inner classes.</li>
042   * </ol>
043   * <p>
044   *
045   * <p>It is not specified if the format returned is a new instance or not.</p>
046   *
047   * This method uses the service providor framework to find format providers.
048   * If you add formats to the core biojava distribution, you must add the
049   * class name to the file <code>biojava-live/resources/META-INF/services/org.biojava.bio.program.formats.Format</code>/ If you implement formats and
050   * place them in your own .jar files, you should put the class name in a
051   * similarly named file in your jar. This should mean that the format becomes
052   * automatically registered with the system.
053   *
054   * @param formatName  the Stirng to use to find the format name
055   * @return a Format for that name
056   * @throws BioException if the format could not be resolved for some reason
057   */
058  public static Format getFormat(String formatName)
059  throws BioException {
060    // fixme: should use somethign better than BioException
061    // should probaby go via jndi
062
063    Format format = null;
064
065    try {
066      LifeScienceIdentifier lsid = LifeScienceIdentifier.valueOf(formatName);
067      Map lsidResolvers = getLsid2Format();
068      format = (Format) lsidResolvers.get(lsid);
069    } catch (LifeScienceIdentifierParseException e) {
070      // - it isn't an LSID I guess
071    }
072
073    if(format == null) {
074      Class formatClass = null;
075
076      try {
077        formatClass = ClassTools.getClassLoader(Parser.class).loadClass(formatName);
078      } catch (ClassNotFoundException cnfe1) {
079      }
080
081      if(formatClass == null) {
082        String fn = "org.biojava.bio.program.formats." +
083                    formatName;
084        try {
085          formatClass = ClassTools.getClassLoader(Parser.class).loadClass(fn);
086        } catch (ClassNotFoundException cnfe2) {
087        }
088      }
089
090      if(formatClass == null) {
091        String fn = "org.biojava.bio.program.formats." +
092                    formatName.replace('.', '$');
093        try {
094          formatClass = ClassTools.getClassLoader(Parser.class).loadClass(fn);
095        } catch (ClassNotFoundException cnfe2) {
096        }
097      }
098
099      if(formatClass != null) {
100        try {
101          format = (Format) formatClass.newInstance();
102        } catch (InstantiationException e) {
103          throw new BioException(
104            "Could not instantiate class for name " + formatName,e );
105        } catch (IllegalAccessException e) {
106          throw new BioException(
107            "Could not instantiate class for name " + formatName , e);
108        }
109      }
110    }
111
112    if(format == null) {
113      throw new BioException("Could not resolve format name: " + formatName);
114    }
115
116    return format;
117  }
118
119  private static Map getLsid2Format()
120  throws BioException {
121    if(LSID_2_FORMAT == null) {
122      try {
123        LSID_2_FORMAT = new HashMap();
124        ClassLoader loader = ClassTools.getClassLoader(Formats.class);
125
126        Iterator implNames = Services.getImplementationNames(
127          Format.class, loader ).iterator();
128
129        while(implNames.hasNext()) {
130          String name = (String) implNames.next();
131          Class clazz = loader.loadClass(name);
132          Format format = (Format) clazz.newInstance();
133          LSID_2_FORMAT.put(format.getLSID(), format);
134        }
135      } catch (Exception e) {
136        throw new BioException("Could not load service provider info for formats",e);
137      }
138    }
139
140    return LSID_2_FORMAT;
141  }
142}