/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.coverage.io.driver; import java.io.IOException; import java.io.Serializable; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.coverage.io.CoverageAccess; import org.geotools.coverage.io.driver.Driver.DriverOperation; import org.geotools.factory.FactoryCreator; import org.geotools.factory.FactoryRegistry; import org.geotools.factory.Hints; import org.opengis.coverage.grid.GridCoverage; import org.opengis.util.ProgressListener; /** * A class containing static convenience methods for locating <code>CoverageAccess</code>s and * specific <code>CoverageSource</code>s, and performing simple encoding and decoding. * * * @author Simone Giannecchini, GeoSolutions * @author Jody Garnett * @todo add caching mechanism * @todo add method for removing and creating connections to access * @todo fix javadocs * * * @source $URL: http://svn.osgeo.org/geotools/trunk/modules/unsupported/coverage-experiment/coverage-api/src/main/java/org/geotools/coverage/io/driver/CoverageIO.java $ */ public class CoverageIO{ /** The {@link Logger}. */ private static final Logger LOGGER = org.geotools.util.logging.Logging .getLogger("org.geotools.coverage.io"); /** * The service registry for this manager. Will be initialized only when first needed. */ private static FactoryRegistry registry; /** * Private constructor, this class cannot be instantiated nor subclassed. */ private CoverageIO() { } /** * Test to see if this factory is suitable for processing the data pointed to by the params map. * * <p> * If this datasource requires a number of parameters then this method should check that they * are all present and that they are all valid. If the datasource is a file reading data source * then the extensions or mime types of any files specified should be checked. For example, a * Shapefile datasource should check that the url param ends with shp, such tests should be case * insensitive. * </p> * * @param params * The full set of information needed to construct a live data source. * * @return boolean true if and only if this factory can process the resource indicated by the * param set and all the required params are present. */ public static boolean canConnect(java.util.Map<String, Serializable> params) { for (Driver driver : getAvailableDrivers()) { boolean canProcess = false; try { canProcess = driver.canProcess(DriverOperation.CONNECT,params); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error asking " + driver.getTitle() + " if it can process request", t); // Protect against DataStores that don't carefully code // canProcess continue; } if (canProcess) { boolean isAvailable = false; try { isAvailable = driver.isAvailable(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error when checking if " + driver.getTitle() + " is available" , t); // Protect against Drivers that don't carefully code // isAvailable continue; } if (isAvailable) { try { if( driver.canProcess(DriverOperation.CONNECT,params)) return true; } catch (Exception couldNotConnect) { LOGGER.log(Level.WARNING, driver.getTitle() + " could not connect", couldNotConnect); } } } } return false; } public static CoverageAccess connect(Map<String, Serializable> params,Hints hints, final ProgressListener listener)throws IOException{ for (Driver driver : getAvailableDrivers()) { boolean canProcess = false; try { canProcess = driver.canProcess(DriverOperation.CONNECT,params); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error asking " + driver.getTitle() + " if it can process request", t); // Protect against DataStores that don't carefully code // canProcess continue; } if (canProcess) { boolean isAvailable = false; try { isAvailable = driver.isAvailable(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error when checking if " + driver.getTitle() + " is available" , t); // Protect against Drivers that don't carefully code // isAvailable continue; } if (isAvailable) { try { return driver.process(DriverOperation.CONNECT,params, hints, listener); } catch (IOException couldNotConnect) { LOGGER.log(Level.WARNING, driver.getTitle() + " could not connect", couldNotConnect); } } } } return null; } public static CoverageAccess connect(Map<String, Serializable> params) throws IOException { return CoverageIO.connect(params,null,null); } /** * Finds all available implementations of {@link Driver} which have registered using the * services mechanism, and that have the appropriate libraries on the class-path. * * @return An unmodifiable {@link Set} of all discovered drivers which have registered * factories, and whose available method returns true. */ public static synchronized Set<Driver> getAvailableDrivers() { // get all Driver implementations scanForPlugins(); final Iterator<Driver> it = getServiceRegistry().getServiceProviders(Driver.class, false); final Set<Driver> drivers = new HashSet<Driver>(); while (it.hasNext()) { final Driver spi = (Driver) it.next(); if (spi.isAvailable()) drivers.add(spi); } return Collections.unmodifiableSet(drivers); } /** * Returns the service registry. The registry will be created the first time this method is * invoked. */ private static FactoryRegistry getServiceRegistry() { assert Thread.holdsLock(CoverageIO.class); if (registry == null) { registry = new FactoryCreator(Arrays.asList(new Class<?>[] { Driver.class })); } return registry; } /** * Scans for factory plug-ins on the application class path. This method is needed because the * application class path can theoretically change, or additional plug-ins may become available. * Rather than re-scanning the class-path on every invocation of the API, the class path is * scanned automatically only on the first invocation. Clients can call this method to prompt a * re-scan. Thus this method need only be invoked by sophisticated applications which * dynamically make new plug-ins available at runtime. */ public static synchronized void scanForPlugins() { getServiceRegistry().scanForPlugins(); } /** * Returns an array with all available {@link Driver} implementations. * * <p> * It can be used together basic information about all the available {@link GridCoverage} * plugins. Note that this method finds all the implemented plugins but returns only the * available one. * * <p> * A plugin could be implemented but not available due to missing dependencies. * * * @return an array with all available {@link Driver} implementations. */ public static Driver[] getAvailableDriversArray() { final Set<? extends Driver> drivers = CoverageIO.getAvailableDrivers(); final List<Driver> driverSet = new ArrayList<Driver>(drivers.size()); for (Iterator<? extends Driver> iter = drivers.iterator(); iter.hasNext();) { final Driver element = (Driver) iter.next(); if (element.isAvailable()) driverSet.add(element); } return (Driver[]) driverSet.toArray(new Driver[driverSet.size()]); } /** * Returns all the {@link Driver}s that can read the supplied {@link URL} url. * * @param url * is the object to search a {@link Driver} that is able to read * @return an unmodifiable {@link Set} comprising all the {@link Driver} that can read the * {@link URL} url. */ public static Set<Driver> findDrivers(URL url) { final Set<? extends Driver> availaibleDrivers = CoverageIO.getAvailableDrivers(); final Set<Driver> drivers = new HashSet<Driver>(); final Iterator<? extends Driver> it = availaibleDrivers.iterator(); while (it.hasNext()) { // get the factory final Driver spi = (Driver) it.next(); // check if we can accept it Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); if (spi.isAvailable() && spi.canProcess(DriverOperation.CONNECT,params)) drivers.add(spi); } return Collections.unmodifiableSet(drivers); } /** * Returns a {@link Driver} that is able to read a certain object. If no {@link Driver} is able * to read such an {@link Object} we return an null object. * * @param url * the object to check for acceptance. * @return a {@link Driver} that has stated to accept this {@link URL} o or <code>null</code> * in no plugins was able to accept it. */ public static Driver findDriver(URL url) { final Set<Driver> drivers = findDrivers(url); final Iterator<Driver> it = drivers.iterator(); if (it.hasNext()) return (Driver) it.next(); return null; } }