001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.data;
017:
018: import java.io.IOException;
019: import java.util.Arrays;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.Map;
023: import java.util.Set;
024: import java.util.logging.Level;
025: import java.util.logging.Logger;
026:
027: import org.geotools.factory.FactoryCreator;
028: import org.geotools.factory.FactoryRegistry;
029:
030: /**
031: * Enable programs to find all available datastore implementations.
032: *
033: * <p>
034: * In order to be located by this finder datasources must provide an
035: * implementation of the {@link DataStoreFactorySpi} interface.
036: * </p>
037: *
038: * <p>
039: * In addition to implementing this interface datasouces should have a services
040: * file:<br/><code>META-INF/services/org.geotools.data.DataStoreFactorySpi</code>
041: * </p>
042: *
043: * <p>
044: * The file should contain a single line which gives the full name of the
045: * implementing class.
046: * </p>
047: *
048: * <p>
049: * Example:<br/><code>org.geotools.data.mytype.MyTypeDataStoreFacotry</code>
050: * </p>
051: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/DataStoreFinder.java $
052: */
053: public final class DataStoreFinder {
054: /** The logger for the filter module. */
055: protected static final Logger LOGGER = org.geotools.util.logging.Logging
056: .getLogger("org.geotools.data");
057:
058: /**
059: * The service registry for this manager. Will be initialized only when
060: * first needed.
061: */
062: private static FactoryRegistry registry;
063:
064: //Singleton pattern
065: private DataStoreFinder() {
066: }
067:
068: /**
069: * Checks each available datasource implementation in turn and returns the
070: * first one which claims to support the resource identified by the params
071: * object.
072: *
073: * @param params A Map object which contains a defenition of the resource
074: * to connect to. for file based resources the property 'url'
075: * should be set within this Map.
076: *
077: * @return The first datasource which claims to process the required
078: * resource, returns null if none can be found.
079: *
080: * @throws IOException If a suitable loader can be found, but it can not be
081: * attached to the specified resource without errors.
082: */
083: public static synchronized DataStore getDataStore(Map params)
084: throws IOException {
085: Iterator ps = getAvailableDataStores();
086: DataStoreFactorySpi fac;
087: while (ps.hasNext()) {
088: fac = (DataStoreFactorySpi) ps.next();
089:
090: try {
091: if (fac.canProcess(params)) {
092: return fac.createDataStore(params);
093: }
094: } catch (Throwable t) {
095: /** The logger for the filter module. */
096: LOGGER.log(Level.WARNING, "Could not acquire "
097: + fac.getDescription() + ":" + t, t);
098: // Protect against DataStores that don't carefully
099: // code canProcess
100:
101: }
102: }
103:
104: return null;
105: }
106:
107: /**
108: * Finds all implemtaions of DataStoreFactory which have registered using
109: * the services mechanism, and that have the appropriate libraries on the
110: * classpath.
111: *
112: * @return An iterator over all discovered datastores which have registered
113: * factories, and whose available method returns true.
114: */
115: public static synchronized Iterator getAvailableDataStores() {
116: Set availableDS = new HashSet(5);
117: Iterator it = getServiceRegistry().getServiceProviders(
118: DataStoreFactorySpi.class);
119: DataStoreFactorySpi dsFactory;
120: while (it.hasNext()) {
121: dsFactory = (DataStoreFactorySpi) it.next();
122:
123: if (dsFactory.isAvailable()) {
124: availableDS.add(dsFactory);
125: }
126: }
127:
128: return availableDS.iterator();
129: }
130:
131: /**
132: * Returns the service registry. The registry will be created the first time
133: * this method is invoked.
134: */
135: private static FactoryRegistry getServiceRegistry() {
136: assert Thread.holdsLock(DataStoreFinder.class);
137: if (registry == null) {
138: registry = new FactoryCreator(Arrays
139: .asList(new Class[] { DataStoreFactorySpi.class }));
140: }
141: return registry;
142: }
143:
144: /**
145: * Scans for factory plug-ins on the application class path. This method is
146: * needed because the application class path can theoretically change, or
147: * additional plug-ins may become available. Rather than re-scanning the
148: * classpath on every invocation of the API, the class path is scanned
149: * automatically only on the first invocation. Clients can call this method
150: * to prompt a re-scan. Thus this method need only be invoked by
151: * sophisticated applications which dynamically make new plug-ins available
152: * at runtime.
153: */
154: public static synchronized void scanForPlugins() {
155:
156: getServiceRegistry().scanForPlugins();
157:
158: }
159: }
|