/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-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.referencing.factory; import java.util.Set; import java.util.Iterator; import java.util.Collection; import java.util.LinkedHashSet; import java.util.logging.Level; import java.util.logging.LogRecord; import javax.measure.unit.Unit; import org.opengis.referencing.cs.*; import org.opengis.referencing.crs.*; import org.opengis.referencing.datum.*; import org.opengis.referencing.operation.*; import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.AuthorityFactory; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.metadata.extent.Extent; import org.opengis.parameter.ParameterDescriptor; import org.opengis.util.InternationalString; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Loggings; import org.geotools.resources.i18n.LoggingKeys; import org.geotools.factory.FactoryNotFoundException; /** * A factory which delegates all object creation to a <cite>primary</cite> factory, * and fallback on an other one if the primary factory failed. * * @since 2.3 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux * * @todo Needs a mechanism for avoiding to query the same factory twice when the fallback is the * same instance than the primary factory for some {@link AuthorityFactory} interfaces. */ public class FallbackAuthorityFactory extends AuthorityFactoryAdapter { /** * The factory to use as a fallback if the primary factory failed. */ private final AbstractAuthorityFactory fallback; /** * The number of time the primary factory failed and the fallback factory was used * instead. This information is provided mostly for debugging and testing purpose. */ private static int failureCount; /** * Returns {@code true} if the two specified factories can be used in a * {@code FallbackAuthorityFactory}. If this method returns {@code false}, * then we should not create instance of this class since it would be useless. */ static boolean chainable(final AuthorityFactory primary, final AuthorityFactory fallback) { return (interfaceMask(primary) & interfaceMask(fallback)) != 0; } /** * Wraps a primary and a fallback authority factories. * <p> * This constructor is protected because subclasses must declare which of the * {@link DatumAuthorityFactory}, {@link CSAuthorityFactory}, {@link CRSAuthorityFactory} * and {@link CoordinateOperationAuthorityFactory} interfaces they choose to implement. * * @param primary The primary factory. * @param fallback The factory to use as a fallback if the primary factory failed. * * @see #create */ protected FallbackAuthorityFactory(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); ensureNonNull("fallback", fallback); this.fallback = (fallback instanceof AbstractAuthorityFactory) ? (AbstractAuthorityFactory) fallback : new AuthorityFactoryAdapter(fallback); } /** * Wraps the specified authority factories. If the specified collection contains more than * one element, then a chain of {@code FallbackAuthorityFactory} instances is created. * * @param <T> The interface to implement. * @param type The interface to implement. Should be one of {@link DatumAuthorityFactory}, * {@link CSAuthorityFactory}, {@link CRSAuthorityFactory} or * {@link CoordinateOperationAuthorityFactory}. * @param factories The factories to wrap, in iteration order. * @return The given factories as a chain of fallback factories. * @throws FactoryNotFoundException if the collection doesn't contains at least one element. * @throws ClassCastException if {@code type} is illegal. */ public static <T extends AuthorityFactory> T create(final Class<T> type, final Collection<T> factories) throws FactoryNotFoundException, ClassCastException { ensureNonNull("type", type); ensureNonNull("factories", factories); if (factories.isEmpty()) { throw new FactoryNotFoundException(Errors.format(ErrorKeys.FACTORY_NOT_FOUND_$1, type)); } return type.cast(create(false, interfaceMask(type), factories.iterator())); } /** * Wraps the specified authority factories. If the specified collection contains more than * one element, then a chain of {@code FallbackAuthorityFactory} instances is created. The * type is inferred from the factories found in the collection. * <p> * Consider using <code>{@linkplain #create(Class, Collection) create}(type, factories)</code> * instead when the type is known at compile time. * * @param factories The factories to wrap, in iteration order. * @return The given factories as a chain of fallback factories. * @throws FactoryNotFoundException if the collection doesn't contains at least one element. * * @since 2.4 */ public static AuthorityFactory create(final Collection<? extends AuthorityFactory> factories) throws FactoryNotFoundException { ensureNonNull("factories", factories); if (factories.isEmpty()) { throw new FactoryNotFoundException(Errors.format( ErrorKeys.FACTORY_NOT_FOUND_$1, AuthorityFactory.class)); } return create(false, interfaceMask(factories), factories.iterator()); } /** * Wraps the specified authority factories. If the specified collection contains more than * one element, then a chain of {@code FallbackAuthorityFactory} instances is created. * * @param automatic {@code true} if {@code interfaceMask} should automatically * be restricted to the factory types detected in the collection. * @param interfaceMask The value computed by {@link #interfaceMask(Class)} that * describe the set of interfaces to be implemented by the returned factory. * @param factories The factories to chain. */ private static AuthorityFactory create(final boolean automatic, int interfaceMask, final Iterator<? extends AuthorityFactory> factories) throws FactoryNotFoundException { AuthorityFactory primary = factories.next(); if (factories.hasNext()) { AuthorityFactory fallback = create(true, interfaceMask, factories); while (fallback != primary) { // Paranoiac check if (!sameAuthorityCodes(fallback, primary)) { /* * (Note: argument order is significant in the above method call) * Creates a "primary - fallback" chain only if the fallback is not * performing the same work than the primary factory, for example: * * - A BufferedAuthorityFactory wrapping the primary factory. Since * the primary factory is tested first, the second one is useless. * * - A OrderedAxisAuthorityFactory wrapping the primary factory. If * the primary factory failed to create a CRS, the second factory * should fail too since it relies on the first one. */ if (automatic) { // Restricts the interface to be implemented to the // same set of interfaces than the backing factories. interfaceMask &= (interfaceMask(primary) | interfaceMask(fallback)); } primary = create(interfaceMask, primary, fallback); } else { /* * If the fallback is redundant, we should be done (just return the primary * factory). A special case occurs if the fallback is an other instance of * FallbackAuthorityFactory. We want to discard only the redundant primary * factory (this is why we don't override sameAuthorityCodes(...) for testing * the fallback). The fallback may have value, so we test it recursively. */ if (fallback instanceof FallbackAuthorityFactory) { fallback = ((FallbackAuthorityFactory) fallback).fallback; continue; } } break; } } return primary; } /** * Returns the direct dependencies. The returned list contains the backing store and the * fallback specified at construction time, or the exception if they can't be obtained. */ @Override Collection<? super AuthorityFactory> dependencies() { final Collection<? super AuthorityFactory> dep = super.dependencies(); dep.add(fallback); return dep; } /** * Returns the set of authority codes for the specified type. The default implementation * returns the union of the authority codes from the <cite>primary</cite> and the * <cite>fallback</cite> factories. */ @Override public Set<String> getAuthorityCodes(final Class<? extends IdentifiedObject> type) throws FactoryException { final Set<String> codes = new LinkedHashSet<String>(super.getAuthorityCodes(type)); codes.addAll(fallback.getAuthorityCodes(type)); return codes; } /** * Returns a description for the object identified by the specified code. */ @Override public InternationalString getDescriptionText(final String code) throws FactoryException { try { return super.getDescriptionText(code); } catch (FactoryException exception) { notifyFailure("getDescriptionText", exception); try { return fallback.getDescriptionText(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns an arbitrary object from a code. */ @Override public IdentifiedObject createObject(final String code) throws FactoryException { try { return super.createObject(code); } catch (FactoryException exception) { notifyFailure("createObject", exception); try { return fallback.createObject(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns an arbitrary {@linkplain org.opengis.referencing.datum.Datum datum} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public org.opengis.referencing.datum.Datum createDatum(final String code) throws FactoryException { try { return super.createDatum(code); } catch (FactoryException exception) { notifyFailure("createDatum", exception); try { return fallback.createDatum(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain EngineeringDatum engineering datum} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public EngineeringDatum createEngineeringDatum(final String code) throws FactoryException { try { return super.createEngineeringDatum(code); } catch (FactoryException exception) { notifyFailure("createEngineeringDatum", exception); try { return fallback.createEngineeringDatum(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain ImageDatum image datum} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public ImageDatum createImageDatum(final String code) throws FactoryException { try { return super.createImageDatum(code); } catch (FactoryException exception) { notifyFailure("createImageDatum", exception); try { return fallback.createImageDatum(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain VerticalDatum vertical datum} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public VerticalDatum createVerticalDatum(final String code) throws FactoryException { try { return super.createVerticalDatum(code); } catch (FactoryException exception) { notifyFailure("createVerticalDatum", exception); try { return fallback.createVerticalDatum(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain TemporalDatum temporal datum} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public TemporalDatum createTemporalDatum(final String code) throws FactoryException { try { return super.createTemporalDatum(code); } catch (FactoryException exception) { notifyFailure("createTemporalDatum", exception); try { return fallback.createTemporalDatum(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain GeodeticDatum geodetic datum} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public GeodeticDatum createGeodeticDatum(final String code) throws FactoryException { try { return super.createGeodeticDatum(code); } catch (FactoryException exception) { notifyFailure("createGeodeticDatum", exception); try { return fallback.createGeodeticDatum(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns an {@linkplain Ellipsoid ellipsoid} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public Ellipsoid createEllipsoid(final String code) throws FactoryException { try { return super.createEllipsoid(code); } catch (FactoryException exception) { notifyFailure("createEllipsoid", exception); try { return fallback.createEllipsoid(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain PrimeMeridian prime meridian} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public PrimeMeridian createPrimeMeridian(final String code) throws FactoryException { try { return super.createPrimeMeridian(code); } catch (FactoryException exception) { notifyFailure("createPrimeMeridian", exception); try { return fallback.createPrimeMeridian(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain Extent extent} (usually an area of validity) from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public Extent createExtent(final String code) throws FactoryException { try { return super.createExtent(code); } catch (FactoryException exception) { notifyFailure("createExtent", exception); try { return fallback.createExtent(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns an arbitrary {@linkplain CoordinateSystem coordinate system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CoordinateSystem createCoordinateSystem(final String code) throws FactoryException { try { return super.createCoordinateSystem(code); } catch (FactoryException exception) { notifyFailure("createCoordinateSystem", exception); try { return fallback.createCoordinateSystem(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a cartesian coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CartesianCS createCartesianCS(final String code) throws FactoryException { try { return super.createCartesianCS(code); } catch (FactoryException exception) { notifyFailure("createCartesianCS", exception); try { return fallback.createCartesianCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a polar coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public PolarCS createPolarCS(final String code) throws FactoryException { try { return super.createPolarCS(code); } catch (FactoryException exception) { notifyFailure("createPolarCS", exception); try { return fallback.createPolarCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a cylindrical coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CylindricalCS createCylindricalCS(final String code) throws FactoryException { try { return super.createCylindricalCS(code); } catch (FactoryException exception) { notifyFailure("createCylindricalCS", exception); try { return fallback.createCylindricalCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a spherical coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public SphericalCS createSphericalCS(final String code) throws FactoryException { try { return super.createSphericalCS(code); } catch (FactoryException exception) { notifyFailure("createSphericalCS", exception); try { return fallback.createSphericalCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates an ellipsoidal coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public EllipsoidalCS createEllipsoidalCS(final String code) throws FactoryException { try { return super.createEllipsoidalCS(code); } catch (FactoryException exception) { notifyFailure("createEllipsoidalCS", exception); try { return fallback.createEllipsoidalCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a vertical coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public VerticalCS createVerticalCS(final String code) throws FactoryException { try { return super.createVerticalCS(code); } catch (FactoryException exception) { notifyFailure("createVerticalCS", exception); try { return fallback.createVerticalCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a temporal coordinate system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public TimeCS createTimeCS(final String code) throws FactoryException { try { return super.createTimeCS(code); } catch (FactoryException exception) { notifyFailure("createTimeCS", exception); try { return fallback.createTimeCS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain CoordinateSystemAxis coordinate system axis} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CoordinateSystemAxis createCoordinateSystemAxis(final String code) throws FactoryException { try { return super.createCoordinateSystemAxis(code); } catch (FactoryException exception) { notifyFailure("createCoordinateSystemAxis", exception); try { return fallback.createCoordinateSystemAxis(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns an {@linkplain Unit unit} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public Unit<?> createUnit(final String code) throws FactoryException { try { return super.createUnit(code); } catch (FactoryException exception) { notifyFailure("createUnit", exception); try { return fallback.createUnit(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns an arbitrary {@linkplain CoordinateReferenceSystem coordinate reference system} * from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CoordinateReferenceSystem createCoordinateReferenceSystem(final String code) throws FactoryException { try { return super.createCoordinateReferenceSystem(code); } catch (FactoryException exception) { notifyFailure("createCoordinateReferenceSystem", exception); try { return fallback.createCoordinateReferenceSystem(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a 3D coordinate reference system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CompoundCRS createCompoundCRS(final String code) throws FactoryException { try { return super.createCompoundCRS(code); } catch (FactoryException exception) { notifyFailure("createCompoundCRS", exception); try { return fallback.createCompoundCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a derived coordinate reference system from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public DerivedCRS createDerivedCRS(final String code) throws FactoryException { try { return super.createDerivedCRS(code); } catch (FactoryException exception) { notifyFailure("createDerivedCRS", exception); try { return fallback.createDerivedCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain EngineeringCRS engineering coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public EngineeringCRS createEngineeringCRS(final String code) throws FactoryException { try { return super.createEngineeringCRS(code); } catch (FactoryException exception) { notifyFailure("createEngineeringCRS", exception); try { return fallback.createEngineeringCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain GeographicCRS geographic coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public GeographicCRS createGeographicCRS(final String code) throws FactoryException { try { return super.createGeographicCRS(code); } catch (FactoryException exception) { notifyFailure("createGeographicCRS", exception); try { return fallback.createGeographicCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain GeocentricCRS geocentric coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public GeocentricCRS createGeocentricCRS(final String code) throws FactoryException { try { return super.createGeocentricCRS(code); } catch (FactoryException exception) { notifyFailure("createGeocentricCRS", exception); try { return fallback.createGeocentricCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain ImageCRS image coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public ImageCRS createImageCRS(final String code) throws FactoryException { try { return super.createImageCRS(code); } catch (FactoryException exception) { notifyFailure("createImageCRS", exception); try { return fallback.createImageCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a {@linkplain ProjectedCRS projected coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public ProjectedCRS createProjectedCRS(final String code) throws FactoryException { try { return super.createProjectedCRS(code); } catch (FactoryException exception) { notifyFailure("createProjectedCRS", exception); try { return fallback.createProjectedCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain TemporalCRS temporal coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public TemporalCRS createTemporalCRS(final String code) throws FactoryException { try { return super.createTemporalCRS(code); } catch (FactoryException exception) { notifyFailure("createTemporalCRS", exception); try { return fallback.createTemporalCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a {@linkplain VerticalCRS vertical coordinate reference system} from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public VerticalCRS createVerticalCRS(final String code) throws FactoryException { try { return super.createVerticalCRS(code); } catch (FactoryException exception) { notifyFailure("createVerticalCRS", exception); try { return fallback.createVerticalCRS(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates a parameter descriptor from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public ParameterDescriptor createParameterDescriptor(final String code) throws FactoryException { try { return super.createParameterDescriptor(code); } catch (FactoryException exception) { notifyFailure("createParameterDescriptor", exception); try { return fallback.createParameterDescriptor(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates an operation method from a code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public OperationMethod createOperationMethod(final String code) throws FactoryException { try { return super.createOperationMethod(code); } catch (FactoryException exception) { notifyFailure("createOperationMethod", exception); try { return fallback.createOperationMethod(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates an operation from a single operation code. * * @throws FactoryException if the object creation failed for all factories. */ @Override public CoordinateOperation createCoordinateOperation(final String code) throws FactoryException { try { return super.createCoordinateOperation(code); } catch (FactoryException exception) { notifyFailure("createCoordinateOperation", exception); try { return fallback.createCoordinateOperation(code); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Creates an operation from coordinate reference system codes. * * @throws FactoryException if the object creation failed for all factories. */ @Override public Set<CoordinateOperation> createFromCoordinateReferenceSystemCodes( final String sourceCRS, final String targetCRS) throws FactoryException { try { return super.createFromCoordinateReferenceSystemCodes(sourceCRS, targetCRS); } catch (FactoryException exception) { notifyFailure("createFromCoordinateReferenceSystemCodes", exception); try { return fallback.createFromCoordinateReferenceSystemCodes(sourceCRS, targetCRS); } catch (NoSuchAuthorityCodeException ignore) { throw exception; } } } /** * Returns a finder which can be used for looking up unidentified objects. * The default implementation delegates the lookups to the primary factory, * and fallback on the second one if the primary factory can't find a match. * * @since 2.4 */ @Override public IdentifiedObjectFinder getIdentifiedObjectFinder(Class<? extends IdentifiedObject> type) throws FactoryException { return new Finder(type); } /** * A {@link IdentifiedObjectFinder} which fallback to the second factory * if the primary one can't find a match. */ private final class Finder extends AuthorityFactoryAdapter.Finder { /** * The fallback. Will be created only when first needed. */ private transient IdentifiedObjectFinder fallback; /** * Creates a finder for the underlying backing store. */ Finder(final Class<? extends IdentifiedObject> type) throws FactoryException { super(type); } /** * Makes sure that {@link #fallback} is initialized. */ private void ensureFallback() throws FactoryException { if (fallback == null) { fallback = FallbackAuthorityFactory.this.fallback.getIdentifiedObjectFinder(getProxy().getType()); } fallback.setFullScanAllowed(isFullScanAllowed()); } /** * Lookups for the specified object. */ @Override public IdentifiedObject find(final IdentifiedObject object) throws FactoryException { IdentifiedObject candidate = finder.find(object); if (candidate != null) { return candidate; } ensureFallback(); candidate = fallback.find(object); return candidate; } /** * Returns the identifier of the specified object, or {@code null} if none. */ @Override public String findIdentifier(final IdentifiedObject object) throws FactoryException { String candidate = finder.findIdentifier(object); if (candidate != null) { return candidate; } ensureFallback(); candidate = fallback.findIdentifier(object); return candidate; } } /** * Invoked by <code>create</code><var>Foo</var><code>(String)</code> methods when the * <cite>primary</cite> factory failed to create an object. Note that it doesn't imply * anything about the success of <cite>fallback</cite> factory. The default implementation * log a message to the {@link Level#FINE FINE} level. * * @param method The name of the invoked method. * @param exception The exception that occured. It is often possible to * get the authority code from some subclasses of this exception. */ private static void notifyFailure(final String method, final FactoryException exception) { failureCount++; if (LOGGER.isLoggable(Level.FINE)) { final LogRecord record = Loggings.format(Level.FINE, LoggingKeys.FALLBACK_FACTORY_$1, exception); record.setSourceClassName(FallbackAuthorityFactory.class.getName()); record.setSourceMethodName(method); record.setLoggerName(LOGGER.getName()); LOGGER.log(record); } } /** * Returns the number of time the primary factory failed and the fallback factory was * used instead. This information is provided mostly for debugging and testing purpose. * It is approximative because incrementation is not sychronized. */ static int getFailureCount() { return failureCount; } /** * Returns a mask that represent the implemented interfaces. */ private static int interfaceMask(final Collection<? extends AuthorityFactory> factories) { int mask = 0; for (final AuthorityFactory factory : factories) { mask |= interfaceMask(factory); } return mask; } /** * Returns a mask that represent the implemented interface. */ private static int interfaceMask(final AuthorityFactory factory) { return interfaceMask(factory.getClass()); } /** * Returns a mask that represent the implemented interface. */ private static int interfaceMask(final Class<? extends AuthorityFactory> type) { int mask = 0; // Will be a set of bit flags, as set below. if (CoordinateOperationAuthorityFactory.class.isAssignableFrom(type)) mask |= 1; if ( CSAuthorityFactory.class.isAssignableFrom(type)) mask |= 2; if ( DatumAuthorityFactory.class.isAssignableFrom(type)) mask |= 4; if ( CRSAuthorityFactory.class.isAssignableFrom(type)) mask |= 8; return mask; } /** * Creates a factory from a mask computed by {@link #interfaceMask}. */ private static AuthorityFactory create(final int mask, final AuthorityFactory primary, final AuthorityFactory fallback) { /* * The following assertion fails if we try to implements some * interfaces not supported by the primary or fallback factory. */ assert (mask & ~(interfaceMask(primary) | interfaceMask(fallback))) == 0 : mask; final AuthorityFactory factory; /* * In the 'switch' statement below, we do not implement all possible combinaisons * of authority factories. Only a few common combinaisons are listed. Other * combinaisons will fallback on some reasonable default. We may complete the * list later if there is a need for that. */ switch (mask) { case 15: factory = new All (primary, fallback); break; case 14: factory = new CRS_Datum_CS (primary, fallback); break; case 13: // = new CRS_Datum_Operation (primary, fallback); break; case 12: // = new CRS_Datum (primary, fallback); break; case 11: // = new CRS_CS_Operation (primary, fallback); break; case 10: // = new CRS_CS (primary, fallback); break; case 9: // = new CRS_Operation (primary, fallback); break; case 8: factory = new CRS (primary, fallback); break; case 7: // = new Datum_CS_Operation (primary, fallback); break; case 6: // = new Datum_CS (primary, fallback); break; case 5: // = new Datum_Operation (primary, fallback); break; case 4: factory = new Datum (primary, fallback); break; case 3: // = new CS_Operation (primary, fallback); break; case 2: factory = new CS (primary, fallback); break; case 1: factory = new Operation (primary, fallback); break; case 0: factory = new FallbackAuthorityFactory(primary, fallback); break; default: throw new AssertionError(mask); // Should never happen. } /* * The following assertion fails if 'factory' implements some interfaces * that wasn't requested. The opposite is allowed however: 'factory' may * not implement every requested interfaces. */ assert (interfaceMask(factory) & ~mask) == 0 : mask; return factory; } /** For internal use by {@link FallbackAuthorityFactory#create} only. */ private static final class CRS extends FallbackAuthorityFactory implements CRSAuthorityFactory { CRS(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); } } /** For internal use by {@link FallbackAuthorityFactory#create} only. */ private static final class CS extends FallbackAuthorityFactory implements CSAuthorityFactory { CS(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); } } /** For internal use by {@link FallbackAuthorityFactory#create} only. */ private static final class Datum extends FallbackAuthorityFactory implements DatumAuthorityFactory { Datum(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); } } /** For internal use by {@link FallbackAuthorityFactory#create} only. */ private static final class Operation extends FallbackAuthorityFactory implements CoordinateOperationAuthorityFactory { Operation(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); } } /** For internal use by {@link FallbackAuthorityFactory#create} only. */ private static final class CRS_Datum_CS extends FallbackAuthorityFactory implements CRSAuthorityFactory, CSAuthorityFactory, DatumAuthorityFactory { CRS_Datum_CS(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); } } /** For internal use by {@link FallbackAuthorityFactory#create} only. */ private static final class All extends FallbackAuthorityFactory implements CRSAuthorityFactory, CSAuthorityFactory, DatumAuthorityFactory, CoordinateOperationAuthorityFactory { All(final AuthorityFactory primary, final AuthorityFactory fallback) { super(primary, fallback); } } }