001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002, 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: */
017: package org.geotools.coverage.grid.io;
018:
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Collections;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Set;
026:
027: import org.geotools.factory.FactoryCreator;
028: import org.geotools.factory.FactoryRegistry;
029: import org.opengis.coverage.grid.Format;
030: import org.opengis.coverage.grid.GridCoverage;
031:
032: /**
033: * Enable programs to find all available grid format implementations.
034: *
035: * <p>
036: * In order to be located by this finder datasources must provide an
037: * implementation of the {@link GridFormatFactorySpi} interface.
038: * </p>
039: *
040: * <p>
041: * In addition to implementing this interface datasouces should have a services
042: * file:<br/><code>META-INF/services/org.geotools.data.GridFormatFactorySpi</code>
043: * </p>
044: *
045: * <p>
046: * The file should contain a single line which gives the full name of the
047: * implementing class.
048: * </p>
049: *
050: * <p>
051: * Example:<br/><code>org.geotools.data.mytype.MyTypeDataStoreFacotry</code>
052: * </p>
053: *
054: * @source $URL:
055: * http://svn.geotools.org/geotools/trunk/gt/module/main/src/org/geotools/data/coverage/grid/GridFormatFinder.java $
056: */
057: public final class GridFormatFinder {
058: /**
059: * The service registry for this manager. Will be initialized only when
060: * first needed.
061: */
062: private static FactoryRegistry registry;
063:
064: /**
065: * Do not allows any instantiation of this class.
066: */
067: private GridFormatFinder() {
068: // singleton
069: }
070:
071: /**
072: * Finds all avalaible implementations of {@link GridFormatFactorySpi} which
073: * have registered using the services mechanism, and that have the
074: * appropriate libraries on the classpath.
075: *
076: * @return An unmodifiable {@link Set} of all discovered datastores which
077: * have registered factories, and whose available method returns
078: * true.
079: */
080: public static synchronized Set getAvailableFormats() {
081: // get all GridFormatFactorySpi implementations
082: scanForPlugins();
083: Iterator it = getServiceRegistry().getServiceProviders(
084: GridFormatFactorySpi.class, true);
085: final Set formats = new HashSet(5);
086: GridFormatFactorySpi spi;
087: while (it.hasNext()) {
088: spi = (GridFormatFactorySpi) it.next();
089: if (spi.isAvailable())
090: formats.add(spi);
091:
092: }
093: return Collections.unmodifiableSet(formats);
094: }
095:
096: /**
097: * Returns the service registry. The registry will be created the first time
098: * this method is invoked.
099: */
100: private static FactoryRegistry getServiceRegistry() {
101: assert Thread.holdsLock(GridFormatFinder.class);
102: if (registry == null) {
103: registry = new FactoryCreator(Arrays
104: .asList(new Class[] { GridFormatFactorySpi.class }));
105: }
106: return registry;
107: }
108:
109: /**
110: * Scans for factory plug-ins on the application class path. This method is
111: * needed because the application class path can theoretically change, or
112: * additional plug-ins may become available. Rather than re-scanning the
113: * classpath on every invocation of the API, the class path is scanned
114: * automatically only on the first invocation. Clients can call this method
115: * to prompt a re-scan. Thus this method need only be invoked by
116: * sophisticated applications which dynamically make new plug-ins available
117: * at runtime.
118: */
119: public static synchronized void scanForPlugins() {
120:
121: getServiceRegistry().scanForPlugins();
122:
123: }
124:
125: /**
126: * Returns an array with all available {@link GridFormatFactorySpi}
127: * implementations.
128: *
129: * <p>
130: * It can be used toget basic information about all the available
131: * {@link GridCoverage} plugins. Note that this method finds all the
132: * implemented plugins but returns only the availaible one.
133: *
134: * <p>
135: * A plugin could be implemented but not availaible due to missing
136: * dependencies.
137: *
138: *
139: * @return an array with all available {@link GridFormatFactorySpi}
140: * implementations.
141: */
142: public static Format[] getFormatArray() {
143: GridFormatFactorySpi element;
144: Set formats = GridFormatFinder.getAvailableFormats();
145: List formatSet = new ArrayList(formats.size());
146: for (Iterator iter = formats.iterator(); iter.hasNext();) {
147: element = (GridFormatFactorySpi) iter.next();
148: formatSet.add(element.createFormat());
149: }
150: return (Format[]) formatSet
151: .toArray(new Format[formatSet.size()]);
152: }
153:
154: /**
155: * Returns all the {@link Format}s that can read the supplied
156: * {@link Object} o.
157: *
158: * @param o
159: * is the object to search a {@link Format} that is able to read
160: * @return an unmodifiable {@link Set} comprising all the {@link Format}
161: * that can read the {@link Object} o.
162: */
163: public static synchronized Set findFormats(Object o) {
164: final Set availaibleFormats = getAvailableFormats();
165: final Set formats = new HashSet();
166: final Iterator it = availaibleFormats.iterator();
167: Format retVal = null;
168: GridFormatFactorySpi spi = null;
169: while (it.hasNext()) {
170: // get the factory
171: spi = (GridFormatFactorySpi) it.next();
172: // create a format for it
173: retVal = spi.createFormat();
174: // check if we can accept it
175: if (retVal instanceof AbstractGridFormat) {
176: if (((AbstractGridFormat) retVal).accepts(o))
177: formats.add(retVal);
178: }
179:
180: }
181:
182: return Collections.unmodifiableSet(formats);
183: }
184:
185: /**
186: * Returns a {@link Format} that is able to read a certain object. If no
187: * {@link Format} is able to read such an {@link Object} we return an
188: * {@link UnknownFormat} object.
189: *
190: * <p>
191: * It is worth to point out that this method will try to convert each format
192: * implementation to {@link AbstractGridFormat} because the original
193: * {@link Format} interface did not allow for an accept method hence we had
194: * to subclass the interface to add such method and we did so by the
195: * {@link AbstractGridFormat} abstract class.
196: *
197: * @param o
198: * the object to check for acceptance.
199: * @return an {@link AbstractGridFormat} that has stated to accept this
200: * {@link Object} o or <code>null</code> in no plugins was able to
201: * accept it.
202: */
203: public static synchronized Format findFormat(Object o) {
204: final Set formats = findFormats(o);
205: final Iterator it = formats.iterator();
206: if (it.hasNext())
207: return (Format) it.next();
208: return new UnknownFormat();
209:
210: }
211: }
|