All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.referencing.DefaultAuthorityFactory Maven / Gradle / Ivy

Go to download

Implementations of Coordinate Reference Systems (CRS), conversion and transformation services derived from ISO 19111.

There is a newer version: 3.20-geoapi-3.0
Show newest version
/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2006-2011, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2011, Geomatys
 *
 *    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.geotoolkit.referencing;

import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;
import javax.imageio.spi.ServiceRegistry;
import net.jcip.annotations.ThreadSafe;

import org.opengis.metadata.Identifier;
import org.opengis.util.FactoryException;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import org.geotoolkit.factory.Hints;
import org.geotoolkit.factory.AuthorityFactoryFinder;
import org.geotoolkit.factory.FactoryRegistryException;
import org.geotoolkit.internal.Citations;
import org.geotoolkit.referencing.crs.DefaultGeographicCRS;
import org.geotoolkit.referencing.factory.AllAuthoritiesFactory;
import org.geotoolkit.referencing.factory.MultiAuthoritiesFactory;
import org.geotoolkit.referencing.factory.CachingAuthorityFactory;
import org.geotoolkit.referencing.factory.FactoryDependencies;
import org.geotoolkit.internal.referencing.factory.ImplementationHints;
import org.geotoolkit.util.collection.UnmodifiableArrayList;
import org.geotoolkit.util.logging.Logging;
import org.geotoolkit.resources.Loggings;


/**
 * The default authority factory to be used by {@link CRS#decode}.
 * This class gathers together a lot of logic in order to capture the following ideas:
 * 

*

    *
  • Uses {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER} to swap ordinate order if needed.
  • *
  • Uses {@link AllAuthoritiesFactory} to select CRS Authorities from the code.
  • *
* * @author Martin Desruisseaux (IRD, Geomatys) * @author Andrea Aime (TOPP) * @version 3.16 * * @since 2.3 * @module */ @ThreadSafe final class DefaultAuthorityFactory extends CachingAuthorityFactory implements CRSAuthorityFactory { /** * List of codes without authority space. We can not defines them in an ordinary * authority factory. */ private static final List AUTHORITY_LESS = UnmodifiableArrayList.wrap( "WGS84(DD)" // (longitude,latitude) with decimal degrees. ); /** * The backing store of this factory. */ final MultiAuthoritiesFactory backingStore; /** * Creates a new authority factory. */ private DefaultAuthorityFactory(final MultiAuthoritiesFactory backingStore) { super(backingStore); this.backingStore = backingStore; } /** * Creates an instance of {@code DefaultAuthorityFactory}. This method first asks for the * list of all factories no matter how they handle the axis order hint, then substitutes * the factories by instances that are compliant with the axis order hint. */ static DefaultAuthorityFactory create(final boolean longitudeFirst) { /* * Get the CRS factories with no user hints (we will apply a filtering later), except * CRS_AUTHORITY_FACTORY because this hint will be overwritten in the loop below. We * don't want to supply the full set of hints because it would prevent the obtention * of factories that don't exist yet but could be derived from existing ones (see the * next comment block below). * * Note that EPSG_DATA_SOURCE is handled specially by the ThreadedEpsgFactory * constructor (see http://jira.geotoolkit.org/browse/GEOTK-159). */ final Hints systemHints = new Hints(); // Initialized to the system default. Hints hints = EMPTY_HINTS.clone(); // Initialized to an empty map. final Object userType = systemHints.get(Hints.CRS_AUTHORITY_FACTORY); if (userType != null) { hints.put(Hints.CRS_AUTHORITY_FACTORY, userType); } final List factories = new ArrayList( AuthorityFactoryFinder.getCRSAuthorityFactories(hints)); /* * Do not invoke FactoryRegistry.getServiceProviders() (which returns an Iterator over * all registered factories) because it doesn't create new instance. We want to create * new factory instances with the FORCE_LONGITUDE_FIRST_AXIS_ORDER hint set to TRUE if * needed. So instead, iterates over the default factories and derives factories from * them. */ hints = systemHints; final TypeFilter filter = new TypeFilter(); hints.put(AuthorityFactoryFinder.FILTER_KEY, filter); hints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, longitudeFirst); for (int i=factories.size(); --i>=0;) { CRSAuthorityFactory factory = factories.get(i); /* * Special case for factories having a hard-coded value for the "force longitude * first axis order" hint. Avoid the cost of querying the factory registry again, * because it may create a new connection to the database just for checking the * hints. */ final ImplementationHints hardHints = factory.getClass().getAnnotation(ImplementationHints.class); if (hardHints != null) { if (hardHints.forceLongitudeFirst() != longitudeFirst) { factories.remove(i); continue; } } /* * General case for factories that doesn't declare hard-coded hints. */ final String authority = Citations.getIdentifier(factory.getAuthority()); hints.put(Hints.CRS_AUTHORITY_FACTORY, filter.type = factory.getClass()); try { factory = AuthorityFactoryFinder.getCRSAuthorityFactory(authority, hints); } catch (FactoryRegistryException e) { /* * The factory does not accept to produce CRS in XY order. Remove it from the * list. Note that this exception does NOT remove the URN and HTTP factories * because they behave in a special way: they just ignore the hint (unless * FORCE_AXIS_ORDER_HONORING is set) instead than declaring that they can not * respect the hint. */ Logging.recoverableException(LOGGER, DefaultAuthorityFactory.class, "create", e); factories.remove(i); continue; } final CRSAuthorityFactory old = factories.set(i, factory); if (old != factory) { final LogRecord record = Loggings.format(Level.FINE, Loggings.Keys.FACTORY_REPLACED_FOR_AXIS_ORDER_$4, authority, factory.getClass(), old.getClass(), longitudeFirst ? 1 : 0); record.setSourceClassName(DefaultAuthorityFactory.class.getName()); record.setSourceMethodName("create"); record.setLoggerName(LOGGER.getName()); LOGGER.log(record); } } /* * At this point we have the list of factories that we want to use. Creates a * MultiAuthoritiesFactory which will use those factories. If all of them fail * for a given authority, then we will fallback on any factory registered in * AuthorityFactoryFinder without hints constraint except axis order. * * Note that the factories found above are override. If the above list contains * an EPSG factory, then AuthorityFactoryFinder will never be used for fetching * an EPSG factory. Consequently the EPSG factory used is constrained by the * hints computed at the beginning of this method. Only factories that would not * be available otherwise will be fetch by AuthorityFactoryFinder with no hints * constraint. */ hints.clear(); hints.put(AllAuthoritiesFactory.USER_FACTORIES_KEY, factories); hints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, longitudeFirst); final DefaultAuthorityFactory factory = new DefaultAuthorityFactory(AllAuthoritiesFactory.getInstance(hints)); factory.log(Level.CONFIG, longitudeFirst); return factory; } /** * Formats a tree of factory dependencies and sent it to the logger at the given level. * We use the logger from the {@link AuthorityFactoryFinder} package because this operation * is more related to factories management than referencing. */ private void log(final Level level, final boolean longitudeFirst) { final Logger logger = Logging.getLogger(AuthorityFactoryFinder.class); if (logger.isLoggable(level)) { final FactoryDependencies printer = new FactoryDependencies(this); printer.setAbridged(true); final LogRecord record = new LogRecord(level, "CRS.getAuthorityFactory(" + longitudeFirst +") creates:" + // TODO: localize System.getProperty("line.separator", "\n") + printer); record.setSourceClassName("org.geotoolkit.referencing.CRS"); record.setSourceMethodName("getAuthorityFactory"); record.setLoggerName(logger.getName()); logger.log(record); } } /** * The filter for requesting factories that are exactly of the given type. */ private static final class TypeFilter implements ServiceRegistry.Filter { /** * The requested factory type. Must be assigned by the caller. */ Class type; /** * Returns {@code true} if the given factory is exactly of the given type * (not a subclass). */ @Override public boolean filter(final Object provider) { return provider.getClass() == type; } } /** * Implementation of {@link CRS#getSupportedCodes}. Provided here in order to reduce the * amount of class loading when using {@link CRS} for other purpose than CRS decoding. */ static Set getSupportedCodes(final String authority) { final Set result = new LinkedHashSet(AUTHORITY_LESS); for (final CRSAuthorityFactory factory : AuthorityFactoryFinder.getCRSAuthorityFactories(null)) { if (Citations.identifierMatches(factory.getAuthority(), authority)) { final Set codes; try { codes = factory.getAuthorityCodes(CoordinateReferenceSystem.class); } catch (Exception exception) { /* * Failed to fetch the codes either because of a database connection problem * (FactoryException), or because we are using a simple factory that doesn't * support this operation (UnsupportedOperationException), or any unexpected * reason. No codes from this factory will be added to the set. */ CRS.unexpectedException("getSupportedCodes", exception); continue; } if (codes != null) { result.addAll(codes); } } } return result; } /** * Implementation of {@link CRS#getSupportedAuthorities}. Provided here in order to reduce the * amount of class loading when using {@link CRS} for other purpose than CRS decoding. */ static Set getSupportedAuthorities(final boolean returnAliases) { final Set result = new LinkedHashSet(); for (final CRSAuthorityFactory factory : AuthorityFactoryFinder.getCRSAuthorityFactories(null)) { for (final Identifier id : factory.getAuthority().getIdentifiers()) { result.add(id.getCode()); if (!returnAliases) { break; } } } return result; } /** * Returns the coordinate reference system for the given code. */ @Override public CoordinateReferenceSystem createCoordinateReferenceSystem(String code) throws FactoryException { if (code != null) { code = code.trim(); if (code.equalsIgnoreCase("WGS84(DD)")) { return DefaultGeographicCRS.WGS84; } } assert !AUTHORITY_LESS.contains(code) : code; return super.createCoordinateReferenceSystem(code); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy