001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022package org.biojava.directory;
023
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027
028import org.biojava.bio.BioException;
029import org.biojava.bio.seq.db.SequenceDBLite;
030import org.biojava.utils.ClassTools;
031import org.biojava.utils.Services;
032
033/**
034 * <p><code>Registry</code> is a factory which gets implementations of
035 * the BioJava <code>SequenceDBLite</code> interface. This is the
036 * point of entry for OBDA access.</p>
037 *
038 * @author Brian Gilman
039 * @author Thomas Down
040 * @author Keith James
041 *
042 * @version $Revision$
043 */
044public class Registry {
045
046    /**
047     * Registry Configuration instance
048     */
049    private RegistryConfiguration regConfig = null;
050
051    /**
052     * Creates a new OBDA <code>Registry</code> with the specified
053     * configuration.
054     *
055     * @param regConfig a <code>RegistryConfiguration</code>.
056     */
057    public Registry(RegistryConfiguration regConfig) {
058        this.regConfig = regConfig;
059    }
060
061    /**
062     * <code>getDatabase</code> retrieves a database instance known by
063     * a name <code>String</code>.
064     *
065     * @param dbName a <code>String</code> database name.
066     *
067     * @return a <code>SequenceDBLite</code>.
068     *
069     * @exception RegistryException if the registry does not contain a
070     * configuration for the specified name.
071     * @exception BioException if the provider fails.
072     */
073    public SequenceDBLite getDatabase(String dbName)
074        throws RegistryException, BioException {
075
076        String providerName = "";
077
078        List dbConfigs =
079            (List) getRegistryConfiguration().getConfiguration().get(dbName);
080
081        if (dbConfigs == null) {
082            throw new RegistryException("Failed to find a configuration"
083                                        + " for database: "
084                                        + dbName);
085        }
086
087        for (Iterator ci = dbConfigs.iterator(); ci.hasNext();) {
088            Map dbConfig = (Map) ci.next();
089            providerName = (String) dbConfig.get("protocol");
090
091            SequenceDBLite db = null;
092            try {
093                db = getProvider(providerName).getSequenceDB(dbConfig);
094            } catch (RegistryException re) {
095                // We allow RegistryExceptions to cause a fallback to
096                // an alternative provider in the same config
097                continue;
098            }
099            catch (Exception e) {
100                // But more serious exceptions cause a failure
101                throw new RegistryException("Failed to configure database "
102                                            + dbName);
103            }
104
105            if (db != null)
106                return db;
107        }
108
109        throw new RegistryException("Failed to find a configuration"
110                                    + " for database: "
111                                    + dbName);
112    }
113
114    private SequenceDBProvider getProvider(String providerName)
115        throws RegistryException {
116        try {
117            ClassLoader loader = ClassTools.getClassLoader(this);
118            Iterator implNames =
119                Services.getImplementationNames(SequenceDBProvider.class, loader).iterator();
120
121            while (implNames.hasNext()) {
122              String className = (String) implNames.next();
123              try {
124                Class clazz = loader.loadClass(className);
125                SequenceDBProvider seqDB =
126                    (SequenceDBProvider) clazz.newInstance();
127                if (seqDB.getName().equals(providerName)) {
128                    return seqDB;
129                }
130              } catch (ClassNotFoundException ce) {
131                throw new RegistryException(
132                  "Could not find class: " + className +
133                  " for service provider " + providerName, ce
134                );
135              }
136            }
137
138            throw new ProviderNotFoundException("No such provider exists: "
139                                                + providerName);
140        } catch (Exception e) {
141            throw new RegistryException("Error accessing"
142                                        + " SequenceDBProvider services",e);
143        }
144    }
145
146    /**
147     * <code>getRegistryConfiguration</code> returns the configuration
148     * of the registry.
149     *
150     * @return a <code>RegistryConfiguration</code>.
151     */
152    public RegistryConfiguration getRegistryConfiguration() {
153        return this.regConfig;
154    }
155}