/* * 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.impl; 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.RasterDatasetReader; import org.geotools.coverage.io.RasterDatasetWriter; import org.geotools.coverage.io.service.RasterService; 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>RasterStorage</code>s and * specific <code>RasterDataset</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 */ public class RasterIO{ /** 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 RasterIO() { } /** * 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 findService( final java.util.Map<String, Serializable> params, final boolean read, final Hints hints) { for (RasterService service : getAvailableServices()) { boolean canProcess = false; try { if(read) canProcess = service.canCreateReader(params,hints); else canProcess = service.canCreateWriter(params,hints); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error asking " + service.getTitle() + " if it can process request", t); // Protect against DataStores that don't carefully code // canProcess continue; } if (canProcess) { boolean isAvailable = false; try { isAvailable = service.isAvailable(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error when checking if " + service.getTitle() + " is available" , t); // Protect against Drivers that don't carefully code // isAvailable continue; } return true; } } return false; } public static RasterDatasetReader aquireReader( final Map<String, Serializable> parameters, final Hints hints, final ProgressListener listener)throws IOException{ for (RasterService service : getAvailableServices()) { boolean canProcess = false; try { canProcess = service.canCreateReader(parameters,hints); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error asking " + service.getTitle() + " if it can process request", t); // Protect against DataStores that don't carefully code // canProcess continue; } if (canProcess) { boolean isAvailable = false; try { isAvailable = service.isAvailable(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error when checking if " + service.getTitle() + " is available" , t); // Protect against Drivers that don't carefully code // isAvailable continue; } return service.createReader(parameters, hints, listener); } } return null; } public static RasterDatasetWriter aquireWriter( final Map<String, Serializable> parameters, final Hints hints, final ProgressListener listener)throws IOException{ for (RasterService service : getAvailableServices()) { boolean canProcess = false; try { canProcess = service.canCreateReader(parameters,hints); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error asking " + service.getTitle() + " if it can process request", t); // Protect against DataStores that don't carefully code // canProcess continue; } if (canProcess) { boolean isAvailable = false; try { isAvailable = service.isAvailable(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error when checking if " + service.getTitle() + " is available" , t); // Protect against Drivers that don't carefully code // isAvailable continue; } return service.createWriter(parameters, hints, listener); } } return null; } /** * Finds all available implementations of {@link RasterService} 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<RasterService> getAvailableServices() { // get all RasterService implementations scanForPlugins(); final Iterator<RasterService> it = getServiceRegistry().getServiceProviders(RasterService.class, true); final Set<RasterService> drivers = new HashSet<RasterService>(); while (it.hasNext()) { final RasterService spi = (RasterService) 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(RasterIO.class); if (registry == null) { registry = new FactoryCreator(Arrays.asList(new Class<?>[] { RasterService.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 RasterService} 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 RasterService} implementations. */ public static RasterService[] getAvailableDriversArray() { final Set<? extends RasterService> drivers = RasterIO.getAvailableServices(); final List<RasterService> driverSet = new ArrayList<RasterService>(drivers.size()); for (Iterator<? extends RasterService> iter = drivers.iterator(); iter.hasNext();) { final RasterService element = (RasterService) iter.next(); if (element.isAvailable()) driverSet.add(element); } return (RasterService[]) driverSet.toArray(new RasterService[driverSet.size()]); } /** * Returns all the {@link RasterService}s that can read the supplied {@link URL} url. * * @param url * is the object to search a {@link RasterService} that is able to read * @param read * @return an unmodifiable {@link Set} comprising all the {@link RasterService} that can read the * {@link URL} url. */ public static Set<RasterService> findServices( final URL url, final boolean read) { final Set<? extends RasterService> availaibleDrivers = RasterIO.getAvailableServices(); final Set<RasterService> drivers = new HashSet<RasterService>(); final Iterator<? extends RasterService> it = availaibleDrivers.iterator(); while (it.hasNext()) { // get the factory final RasterService spi = (RasterService) it.next(); // check if we can accept it Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); //is it available? if (!spi.isAvailable()) continue; try{ if(read) { if(spi.canCreateReader(params, null)) drivers.add(spi); } else{ if(spi.canCreateWriter(params, null)) drivers.add(spi); } }catch (Throwable e) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,e.getLocalizedMessage(),e); } } return Collections.unmodifiableSet(drivers); } /** * Returns a {@link RasterService} that is able to read a certain object. If no {@link RasterService} is able * to read such an {@link Object} we return an null object. * * @param url * the object to check for acceptance. * @return a {@link RasterService} that has stated to accept this {@link URL} o or <code>null</code> * in no plugins was able to accept it. */ public static RasterService findService( final URL url, final boolean read) { final Set<RasterService> drivers = findServices(url,read); final Iterator<RasterService> it = drivers.iterator(); if (it.hasNext()) return (RasterService) it.next(); return null; } }