/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2016, 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.imageio.netcdf.cv; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.factory.FactoryCreator; import org.geotools.factory.FactoryRegistry; import org.geotools.imageio.netcdf.cv.CoordinateHandlerSpi.CoordinateHandler; import org.geotools.util.logging.Logging; import ucar.nc2.dataset.CoordinateAxis; import ucar.nc2.dataset.CoordinateAxis1D; /** * Enable programs to find all available CoordinateHandler implementations. * * <p> * In order to be located by this finder modules must provide an implementation of * the {@link CoordinateHandlerSpi} interface. * </p> * * <p> * In addition to implementing this interface, this service file should be defined: * </p> * * <p> * <code>META-INF/services/org.geotools.imageio.netcdf.cv.CoordinateHandlerSpi</code> * </p> * * * <p> * Example:<br/> * <code>org.geotools.imageio.netcdf.cv.ClimatologicalTimeHandlerSPI</code> * </p> * * @author Daniele Romagnoli, GeoSolutions * */ public final class CoordinateHandlerFinder { private final static Logger LOGGER = Logging.getLogger(CoordinateHandlerFinder.class.toString()); /** * The service registry for this manager. Will be initialized only when first needed. */ private static FactoryRegistry registry; /** * Do not allows any instantiation of this class. */ private CoordinateHandlerFinder() { // singleton } /** * Finds all available implementations of {@link CoordinateHandlerSpi} * which have registered using the services mechanism. * * @return An unmodifiable {@link Set} of all discovered modules which * have registered factories */ public static synchronized Set<CoordinateHandlerSpi> getAvailableHandlers() { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Coordinate Handlers scan"); } // get all CoordinateHandlerSpi implementations scanForPlugins(); final Iterator<CoordinateHandlerSpi> it = getServiceRegistry().getServiceProviders( CoordinateHandlerSpi.class, true); final Set<CoordinateHandlerSpi> handlers = new HashSet<CoordinateHandlerSpi>(); while (it.hasNext()) { handlers.add(it.next()); } return Collections.unmodifiableSet(handlers); } /** * Returns the service registry. The registry will be created the first time this method is invoked. */ private static FactoryRegistry getServiceRegistry() { assert Thread.holdsLock(CoordinateHandlerFinder.class); if (registry == null) { registry = new FactoryCreator( Arrays.asList(new Class<?>[] { CoordinateHandlerSpi.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 * classpath 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 all the {@link CoordinateHandler}s that can handle the supplied {@link CoordinateAxis1D} axis. * * @param axis is the axis to search a {@link CoordinateHandler} that is able to handle * * @return an unmodifiable {@link Set} comprising all the {@link CoordinateHandler} * that can handle the {@link CoordinateAxis1D} axis. */ public static synchronized Set<CoordinateHandler> findHandlers(CoordinateAxis axis) { final Set<CoordinateHandlerSpi> availableHandlersSpi = getAvailableHandlers(); final Set<CoordinateHandler> handlers = new HashSet<CoordinateHandler>(); final Iterator<CoordinateHandlerSpi> it = availableHandlersSpi.iterator(); while (it.hasNext()) { // get the spi final CoordinateHandlerSpi spi = it.next(); // check if we can handle it if (spi.canHandle(axis)) { handlers.add(spi.createHandler()); } } return Collections.unmodifiableSet(handlers); } /** * Returns a {@link CoordinateHandler} that is able to handle a certain coordinate axis. * * @param axis the object to check for acceptance. */ public static synchronized CoordinateHandler findHandler(CoordinateAxis axis) { final Set<CoordinateHandler> formats = findHandlers(axis); final Iterator<CoordinateHandler> it = formats.iterator(); if (it.hasNext()) { return it.next(); } return null; } }