0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: */
0016: package org.geotools.referencing.factory;
0017:
0018: // J2SE dependencies
0019: import java.util.Set;
0020: import java.util.Iterator;
0021: import java.util.Collection;
0022: import java.util.Collections;
0023: import java.util.LinkedHashSet;
0024: import java.util.NoSuchElementException;
0025: import java.util.logging.Level;
0026: import java.util.logging.LogRecord;
0027: import javax.units.Unit;
0028:
0029: // OpenGIS dependencies
0030: import org.opengis.referencing.cs.*;
0031: import org.opengis.referencing.crs.*;
0032: import org.opengis.referencing.datum.*;
0033: import org.opengis.referencing.operation.*;
0034: import org.opengis.referencing.IdentifiedObject;
0035: import org.opengis.referencing.AuthorityFactory;
0036: import org.opengis.referencing.FactoryException;
0037: import org.opengis.referencing.NoSuchAuthorityCodeException;
0038: import org.opengis.metadata.extent.Extent;
0039: import org.opengis.metadata.citation.Citation;
0040: import org.opengis.parameter.ParameterDescriptor;
0041: import org.opengis.util.InternationalString;
0042:
0043: // Geotools dependencies
0044: import org.geotools.resources.Utilities;
0045: import org.geotools.resources.i18n.Errors;
0046: import org.geotools.resources.i18n.ErrorKeys;
0047: import org.geotools.resources.i18n.Logging;
0048: import org.geotools.resources.i18n.LoggingKeys;
0049: import org.geotools.factory.FactoryNotFoundException;
0050:
0051: /**
0052: * A factory which delegates all object creation to a <cite>primary</cite> factory,
0053: * and fallback on an other one if the primary factory failed.
0054: *
0055: * @since 2.3
0056: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/FallbackAuthorityFactory.java $
0057: * @version $Id: FallbackAuthorityFactory.java 29124 2008-02-07 08:22:48Z aaime $
0058: * @author Martin Desruisseaux
0059: *
0060: * @todo Needs a mechanism for avoiding to query the same factory twice when the fallback is the
0061: * same instance than the primary factory for some {@link AuthorityFactory} interfaces.
0062: */
0063: public class FallbackAuthorityFactory extends AuthorityFactoryAdapter {
0064: /**
0065: * The factory to use as a fallback if the primary factory failed.
0066: */
0067: private final AbstractAuthorityFactory fallback;
0068:
0069: /**
0070: * The number of time the primary factory failed and the fallback factory was used
0071: * instead. This information is provided mostly for debugging and testing purpose.
0072: */
0073: private static int failureCount;
0074:
0075: /**
0076: * Returns {@code true} if the two specified factories can be used in a
0077: * {@code FallbackAuthorityFactory}. If this method returns {@code false},
0078: * then we should not create instance of this class since it would be useless.
0079: */
0080: static boolean chainable(final AuthorityFactory primary,
0081: final AuthorityFactory fallback) {
0082: return (interfaceMask(primary) & interfaceMask(fallback)) != 0;
0083: }
0084:
0085: /**
0086: * Wraps a primary and a fallback authority factories.
0087: * <p>
0088: * This constructor is protected because subclasses must declare which of the
0089: * {@link DatumAuthorityFactory}, {@link CSAuthorityFactory}, {@link CRSAuthorityFactory}
0090: * and {@link CoordinateOperationAuthorityFactory} interfaces they choose to implement.
0091: *
0092: * @param primary The primary factory.
0093: * @param fallback The factory to use as a fallback if the primary factory failed.
0094: *
0095: * @see #create
0096: */
0097: protected FallbackAuthorityFactory(final AuthorityFactory primary,
0098: final AuthorityFactory fallback) {
0099: super (primary, fallback);
0100: ensureNonNull("fallback", fallback);
0101: this .fallback = (fallback instanceof AbstractAuthorityFactory) ? (AbstractAuthorityFactory) fallback
0102: : new AuthorityFactoryAdapter(fallback);
0103: }
0104:
0105: /**
0106: * Wraps the specified authority factories. If the specified collection contains more than
0107: * one element, then a chain of {@code FallbackAuthorityFactory} instances is created.
0108: *
0109: * @param type The interface to implement. Should be one of {@link DatumAuthorityFactory},
0110: * {@link CSAuthorityFactory}, {@link CRSAuthorityFactory} or
0111: * {@link CoordinateOperationAuthorityFactory}.
0112: * @param factories The factories to wrap, in iteration order.
0113: * @throws FactoryNotFoundException if the collection doesn't contains at least one element.
0114: * @throws ClassCastException if {@code type} is illegal.
0115: *
0116: * @todo Use generic types when we will be allowed to compile for J2SE 1.5 (the return type
0117: * should be T).
0118: */
0119: public static AuthorityFactory create(
0120: final Class/*<T extends AuthorityFactory>*/type,
0121: final Collection/*<T>*/factories)
0122: throws FactoryNotFoundException, ClassCastException {
0123: ensureNonNull("type", type);
0124: ensureNonNull("factories", factories);
0125: if (factories.isEmpty()) {
0126: throw new FactoryNotFoundException(Errors.format(
0127: ErrorKeys.FACTORY_NOT_FOUND_$1, Utilities
0128: .getShortName(type)));
0129: }
0130: return create(false, interfaceMask(type), factories.iterator());
0131: // TODO: use the following line when we will be allowed to compile for J2SE 1.5.
0132: // return type.cast(...);
0133: }
0134:
0135: /**
0136: * Wraps the specified authority factories. If the specified collection contains more than
0137: * one element, then a chain of {@code FallbackAuthorityFactory} instances is created. The
0138: * type is inferred from the factories found in the collection.
0139: * <p>
0140: * Consider using <code>{@linkplain #create(Class, Collection) create}(type, factories)</code>
0141: * instead when the type is known at compile time.
0142: *
0143: * @param factories The factories to wrap, in iteration order.
0144: * @throws FactoryNotFoundException if the collection doesn't contains at least one element.
0145: *
0146: * @since 2.4
0147: */
0148: public static AuthorityFactory create(final Collection factories)
0149: throws FactoryNotFoundException {
0150: ensureNonNull("factories", factories);
0151: if (factories.isEmpty()) {
0152: throw new FactoryNotFoundException(Errors.format(
0153: ErrorKeys.FACTORY_NOT_FOUND_$1, Utilities
0154: .getShortName(AuthorityFactory.class)));
0155: }
0156: return create(false, interfaceMask(factories), factories
0157: .iterator());
0158: }
0159:
0160: /**
0161: * Wraps the specified authority factories. If the specified collection contains more than
0162: * one element, then a chain of {@code FallbackAuthorityFactory} instances is created.
0163: *
0164: * @param automatic {@code true} if {@code interfaceMask} should automatically
0165: * be restricted to the factory types detected in the collection.
0166: * @param interfaceMask The value computed by {@link #interfaceMask(Class)} that
0167: * describe the set of interfaces to be implemented by the returned factory.
0168: * @param factories The factories to chain.
0169: */
0170: private static AuthorityFactory create(final boolean automatic,
0171: int interfaceMask,
0172: final Iterator/*<AuthorityFactory>*/factories)
0173: throws FactoryNotFoundException {
0174: AuthorityFactory primary = (AuthorityFactory) factories.next();
0175: if (factories.hasNext()) {
0176: AuthorityFactory fallback = create(true, interfaceMask,
0177: factories);
0178: while (fallback != primary) { // Paranoiac check
0179: if (!sameAuthorityCodes(fallback, primary)) {
0180: /*
0181: * (Note: argument order is significant in the above method call)
0182: * Creates a "primary - fallback" chain only if the fallback is not
0183: * performing the same work than the primary factory, for example:
0184: *
0185: * - A BufferedAuthorityFactory wrapping the primary factory. Since
0186: * the primary factory is tested first, the second one is useless.
0187: *
0188: * - A OrderedAxisAuthorityFactory wrapping the primary factory. If
0189: * the primary factory failed to create a CRS, the second factory
0190: * should fail too since it relies on the first one.
0191: */
0192: if (automatic) {
0193: // Restricts the interface to be implemented to the
0194: // same set of interfaces than the backing factories.
0195: interfaceMask &= (interfaceMask(primary) | interfaceMask(fallback));
0196: }
0197: primary = create(interfaceMask, primary, fallback);
0198: } else {
0199: /*
0200: * If the fallback is redundant, we should be done (just return the primary
0201: * factory). A special case occurs if the fallback is an other instance of
0202: * FallbackAuthorityFactory. We want to discard only the redundant primary
0203: * factory (this is why we don't override sameAuthorityCodes(...) for testing
0204: * the fallback). The fallback may have value, so we test it recursively.
0205: */
0206: if (fallback instanceof FallbackAuthorityFactory) {
0207: fallback = ((FallbackAuthorityFactory) fallback).fallback;
0208: continue;
0209: }
0210: }
0211: break;
0212: }
0213: }
0214: return primary;
0215: }
0216:
0217: /**
0218: * Returns the direct dependencies. The returned list contains the backing store and the
0219: * fallback specified at construction time, or the exception if they can't be obtained.
0220: */
0221: //@Override
0222: Collection/*<?>*/dependencies() {
0223: final Collection/*<?>*/dep = super .dependencies();
0224: dep.add(fallback);
0225: return dep;
0226: }
0227:
0228: /**
0229: * Returns the set of authority codes for the specified type. The default implementation
0230: * returns the union of the authority codes from the <cite>primary</cite> and the
0231: * <cite>fallback</cite> factories.
0232: */
0233: public Set/*<String>*/getAuthorityCodes(final Class type)
0234: throws FactoryException {
0235: final Set codes = new LinkedHashSet(super
0236: .getAuthorityCodes(type));
0237: codes.addAll(fallback.getAuthorityCodes(type));
0238: return codes;
0239: }
0240:
0241: /**
0242: * Returns a description for the object identified by the specified code.
0243: */
0244: public InternationalString getDescriptionText(final String code)
0245: throws FactoryException {
0246: try {
0247: return super .getDescriptionText(code);
0248: } catch (FactoryException exception) {
0249: notifyFailure("getDescriptionText", exception);
0250: try {
0251: return fallback.getDescriptionText(code);
0252: } catch (NoSuchAuthorityCodeException ignore) {
0253: throw exception;
0254: }
0255: }
0256: }
0257:
0258: /**
0259: * Returns an arbitrary object from a code.
0260: */
0261: public IdentifiedObject createObject(final String code)
0262: throws FactoryException {
0263: try {
0264: return super .createObject(code);
0265: } catch (FactoryException exception) {
0266: notifyFailure("createObject", exception);
0267: try {
0268: return fallback.createObject(code);
0269: } catch (NoSuchAuthorityCodeException ignore) {
0270: throw exception;
0271: }
0272: }
0273: }
0274:
0275: /**
0276: * Returns an arbitrary {@linkplain org.opengis.referencing.datum.Datum datum} from a code.
0277: */
0278: public org.opengis.referencing.datum.Datum createDatum(
0279: final String code) throws FactoryException {
0280: try {
0281: return super .createDatum(code);
0282: } catch (FactoryException exception) {
0283: notifyFailure("createDatum", exception);
0284: try {
0285: return fallback.createDatum(code);
0286: } catch (NoSuchAuthorityCodeException ignore) {
0287: throw exception;
0288: }
0289: }
0290: }
0291:
0292: /**
0293: * Creates a {@linkplain EngineeringDatum engineering datum} from a code.
0294: */
0295: public EngineeringDatum createEngineeringDatum(final String code)
0296: throws FactoryException {
0297: try {
0298: return super .createEngineeringDatum(code);
0299: } catch (FactoryException exception) {
0300: notifyFailure("createEngineeringDatum", exception);
0301: try {
0302: return fallback.createEngineeringDatum(code);
0303: } catch (NoSuchAuthorityCodeException ignore) {
0304: throw exception;
0305: }
0306: }
0307: }
0308:
0309: /**
0310: * Creates a {@linkplain ImageDatum image datum} from a code.
0311: */
0312: public ImageDatum createImageDatum(final String code)
0313: throws FactoryException {
0314: try {
0315: return super .createImageDatum(code);
0316: } catch (FactoryException exception) {
0317: notifyFailure("createImageDatum", exception);
0318: try {
0319: return fallback.createImageDatum(code);
0320: } catch (NoSuchAuthorityCodeException ignore) {
0321: throw exception;
0322: }
0323: }
0324: }
0325:
0326: /**
0327: * Creates a {@linkplain VerticalDatum vertical datum} from a code.
0328: */
0329: public VerticalDatum createVerticalDatum(final String code)
0330: throws FactoryException {
0331: try {
0332: return super .createVerticalDatum(code);
0333: } catch (FactoryException exception) {
0334: notifyFailure("createVerticalDatum", exception);
0335: try {
0336: return fallback.createVerticalDatum(code);
0337: } catch (NoSuchAuthorityCodeException ignore) {
0338: throw exception;
0339: }
0340: }
0341: }
0342:
0343: /**
0344: * Creates a {@linkplain TemporalDatum temporal datum} from a code.
0345: */
0346: public TemporalDatum createTemporalDatum(final String code)
0347: throws FactoryException {
0348: try {
0349: return super .createTemporalDatum(code);
0350: } catch (FactoryException exception) {
0351: notifyFailure("createTemporalDatum", exception);
0352: try {
0353: return fallback.createTemporalDatum(code);
0354: } catch (NoSuchAuthorityCodeException ignore) {
0355: throw exception;
0356: }
0357: }
0358: }
0359:
0360: /**
0361: * Returns a {@linkplain GeodeticDatum geodetic datum} from a code.
0362: */
0363: public GeodeticDatum createGeodeticDatum(final String code)
0364: throws FactoryException {
0365: try {
0366: return super .createGeodeticDatum(code);
0367: } catch (FactoryException exception) {
0368: notifyFailure("createGeodeticDatum", exception);
0369: try {
0370: return fallback.createGeodeticDatum(code);
0371: } catch (NoSuchAuthorityCodeException ignore) {
0372: throw exception;
0373: }
0374: }
0375: }
0376:
0377: /**
0378: * Returns an {@linkplain Ellipsoid ellipsoid} from a code.
0379: */
0380: public Ellipsoid createEllipsoid(final String code)
0381: throws FactoryException {
0382: try {
0383: return super .createEllipsoid(code);
0384: } catch (FactoryException exception) {
0385: notifyFailure("createEllipsoid", exception);
0386: try {
0387: return fallback.createEllipsoid(code);
0388: } catch (NoSuchAuthorityCodeException ignore) {
0389: throw exception;
0390: }
0391: }
0392: }
0393:
0394: /**
0395: * Returns a {@linkplain PrimeMeridian prime meridian} from a code.
0396: */
0397: public PrimeMeridian createPrimeMeridian(final String code)
0398: throws FactoryException {
0399: try {
0400: return super .createPrimeMeridian(code);
0401: } catch (FactoryException exception) {
0402: notifyFailure("createPrimeMeridian", exception);
0403: try {
0404: return fallback.createPrimeMeridian(code);
0405: } catch (NoSuchAuthorityCodeException ignore) {
0406: throw exception;
0407: }
0408: }
0409: }
0410:
0411: /**
0412: * Returns a {@linkplain Extent extent} (usually an area of validity) from a code.
0413: */
0414: public Extent createExtent(final String code)
0415: throws FactoryException {
0416: try {
0417: return super .createExtent(code);
0418: } catch (FactoryException exception) {
0419: notifyFailure("createExtent", exception);
0420: try {
0421: return fallback.createExtent(code);
0422: } catch (NoSuchAuthorityCodeException ignore) {
0423: throw exception;
0424: }
0425: }
0426: }
0427:
0428: /**
0429: * Returns an arbitrary {@linkplain CoordinateSystem coordinate system} from a code.
0430: */
0431: public CoordinateSystem createCoordinateSystem(final String code)
0432: throws FactoryException {
0433: try {
0434: return super .createCoordinateSystem(code);
0435: } catch (FactoryException exception) {
0436: notifyFailure("createCoordinateSystem", exception);
0437: try {
0438: return fallback.createCoordinateSystem(code);
0439: } catch (NoSuchAuthorityCodeException ignore) {
0440: throw exception;
0441: }
0442: }
0443: }
0444:
0445: /**
0446: * Creates a cartesian coordinate system from a code.
0447: */
0448: public CartesianCS createCartesianCS(final String code)
0449: throws FactoryException {
0450: try {
0451: return super .createCartesianCS(code);
0452: } catch (FactoryException exception) {
0453: notifyFailure("createCartesianCS", exception);
0454: try {
0455: return fallback.createCartesianCS(code);
0456: } catch (NoSuchAuthorityCodeException ignore) {
0457: throw exception;
0458: }
0459: }
0460: }
0461:
0462: /**
0463: * Creates a polar coordinate system from a code.
0464: */
0465: public PolarCS createPolarCS(final String code)
0466: throws FactoryException {
0467: try {
0468: return super .createPolarCS(code);
0469: } catch (FactoryException exception) {
0470: notifyFailure("createPolarCS", exception);
0471: try {
0472: return fallback.createPolarCS(code);
0473: } catch (NoSuchAuthorityCodeException ignore) {
0474: throw exception;
0475: }
0476: }
0477: }
0478:
0479: /**
0480: * Creates a cylindrical coordinate system from a code.
0481: */
0482: public CylindricalCS createCylindricalCS(final String code)
0483: throws FactoryException {
0484: try {
0485: return super .createCylindricalCS(code);
0486: } catch (FactoryException exception) {
0487: notifyFailure("createCylindricalCS", exception);
0488: try {
0489: return fallback.createCylindricalCS(code);
0490: } catch (NoSuchAuthorityCodeException ignore) {
0491: throw exception;
0492: }
0493: }
0494: }
0495:
0496: /**
0497: * Creates a spherical coordinate system from a code.
0498: */
0499: public SphericalCS createSphericalCS(final String code)
0500: throws FactoryException {
0501: try {
0502: return super .createSphericalCS(code);
0503: } catch (FactoryException exception) {
0504: notifyFailure("createSphericalCS", exception);
0505: try {
0506: return fallback.createSphericalCS(code);
0507: } catch (NoSuchAuthorityCodeException ignore) {
0508: throw exception;
0509: }
0510: }
0511: }
0512:
0513: /**
0514: * Creates an ellipsoidal coordinate system from a code.
0515: */
0516: public EllipsoidalCS createEllipsoidalCS(final String code)
0517: throws FactoryException {
0518: try {
0519: return super .createEllipsoidalCS(code);
0520: } catch (FactoryException exception) {
0521: notifyFailure("createEllipsoidalCS", exception);
0522: try {
0523: return fallback.createEllipsoidalCS(code);
0524: } catch (NoSuchAuthorityCodeException ignore) {
0525: throw exception;
0526: }
0527: }
0528: }
0529:
0530: /**
0531: * Creates a vertical coordinate system from a code.
0532: */
0533: public VerticalCS createVerticalCS(final String code)
0534: throws FactoryException {
0535: try {
0536: return super .createVerticalCS(code);
0537: } catch (FactoryException exception) {
0538: notifyFailure("createVerticalCS", exception);
0539: try {
0540: return fallback.createVerticalCS(code);
0541: } catch (NoSuchAuthorityCodeException ignore) {
0542: throw exception;
0543: }
0544: }
0545: }
0546:
0547: /**
0548: * Creates a temporal coordinate system from a code.
0549: */
0550: public TimeCS createTimeCS(final String code)
0551: throws FactoryException {
0552: try {
0553: return super .createTimeCS(code);
0554: } catch (FactoryException exception) {
0555: notifyFailure("createTimeCS", exception);
0556: try {
0557: return fallback.createTimeCS(code);
0558: } catch (NoSuchAuthorityCodeException ignore) {
0559: throw exception;
0560: }
0561: }
0562: }
0563:
0564: /**
0565: * Returns a {@linkplain CoordinateSystemAxis coordinate system axis} from a code.
0566: */
0567: public CoordinateSystemAxis createCoordinateSystemAxis(
0568: final String code) throws FactoryException {
0569: try {
0570: return super .createCoordinateSystemAxis(code);
0571: } catch (FactoryException exception) {
0572: notifyFailure("createCoordinateSystemAxis", exception);
0573: try {
0574: return fallback.createCoordinateSystemAxis(code);
0575: } catch (NoSuchAuthorityCodeException ignore) {
0576: throw exception;
0577: }
0578: }
0579: }
0580:
0581: /**
0582: * Returns an {@linkplain Unit unit} from a code.
0583: */
0584: public Unit createUnit(final String code) throws FactoryException {
0585: try {
0586: return super .createUnit(code);
0587: } catch (FactoryException exception) {
0588: notifyFailure("createUnit", exception);
0589: try {
0590: return fallback.createUnit(code);
0591: } catch (NoSuchAuthorityCodeException ignore) {
0592: throw exception;
0593: }
0594: }
0595: }
0596:
0597: /**
0598: * Returns an arbitrary {@linkplain CoordinateReferenceSystem coordinate reference system}
0599: * from a code.
0600: */
0601: public CoordinateReferenceSystem createCoordinateReferenceSystem(
0602: final String code) throws FactoryException {
0603: try {
0604: return super .createCoordinateReferenceSystem(code);
0605: } catch (FactoryException exception) {
0606: notifyFailure("createCoordinateReferenceSystem", exception);
0607: try {
0608: return fallback.createCoordinateReferenceSystem(code);
0609: } catch (NoSuchAuthorityCodeException ignore) {
0610: throw exception;
0611: }
0612: }
0613: }
0614:
0615: /**
0616: * Creates a 3D coordinate reference system from a code.
0617: */
0618: public CompoundCRS createCompoundCRS(final String code)
0619: throws FactoryException {
0620: try {
0621: return super .createCompoundCRS(code);
0622: } catch (FactoryException exception) {
0623: notifyFailure("createCompoundCRS", exception);
0624: try {
0625: return fallback.createCompoundCRS(code);
0626: } catch (NoSuchAuthorityCodeException ignore) {
0627: throw exception;
0628: }
0629: }
0630: }
0631:
0632: /**
0633: * Creates a derived coordinate reference system from a code.
0634: */
0635: public DerivedCRS createDerivedCRS(final String code)
0636: throws FactoryException {
0637: try {
0638: return super .createDerivedCRS(code);
0639: } catch (FactoryException exception) {
0640: notifyFailure("createDerivedCRS", exception);
0641: try {
0642: return fallback.createDerivedCRS(code);
0643: } catch (NoSuchAuthorityCodeException ignore) {
0644: throw exception;
0645: }
0646: }
0647: }
0648:
0649: /**
0650: * Creates a {@linkplain EngineeringCRS engineering coordinate reference system} from a code.
0651: */
0652: public EngineeringCRS createEngineeringCRS(final String code)
0653: throws FactoryException {
0654: try {
0655: return super .createEngineeringCRS(code);
0656: } catch (FactoryException exception) {
0657: notifyFailure("createEngineeringCRS", exception);
0658: try {
0659: return fallback.createEngineeringCRS(code);
0660: } catch (NoSuchAuthorityCodeException ignore) {
0661: throw exception;
0662: }
0663: }
0664: }
0665:
0666: /**
0667: * Returns a {@linkplain GeographicCRS geographic coordinate reference system} from a code.
0668: */
0669: public GeographicCRS createGeographicCRS(final String code)
0670: throws FactoryException {
0671: try {
0672: return super .createGeographicCRS(code);
0673: } catch (FactoryException exception) {
0674: notifyFailure("createGeographicCRS", exception);
0675: try {
0676: return fallback.createGeographicCRS(code);
0677: } catch (NoSuchAuthorityCodeException ignore) {
0678: throw exception;
0679: }
0680: }
0681: }
0682:
0683: /**
0684: * Returns a {@linkplain GeocentricCRS geocentric coordinate reference system} from a code.
0685: */
0686: public GeocentricCRS createGeocentricCRS(final String code)
0687: throws FactoryException {
0688: try {
0689: return super .createGeocentricCRS(code);
0690: } catch (FactoryException exception) {
0691: notifyFailure("createGeocentricCRS", exception);
0692: try {
0693: return fallback.createGeocentricCRS(code);
0694: } catch (NoSuchAuthorityCodeException ignore) {
0695: throw exception;
0696: }
0697: }
0698: }
0699:
0700: /**
0701: * Creates a {@linkplain ImageCRS image coordinate reference system} from a code.
0702: */
0703: public ImageCRS createImageCRS(final String code)
0704: throws FactoryException {
0705: try {
0706: return super .createImageCRS(code);
0707: } catch (FactoryException exception) {
0708: notifyFailure("createImageCRS", exception);
0709: try {
0710: return fallback.createImageCRS(code);
0711: } catch (NoSuchAuthorityCodeException ignore) {
0712: throw exception;
0713: }
0714: }
0715: }
0716:
0717: /**
0718: * Returns a {@linkplain ProjectedCRS projected coordinate reference system} from a code.
0719: */
0720: public ProjectedCRS createProjectedCRS(final String code)
0721: throws FactoryException {
0722: try {
0723: return super .createProjectedCRS(code);
0724: } catch (FactoryException exception) {
0725: notifyFailure("createProjectedCRS", exception);
0726: try {
0727: return fallback.createProjectedCRS(code);
0728: } catch (NoSuchAuthorityCodeException ignore) {
0729: throw exception;
0730: }
0731: }
0732: }
0733:
0734: /**
0735: * Creates a {@linkplain TemporalCRS temporal coordinate reference system} from a code.
0736: */
0737: public TemporalCRS createTemporalCRS(final String code)
0738: throws FactoryException {
0739: try {
0740: return super .createTemporalCRS(code);
0741: } catch (FactoryException exception) {
0742: notifyFailure("createTemporalCRS", exception);
0743: try {
0744: return fallback.createTemporalCRS(code);
0745: } catch (NoSuchAuthorityCodeException ignore) {
0746: throw exception;
0747: }
0748: }
0749: }
0750:
0751: /**
0752: * Creates a {@linkplain VerticalCRS vertical coordinate reference system} from a code.
0753: */
0754: public VerticalCRS createVerticalCRS(final String code)
0755: throws FactoryException {
0756: try {
0757: return super .createVerticalCRS(code);
0758: } catch (FactoryException exception) {
0759: notifyFailure("createVerticalCRS", exception);
0760: try {
0761: return fallback.createVerticalCRS(code);
0762: } catch (NoSuchAuthorityCodeException ignore) {
0763: throw exception;
0764: }
0765: }
0766: }
0767:
0768: /**
0769: * Creates a parameter descriptor from a code.
0770: */
0771: public ParameterDescriptor createParameterDescriptor(
0772: final String code) throws FactoryException {
0773: try {
0774: return super .createParameterDescriptor(code);
0775: } catch (FactoryException exception) {
0776: notifyFailure("createParameterDescriptor", exception);
0777: try {
0778: return fallback.createParameterDescriptor(code);
0779: } catch (NoSuchAuthorityCodeException ignore) {
0780: throw exception;
0781: }
0782: }
0783: }
0784:
0785: /**
0786: * Creates an operation method from a code.
0787: */
0788: public OperationMethod createOperationMethod(final String code)
0789: throws FactoryException {
0790: try {
0791: return super .createOperationMethod(code);
0792: } catch (FactoryException exception) {
0793: notifyFailure("createOperationMethod", exception);
0794: try {
0795: return fallback.createOperationMethod(code);
0796: } catch (NoSuchAuthorityCodeException ignore) {
0797: throw exception;
0798: }
0799: }
0800: }
0801:
0802: /**
0803: * Creates an operation from a single operation code.
0804: */
0805: public CoordinateOperation createCoordinateOperation(
0806: final String code) throws FactoryException {
0807: try {
0808: return super .createCoordinateOperation(code);
0809: } catch (FactoryException exception) {
0810: notifyFailure("createCoordinateOperation", exception);
0811: try {
0812: return fallback.createCoordinateOperation(code);
0813: } catch (NoSuchAuthorityCodeException ignore) {
0814: throw exception;
0815: }
0816: }
0817: }
0818:
0819: /**
0820: * Creates an operation from coordinate reference system codes.
0821: */
0822: public Set/*<CoordinateOperation>*/createFromCoordinateReferenceSystemCodes(
0823: final String sourceCode, final String targetCode)
0824: throws FactoryException {
0825: try {
0826: return super .createFromCoordinateReferenceSystemCodes(
0827: sourceCode, targetCode);
0828: } catch (FactoryException exception) {
0829: notifyFailure("createFromCoordinateReferenceSystemCodes",
0830: exception);
0831: try {
0832: return fallback
0833: .createFromCoordinateReferenceSystemCodes(
0834: sourceCode, targetCode);
0835: } catch (NoSuchAuthorityCodeException ignore) {
0836: throw exception;
0837: }
0838: }
0839: }
0840:
0841: /**
0842: * Returns a finder which can be used for looking up unidentified objects.
0843: * The default implementation delegates the lookups to the primary factory,
0844: * and fallback on the second one if the primary factory can't find a match.
0845: *
0846: * @since 2.4
0847: */
0848: //@Override
0849: public IdentifiedObjectFinder getIdentifiedObjectFinder(
0850: final Class/*<? extends IdentifiedObject>*/type)
0851: throws FactoryException {
0852: return new Finder(type);
0853: }
0854:
0855: /**
0856: * A {@link IdentifiedObjectFinder} which fallback to the second factory
0857: * if the primary one can't find a match.
0858: */
0859: private final class Finder extends AuthorityFactoryAdapter.Finder {
0860: /**
0861: * The fallback. Will be created only when first needed.
0862: */
0863: private transient IdentifiedObjectFinder fallback;
0864:
0865: /**
0866: * Creates a finder for the underlying backing store.
0867: */
0868: Finder(final Class/*<? extends IdentifiedObject>*/type)
0869: throws FactoryException {
0870: super (type);
0871: }
0872:
0873: /**
0874: * Makes sure that {@link #fallback} is initialized.
0875: */
0876: private void ensureFallback() throws FactoryException {
0877: if (fallback == null) {
0878: fallback = FallbackAuthorityFactory.this .fallback
0879: .getIdentifiedObjectFinder(proxy.getType());
0880: }
0881: fallback.setFullScanAllowed(isFullScanAllowed());
0882: }
0883:
0884: /**
0885: * Lookups for the specified object.
0886: */
0887: //@Override
0888: public IdentifiedObject find(final IdentifiedObject object)
0889: throws FactoryException {
0890: IdentifiedObject candidate = finder.find(object);
0891: if (candidate != null) {
0892: return candidate;
0893: }
0894: ensureFallback();
0895: candidate = fallback.find(object);
0896: return candidate;
0897: }
0898:
0899: /**
0900: * Returns the identifier of the specified object, or {@code null} if none.
0901: */
0902: //@Override
0903: public String findIdentifier(final IdentifiedObject object)
0904: throws FactoryException {
0905: String candidate = finder.findIdentifier(object);
0906: if (candidate != null) {
0907: return candidate;
0908: }
0909: ensureFallback();
0910: candidate = fallback.findIdentifier(object);
0911: return candidate;
0912: }
0913: }
0914:
0915: /**
0916: * Invoked by <code>create</code><var>Foo</var><code>(String)</code> methods when the
0917: * <cite>primary</cite> factory failed to create an object. Note that it doesn't imply
0918: * anything about the success of <cite>fallback</cite> factory. The default implementation
0919: * log a message to the {@link Level#FINE FINE} level.
0920: *
0921: * @param method The name of the invoked method.
0922: * @param exception The exception that occured. It is often possible to
0923: * get the authority code from some subclasses of this exception.
0924: */
0925: private static void notifyFailure(final String method,
0926: final FactoryException exception) {
0927: failureCount++;
0928: if (LOGGER.isLoggable(Level.FINE)) {
0929: final LogRecord record = Logging.format(Level.FINE,
0930: LoggingKeys.FALLBACK_FACTORY_$1, exception);
0931: record.setSourceClassName(FallbackAuthorityFactory.class
0932: .getName());
0933: record.setSourceMethodName(method);
0934: LOGGER.log(record);
0935: }
0936: }
0937:
0938: /**
0939: * Returns the number of time the primary factory failed and the fallback factory was
0940: * used instead. This information is provided mostly for debugging and testing purpose.
0941: * It is approximative because incrementation is not sychronized.
0942: */
0943: static int getFailureCount() {
0944: return failureCount;
0945: }
0946:
0947: /**
0948: * Returns a mask that represent the implemented interfaces.
0949: */
0950: private static int interfaceMask(
0951: final Collection/*<? extends AuthorityFactory>*/factories) {
0952: int mask = 0;
0953: for (final Iterator it = factories.iterator(); it.hasNext();) {
0954: mask |= interfaceMask((AuthorityFactory) it.next());
0955: }
0956: return mask;
0957: }
0958:
0959: /**
0960: * Returns a mask that represent the implemented interface.
0961: */
0962: private static int interfaceMask(final AuthorityFactory factory) {
0963: return interfaceMask(factory.getClass());
0964: }
0965:
0966: /**
0967: * Returns a mask that represent the implemented interface.
0968: */
0969: private static int interfaceMask(
0970: final Class/*<? extends AuthorityFactory>*/type) {
0971: int mask = 0; // Will be a set of bit flags, as set below.
0972: if (CoordinateOperationAuthorityFactory.class
0973: .isAssignableFrom(type))
0974: mask |= 1;
0975: if (CSAuthorityFactory.class.isAssignableFrom(type))
0976: mask |= 2;
0977: if (DatumAuthorityFactory.class.isAssignableFrom(type))
0978: mask |= 4;
0979: if (CRSAuthorityFactory.class.isAssignableFrom(type))
0980: mask |= 8;
0981: return mask;
0982: }
0983:
0984: /**
0985: * Creates a factory from a mask computed by {@link #interfaceMask}.
0986: */
0987: private static AuthorityFactory create(final int mask,
0988: final AuthorityFactory primary,
0989: final AuthorityFactory fallback) {
0990: /*
0991: * The following assertion fails if we try to implements some
0992: * interfaces not supported by the primary or fallback factory.
0993: */
0994: assert (mask & ~(interfaceMask(primary) | interfaceMask(fallback))) == 0 : mask;
0995: final AuthorityFactory factory;
0996: /*
0997: * In the 'switch' statement below, we do not implement all possible combinaisons
0998: * of authority factories. Only a few common combinaisons are listed. Other
0999: * combinaisons will fallback on some reasonable default. We may complete the
1000: * list later if there is a need for that.
1001: */
1002: switch (mask) {
1003: case 15:
1004: factory = new All(primary, fallback);
1005: break;
1006: case 14:
1007: factory = new CRS_Datum_CS(primary, fallback);
1008: break;
1009: case 13: // = new CRS_Datum_Operation (primary, fallback); break;
1010: case 12: // = new CRS_Datum (primary, fallback); break;
1011: case 11: // = new CRS_CS_Operation (primary, fallback); break;
1012: case 10: // = new CRS_CS (primary, fallback); break;
1013: case 9: // = new CRS_Operation (primary, fallback); break;
1014: case 8:
1015: factory = new CRS(primary, fallback);
1016: break;
1017: case 7: // = new Datum_CS_Operation (primary, fallback); break;
1018: case 6: // = new Datum_CS (primary, fallback); break;
1019: case 5: // = new Datum_Operation (primary, fallback); break;
1020: case 4:
1021: factory = new Datum(primary, fallback);
1022: break;
1023: case 3: // = new CS_Operation (primary, fallback); break;
1024: case 2:
1025: factory = new CS(primary, fallback);
1026: break;
1027: case 1:
1028: factory = new Operation(primary, fallback);
1029: break;
1030: case 0:
1031: factory = new FallbackAuthorityFactory(primary, fallback);
1032: break;
1033: default:
1034: throw new AssertionError(mask); // Should never happen.
1035: }
1036: /*
1037: * The following assertion fails if 'factory' implements some interfaces
1038: * that wasn't requested. The opposite is allowed however: 'factory' may
1039: * not implement every requested interfaces.
1040: */
1041: assert (interfaceMask(factory) & ~mask) == 0 : mask;
1042: return factory;
1043: }
1044:
1045: /** For internal use by {@link FallbackAuthorityFactory#create} only. */
1046: private static final class CRS extends FallbackAuthorityFactory
1047: implements CRSAuthorityFactory {
1048: CRS(final AuthorityFactory primary,
1049: final AuthorityFactory fallback) {
1050: super (primary, fallback);
1051: }
1052: }
1053:
1054: /** For internal use by {@link FallbackAuthorityFactory#create} only. */
1055: private static final class CS extends FallbackAuthorityFactory
1056: implements CSAuthorityFactory {
1057: CS(final AuthorityFactory primary,
1058: final AuthorityFactory fallback) {
1059: super (primary, fallback);
1060: }
1061: }
1062:
1063: /** For internal use by {@link FallbackAuthorityFactory#create} only. */
1064: private static final class Datum extends FallbackAuthorityFactory
1065: implements DatumAuthorityFactory {
1066: Datum(final AuthorityFactory primary,
1067: final AuthorityFactory fallback) {
1068: super (primary, fallback);
1069: }
1070: }
1071:
1072: /** For internal use by {@link FallbackAuthorityFactory#create} only. */
1073: private static final class Operation extends
1074: FallbackAuthorityFactory implements
1075: CoordinateOperationAuthorityFactory {
1076: Operation(final AuthorityFactory primary,
1077: final AuthorityFactory fallback) {
1078: super (primary, fallback);
1079: }
1080: }
1081:
1082: /** For internal use by {@link FallbackAuthorityFactory#create} only. */
1083: private static final class CRS_Datum_CS extends
1084: FallbackAuthorityFactory implements CRSAuthorityFactory,
1085: CSAuthorityFactory, DatumAuthorityFactory {
1086: CRS_Datum_CS(final AuthorityFactory primary,
1087: final AuthorityFactory fallback) {
1088: super (primary, fallback);
1089: }
1090: }
1091:
1092: /** For internal use by {@link FallbackAuthorityFactory#create} only. */
1093: private static final class All extends FallbackAuthorityFactory
1094: implements CRSAuthorityFactory, CSAuthorityFactory,
1095: DatumAuthorityFactory, CoordinateOperationAuthorityFactory {
1096: All(final AuthorityFactory primary,
1097: final AuthorityFactory fallback) {
1098: super(primary, fallback);
1099: }
1100: }
1101: }
|