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.Collections;
025import java.util.Map;
026
027import org.biojava.utils.OverlayMap;
028
029/**
030 * <p>The BioDirectory Registry is a simple system for specifying
031 * where to find services which provide sequence databases. A client
032 * should look at the following places in order to find this file:</p>
033 *
034 * <pre>
035 *  $HOME/.bioinformatics/seqdatabase.ini
036 *  /etc/bioinformatics/seqdatabase.ini
037 *  http://www.open-bio.org/registry/seqdatabase.ini
038 * </pre>
039 *
040 * <p>The file is a simple stanza format</p>
041 *
042 * <pre>
043 *  [database-name]
044 *  tag=value
045 *  tag=value
046 *
047 *  [database-name]
048 *  tag=value
049 *  tag=value
050 * </pre>
051 * 
052 * <p>where each stanza starts with the declaration of the database
053 * being in square brackets and following that one line tag=value tag
054 * value formats.</p>
055 *
056 * <p>Database-name stanzas can be repeated, in which case the client
057 * should try each service in turn (starting at the first one).</p>
058 *
059 * <p>The options under each stanza must have two non-optional
060 * tag=value lines being</p>
061 *
062 * <pre>
063 *  protocol=&lt;protocol-type&gt;
064 *  location=&lt;location-string&gt;
065 * </pre>
066 *
067 * <p>'protocol' currently can be one of</p>
068 *
069 * <ul>
070 *  <li>flat</li>
071 *  <li>biofetch</li>
072 *  <li>biosql</li>
073 * </ul>
074 *
075 * <p>'location' is a string specific to the protocol. Any number of
076 * additional tag values are allowed in the stanza which should be
077 * passed to the appropiate constructor of the protocol to
078 * interpret. Some protocols might insist on other mandatory tags.</p>
079 *
080 * @author Brian Gilman
081 * @author Keith James
082 * @author Matthew Pocock
083 * @version $Revision$
084 */
085public interface RegistryConfiguration {
086  /**
087   * <code>getConfiguration</code> returns a mapping of registry
088   * database names to collections of tag-value pairs.
089   *
090   * @return a <code>Map</code>.
091   *
092   * @exception RegistryException if an error occurs.
093   */
094  public Map getConfiguration() throws RegistryException;
095  
096  /**
097   * <code>getConfigLocator</code> returns a locator for the
098   * configuration.
099   *
100   * @return a <code>String</code>.
101   */
102  public String getConfigLocator();
103  
104  /**
105   * A simple implementation of RegistryConfiguration backed by a Map.
106   *
107   * @author Brian Gilman
108   * @author Matthew Pocock
109   */
110  public static class Impl implements RegistryConfiguration {
111    private String configFileLocation = null;
112    private Map config = null;
113    
114    public Impl(String configFileLocation, Map config){
115      this.configFileLocation = configFileLocation;
116      this.config = config;
117    }
118
119    public Map getConfiguration() {
120      return config;
121    }
122
123    public String getConfigLocator() {
124      return configFileLocation;
125    }
126  }
127  
128  /**
129   * A RegistryConfiguration that allows you to treat other
130   * configurations as providing important or default configuration
131   * information.
132   *
133   * @author Matthew Pocock
134   */
135  public static class Composite
136  implements RegistryConfiguration {
137    private String configLocator;
138    private Map config;
139
140    public Composite() {
141    }
142
143    public Map getConfiguration() {
144      if(config == null) {
145        return Collections.EMPTY_MAP;
146      } else {
147        return config;
148      }
149    }
150
151    public String getConfigLocator() {
152      return configLocator;
153    }
154
155    /**
156     * Add a configuration as the most authoritative place to look.
157     * During future lookups with this context, values in newConfig
158     * will take precedence over values in the previously existing
159     * configuration.
160     *
161     * @param newConfig the RegistryConfiguration to add as most
162     * important
163     */
164    public void addTopConfig(RegistryConfiguration newConfig)
165    throws RegistryException {
166      Map cfg = newConfig.getConfiguration();
167      if(config == null) {
168        config = cfg;
169        configLocator = newConfig.getConfigLocator();
170      } else {
171        config = new OverlayMap(config, cfg);
172        configLocator = newConfig.getConfigLocator() + "::" + configLocator;
173      }
174    }
175
176    /**
177     * Add a configuration as the most default place to look. During
178     * future lookups with this context, values in newConfig will be
179     * used as default values only if the lookup would return nothing
180     * in the previously existing configuration.
181     *
182     * @param newConfig the RegistryConfiguration to add as the
183     * default
184     */
185    public void addBottomConfig(RegistryConfiguration newConfig)
186    throws RegistryException {
187      Map cfg = newConfig.getConfiguration();
188      if(config == null) {
189        config = cfg;
190        configLocator = newConfig.getConfigLocator();
191      } else {
192        config = new OverlayMap(cfg, config);
193        configLocator = configLocator + "::" + newConfig.getConfigLocator();
194      }
195    }
196  }
197}