0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
0005: * (C) 2005, Institut de Recherche pour le Développement
0006: *
0007: * This library is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU Lesser General Public
0009: * License as published by the Free Software Foundation;
0010: * version 2.1 of the License.
0011: *
0012: * This library is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * This package contains documentation from OpenGIS specifications.
0018: * OpenGIS consortium's work is fully acknowledged here.
0019: */
0020: package org.geotools.referencing.factory;
0021:
0022: // J2SE dependencies and extensions
0023: import java.lang.ref.Reference;
0024: import java.lang.ref.WeakReference;
0025: import java.util.Map;
0026: import java.util.Set;
0027: import java.util.Iterator;
0028: import java.util.Collection;
0029: import java.util.Collections;
0030: import java.util.WeakHashMap;
0031: import java.util.LinkedHashMap;
0032: import java.util.logging.LogRecord;
0033: import java.util.logging.Level;
0034: import javax.units.Unit;
0035:
0036: // OpenGIS dependencies
0037: import org.opengis.metadata.extent.Extent;
0038: import org.opengis.metadata.citation.Citation;
0039: import org.opengis.parameter.ParameterDescriptor;
0040: import org.opengis.referencing.AuthorityFactory;
0041: import org.opengis.referencing.FactoryException;
0042: import org.opengis.referencing.IdentifiedObject;
0043: import org.opengis.referencing.cs.*;
0044: import org.opengis.referencing.crs.*;
0045: import org.opengis.referencing.datum.*;
0046: import org.opengis.referencing.operation.*;
0047: import org.opengis.util.InternationalString;
0048:
0049: // Geotools dependencies
0050: import org.geotools.factory.Hints;
0051: import org.geotools.factory.BufferedFactory;
0052: import org.geotools.resources.Utilities;
0053: import org.geotools.resources.i18n.Errors;
0054: import org.geotools.resources.i18n.ErrorKeys;
0055: import org.geotools.resources.i18n.Logging;
0056: import org.geotools.resources.i18n.LoggingKeys;
0057:
0058: /**
0059: * An authority factory that caches all objects created by an other factory. All
0060: * {@code createFoo(String)} methods first looks if a previously created object
0061: * exists for the given code. If such an object exists, it is returned. Otherwise,
0062: * the object creation is delegated to the {@linkplain AbstractAuthorityFactory authority factory}
0063: * specified at creation time, and the result is cached in this buffered factory.
0064: * <p>
0065: * Objects are cached by strong references, up to the amount of objects specified at
0066: * construction time. If a greater amount of objects are cached, the oldest ones will
0067: * be retained through a {@linkplain WeakReference weak reference} instead of a strong
0068: * one. This means that this buffered factory will continue to returns them as long as
0069: * they are in use somewhere else in the Java virtual machine, but will be discarted
0070: * (and recreated on the fly if needed) otherwise.
0071: *
0072: * @since 2.1
0073: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/BufferedAuthorityFactory.java $
0074: * @version $Id: BufferedAuthorityFactory.java 26078 2007-06-28 15:00:59Z desruisseaux $
0075: * @author Martin Desruisseaux
0076: */
0077: public class BufferedAuthorityFactory extends AbstractAuthorityFactory
0078: implements BufferedFactory {
0079: /**
0080: * The default value for {@link #maxStrongReferences}.
0081: */
0082: static final int DEFAULT_MAX = 20;
0083:
0084: /**
0085: * The underlying authority factory. This field may be {@code null} if this object was
0086: * created by the {@linkplain #BufferedAuthorityFactory(AbstractAuthorityFactory,int)
0087: * package protected constructor}. In this case, the subclass is responsible for creating
0088: * the backing store when {@link DeferredAuthorityFactory#createBackingStore} is invoked.
0089: *
0090: * @see #getBackingStore
0091: * @see DeferredAuthorityFactory#createBackingStore
0092: */
0093: AbstractAuthorityFactory backingStore;
0094:
0095: /**
0096: * The pool of cached objects.
0097: */
0098: private final LinkedHashMap pool = new LinkedHashMap(32, 0.75f,
0099: true);
0100:
0101: /**
0102: * The maximum number of objects to keep by strong reference. If a greater amount of
0103: * objects are created, then the strong references for the oldest ones are replaced by
0104: * weak references.
0105: */
0106: private final int maxStrongReferences;
0107:
0108: /**
0109: * The pool of objects identified by {@link #find}.
0110: */
0111: private final Map/*<IdentifiedObject,IdentifiedObject>*/findPool = new WeakHashMap();
0112:
0113: /**
0114: * Constructs an instance wrapping the specified factory with a default number
0115: * of entries to keep by strong reference.
0116: * <p>
0117: * This constructor is protected because subclasses must declare which of the
0118: * {@link DatumAuthorityFactory}, {@link CSAuthorityFactory}, {@link CRSAuthorityFactory}
0119: * and {@link CoordinateOperationAuthorityFactory} interfaces they choose to implement.
0120: *
0121: * @param factory The factory to cache. Can not be {@code null}.
0122: */
0123: protected BufferedAuthorityFactory(
0124: final AbstractAuthorityFactory factory) {
0125: this (factory, DEFAULT_MAX);
0126: }
0127:
0128: /**
0129: * Constructs an instance wrapping the specified factory. The {@code maxStrongReferences}
0130: * argument specify the maximum number of objects to keep by strong reference. If a greater
0131: * amount of objects are created, then the strong references for the oldest ones are replaced
0132: * by weak references.
0133: * <p>
0134: * This constructor is protected because subclasses must declare which of the
0135: * {@link DatumAuthorityFactory}, {@link CSAuthorityFactory}, {@link CRSAuthorityFactory}
0136: * and {@link CoordinateOperationAuthorityFactory} interfaces they choose to implement.
0137: *
0138: * @param factory The factory to cache. Can not be {@code null}.
0139: * @param maxStrongReferences The maximum number of objects to keep by strong reference.
0140: */
0141: protected BufferedAuthorityFactory(
0142: AbstractAuthorityFactory factory,
0143: final int maxStrongReferences) {
0144: super (factory.getPriority());
0145: while (factory instanceof BufferedAuthorityFactory) {
0146: factory = ((BufferedAuthorityFactory) factory).backingStore;
0147: }
0148: this .backingStore = factory;
0149: this .maxStrongReferences = maxStrongReferences;
0150: completeHints();
0151: }
0152:
0153: /**
0154: * Constructs an instance without initial backing store. This constructor is for subclass
0155: * constructors only. Subclasses are responsible for creating an appropriate backing store
0156: * when the {@link DeferredAuthorityFactory#createBackingStore} method is invoked.
0157: *
0158: * @param priority The priority for this factory, as a number between
0159: * {@link #MINIMUM_PRIORITY MINIMUM_PRIORITY} and
0160: * {@link #MAXIMUM_PRIORITY MAXIMUM_PRIORITY} inclusive.
0161: * @param maxStrongReferences The maximum number of objects to keep by strong reference.
0162: *
0163: * @see DeferredAuthorityFactory#createBackingStore
0164: */
0165: BufferedAuthorityFactory(final int priority,
0166: final int maxStrongReferences) {
0167: super (priority);
0168: this .maxStrongReferences = maxStrongReferences;
0169: // completeHints() will be invoked by DeferredAuthorityFactory.getBackingStore()
0170: }
0171:
0172: /**
0173: * Completes the set of hints according the value currently set in this object. This method
0174: * is invoked by {@code BufferedAuthorityFactory} or by {@code DeferredAuthorityFactory} at
0175: * backing store creation time.
0176: * <p>
0177: * The backing store is of course an important dependency. This method gives a chance
0178: * to {@link org.geotools.factory.FactoryRegistry} to compare the user-requested hints
0179: * (especially {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER}) against the backing store
0180: * hints, by following the dependency declared there.
0181: * <p>
0182: * DON'T FORGET to set those hints to {@code null} when {@link DeferredAuthorityFactory}
0183: * dispose the backing store.
0184: */
0185: final void completeHints() {
0186: if (backingStore instanceof DatumAuthorityFactory) {
0187: hints.put(Hints.DATUM_AUTHORITY_FACTORY, backingStore);
0188: }
0189: if (backingStore instanceof CSAuthorityFactory) {
0190: hints.put(Hints.CS_AUTHORITY_FACTORY, backingStore);
0191: }
0192: if (backingStore instanceof CRSAuthorityFactory) {
0193: hints.put(Hints.CRS_AUTHORITY_FACTORY, backingStore);
0194: }
0195: if (backingStore instanceof CoordinateOperationAuthorityFactory) {
0196: hints.put(Hints.COORDINATE_OPERATION_AUTHORITY_FACTORY,
0197: backingStore);
0198: }
0199: }
0200:
0201: /**
0202: * Returns the direct dependencies. The returned list contains the backing store
0203: * specified at construction time, or the exception if it can't be obtained.
0204: */
0205: //@Override
0206: Collection/*<?>*/dependencies() {
0207: Object factory;
0208: try {
0209: factory = getBackingStore();
0210: } catch (FactoryException e) {
0211: factory = e;
0212: }
0213: return Collections.singleton(factory);
0214: }
0215:
0216: /**
0217: * Returns the backing store authority factory.
0218: *
0219: * @return The backing store to uses in {@code createXXX(...)} methods.
0220: * @throws FactoryException if the creation of backing store failed.
0221: */
0222: AbstractAuthorityFactory getBackingStore() throws FactoryException {
0223: if (backingStore == null) {
0224: throw new FactoryException(Errors
0225: .format(ErrorKeys.DISPOSED_FACTORY));
0226: }
0227: return backingStore;
0228: }
0229:
0230: /**
0231: * Returns {@code true} if this factory is available. The default implementation returns
0232: * {@code false} if no backing store were setup and
0233: * {@link DeferredAuthorityFactory#createBackingStore} throws an exception.
0234: */
0235: synchronized boolean isAvailable() {
0236: try {
0237: return getBackingStore().isAvailable();
0238: } catch (FactoryNotFoundException exception) {
0239: /*
0240: * The factory is not available. This is error may be normal; it happens
0241: * for example if no gt2-epsg-hsql.jar (or similar JAR) are found in the
0242: * classpath, which is the case for example in GeoServer 1.3. Do not log
0243: * any stack trace, since stack traces suggest more serious errors than
0244: * what we really have here.
0245: */
0246: } catch (FactoryException exception) {
0247: /*
0248: * The factory creation failed for an other reason, which may be more
0249: * serious. Now it is time to log a warning with a stack trace.
0250: */
0251: final Citation citation = getAuthority();
0252: final Collection titles = citation.getAlternateTitles();
0253: InternationalString title = citation.getTitle();
0254: if (titles != null) {
0255: for (final Iterator it = titles.iterator(); it
0256: .hasNext();) {
0257: /*
0258: * Uses the longuest title instead of the main one. In Geotools
0259: * implementation, the alternate title may contains usefull informations
0260: * like the EPSG database version number and the database engine.
0261: */
0262: final InternationalString candidate = (InternationalString) it
0263: .next();
0264: if (candidate.length() > title.length()) {
0265: title = candidate;
0266: }
0267: }
0268: }
0269: final LogRecord record = Logging
0270: .format(
0271: Level.WARNING,
0272: LoggingKeys.UNAVAILABLE_AUTHORITY_FACTORY_$1,
0273: title);
0274: record.setSourceClassName(getClass().getName());
0275: record.setSourceMethodName("isAvailable");
0276: record.setThrown(exception);
0277: LOGGER.log(record);
0278: }
0279: return false;
0280: }
0281:
0282: /**
0283: * If this factory is a wrapper for the specified factory that do not add any additional
0284: * {@linkplain #getAuthorityCodes authority codes}, returns {@code true}. This method is
0285: * for {@link FallbackAuthorityFactory} internal use only and should not be public. A
0286: * cheap test without {@link #getBackingStore} invocation is suffisient for our needs.
0287: */
0288: //@Override
0289: boolean sameAuthorityCodes(final AuthorityFactory factory) {
0290: final AbstractAuthorityFactory backingStore = this .backingStore; // Protect from changes.
0291: if (backingStore != null
0292: && backingStore.sameAuthorityCodes(factory)) {
0293: return true;
0294: }
0295: return super .sameAuthorityCodes(factory);
0296: }
0297:
0298: /**
0299: * Returns the vendor responsible for creating the underlying factory implementation.
0300: */
0301: public synchronized Citation getVendor() {
0302: return (backingStore != null) ? backingStore.getVendor()
0303: : super .getVendor();
0304: }
0305:
0306: /**
0307: * Returns the organization or party responsible for definition and maintenance of the
0308: * underlying database.
0309: */
0310: public synchronized Citation getAuthority() {
0311: return (backingStore != null) ? backingStore.getAuthority()
0312: : null;
0313: }
0314:
0315: /**
0316: * Returns a description of the underlying backing store, or {@code null} if unknow.
0317: * This is for example the database software used for storing the data.
0318: *
0319: * @throws FactoryException if a failure occured while fetching the engine description.
0320: */
0321: public synchronized String getBackingStoreDescription()
0322: throws FactoryException {
0323: return getBackingStore().getBackingStoreDescription();
0324: }
0325:
0326: /**
0327: * Returns the set of authority codes of the given type. The {@code type}
0328: * argument specify the base class.
0329: *
0330: * @param type The spatial reference objects type.
0331: * @return The set of authority codes for spatial reference objects of the given type.
0332: * If this factory doesn't contains any object of the given type, then this method
0333: * returns an {@linkplain java.util.Collections#EMPTY_SET empty set}.
0334: * @throws FactoryException if access to the underlying database failed.
0335: */
0336: public synchronized Set getAuthorityCodes(final Class type)
0337: throws FactoryException {
0338: return getBackingStore().getAuthorityCodes(type);
0339: }
0340:
0341: /**
0342: * Gets a description of the object corresponding to a code.
0343: *
0344: * @param code Value allocated by authority.
0345: * @return A description of the object, or {@code null} if the object
0346: * corresponding to the specified {@code code} has no description.
0347: * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
0348: * @throws FactoryException if the query failed for some other reason.
0349: */
0350: public synchronized InternationalString getDescriptionText(
0351: final String code) throws FactoryException {
0352: return getBackingStore().getDescriptionText(code);
0353: }
0354:
0355: /**
0356: * Returns an arbitrary object from a code.
0357: */
0358: public synchronized IdentifiedObject createObject(final String code)
0359: throws FactoryException {
0360: final IdentifiedObject object;
0361: final String key = trimAuthority(code);
0362: final Object cached = get(key);
0363: if (cached instanceof IdentifiedObject) {
0364: object = (IdentifiedObject) cached;
0365: } else {
0366: object = getBackingStore().createObject(code);
0367: }
0368: put(key, object);
0369: return object;
0370: }
0371:
0372: /**
0373: * Returns an arbitrary datum from a code.
0374: */
0375: public synchronized Datum createDatum(final String code)
0376: throws FactoryException {
0377: final Datum datum;
0378: final String key = trimAuthority(code);
0379: final Object cached = get(key);
0380: if (cached instanceof Datum) {
0381: datum = (Datum) cached;
0382: } else {
0383: datum = getBackingStore().createDatum(code);
0384: }
0385: put(key, datum);
0386: return datum;
0387: }
0388:
0389: /**
0390: * Returns an engineering datum from a code.
0391: */
0392: public synchronized EngineeringDatum createEngineeringDatum(
0393: final String code) throws FactoryException {
0394: final EngineeringDatum datum;
0395: final String key = trimAuthority(code);
0396: final Object cached = get(key);
0397: if (cached instanceof EngineeringDatum) {
0398: datum = (EngineeringDatum) cached;
0399: } else {
0400: datum = getBackingStore().createEngineeringDatum(code);
0401: }
0402: put(key, datum);
0403: return datum;
0404: }
0405:
0406: /**
0407: * Returns an image datum from a code.
0408: */
0409: public synchronized ImageDatum createImageDatum(final String code)
0410: throws FactoryException {
0411: final ImageDatum datum;
0412: final String key = trimAuthority(code);
0413: final Object cached = get(key);
0414: if (cached instanceof ImageDatum) {
0415: datum = (ImageDatum) cached;
0416: } else {
0417: datum = getBackingStore().createImageDatum(code);
0418: }
0419: put(key, datum);
0420: return datum;
0421: }
0422:
0423: /**
0424: * Returns a vertical datum from a code.
0425: */
0426: public synchronized VerticalDatum createVerticalDatum(
0427: final String code) throws FactoryException {
0428: final VerticalDatum datum;
0429: final String key = trimAuthority(code);
0430: final Object cached = get(key);
0431: if (cached instanceof VerticalDatum) {
0432: datum = (VerticalDatum) cached;
0433: } else {
0434: datum = getBackingStore().createVerticalDatum(code);
0435: }
0436: put(key, datum);
0437: return datum;
0438: }
0439:
0440: /**
0441: * Returns a temporal datum from a code.
0442: */
0443: public synchronized TemporalDatum createTemporalDatum(
0444: final String code) throws FactoryException {
0445: final TemporalDatum datum;
0446: final String key = trimAuthority(code);
0447: final Object cached = get(key);
0448: if (cached instanceof TemporalDatum) {
0449: datum = (TemporalDatum) cached;
0450: } else {
0451: datum = getBackingStore().createTemporalDatum(code);
0452: }
0453: put(key, datum);
0454: return datum;
0455: }
0456:
0457: /**
0458: * Returns a geodetic datum from a code.
0459: */
0460: public synchronized GeodeticDatum createGeodeticDatum(
0461: final String code) throws FactoryException {
0462: final GeodeticDatum datum;
0463: final String key = trimAuthority(code);
0464: final Object cached = get(key);
0465: if (cached instanceof GeodeticDatum) {
0466: datum = (GeodeticDatum) cached;
0467: } else {
0468: datum = getBackingStore().createGeodeticDatum(code);
0469: }
0470: put(key, datum);
0471: return datum;
0472: }
0473:
0474: /**
0475: * Returns an ellipsoid from a code.
0476: */
0477: public synchronized Ellipsoid createEllipsoid(final String code)
0478: throws FactoryException {
0479: final Ellipsoid ellipsoid;
0480: final String key = trimAuthority(code);
0481: final Object cached = get(key);
0482: if (cached instanceof Ellipsoid) {
0483: ellipsoid = (Ellipsoid) cached;
0484: } else {
0485: ellipsoid = getBackingStore().createEllipsoid(code);
0486: }
0487: put(key, ellipsoid);
0488: return ellipsoid;
0489: }
0490:
0491: /**
0492: * Returns a prime meridian from a code.
0493: */
0494: public synchronized PrimeMeridian createPrimeMeridian(
0495: final String code) throws FactoryException {
0496: final PrimeMeridian meridian;
0497: final String key = trimAuthority(code);
0498: final Object cached = get(key);
0499: if (cached instanceof PrimeMeridian) {
0500: meridian = (PrimeMeridian) cached;
0501: } else {
0502: meridian = getBackingStore().createPrimeMeridian(code);
0503: }
0504: put(key, meridian);
0505: return meridian;
0506: }
0507:
0508: /**
0509: * Returns an extent (usually an area of validity) from a code.
0510: */
0511: public synchronized Extent createExtent(final String code)
0512: throws FactoryException {
0513: final Extent extent;
0514: final String key = trimAuthority(code);
0515: final Object cached = get(key);
0516: if (cached instanceof Extent) {
0517: extent = (Extent) cached;
0518: } else {
0519: extent = getBackingStore().createExtent(code);
0520: }
0521: put(key, extent);
0522: return extent;
0523: }
0524:
0525: /**
0526: * Returns an arbitrary coordinate system from a code.
0527: */
0528: public synchronized CoordinateSystem createCoordinateSystem(
0529: final String code) throws FactoryException {
0530: final CoordinateSystem cs;
0531: final String key = trimAuthority(code);
0532: final Object cached = get(key);
0533: if (cached instanceof CoordinateSystem) {
0534: cs = (CoordinateSystem) cached;
0535: } else {
0536: cs = getBackingStore().createCoordinateSystem(code);
0537: }
0538: put(key, cs);
0539: return cs;
0540: }
0541:
0542: /**
0543: * Returns a cartesian coordinate system from a code.
0544: */
0545: public synchronized CartesianCS createCartesianCS(final String code)
0546: throws FactoryException {
0547: final CartesianCS cs;
0548: final String key = trimAuthority(code);
0549: final Object cached = get(key);
0550: if (cached instanceof CartesianCS) {
0551: cs = (CartesianCS) cached;
0552: } else {
0553: cs = getBackingStore().createCartesianCS(code);
0554: }
0555: put(key, cs);
0556: return cs;
0557: }
0558:
0559: /**
0560: * Returns a polar coordinate system from a code.
0561: */
0562: public synchronized PolarCS createPolarCS(final String code)
0563: throws FactoryException {
0564: final PolarCS cs;
0565: final String key = trimAuthority(code);
0566: final Object cached = get(key);
0567: if (cached instanceof PolarCS) {
0568: cs = (PolarCS) cached;
0569: } else {
0570: cs = getBackingStore().createPolarCS(code);
0571: }
0572: put(key, cs);
0573: return cs;
0574: }
0575:
0576: /**
0577: * Returns a cylindrical coordinate system from a code.
0578: */
0579: public synchronized CylindricalCS createCylindricalCS(
0580: final String code) throws FactoryException {
0581: final CylindricalCS cs;
0582: final String key = trimAuthority(code);
0583: final Object cached = get(key);
0584: if (cached instanceof CylindricalCS) {
0585: cs = (CylindricalCS) cached;
0586: } else {
0587: cs = getBackingStore().createCylindricalCS(code);
0588: }
0589: put(key, cs);
0590: return cs;
0591: }
0592:
0593: /**
0594: * Returns a spherical coordinate system from a code.
0595: */
0596: public synchronized SphericalCS createSphericalCS(final String code)
0597: throws FactoryException {
0598: final SphericalCS cs;
0599: final String key = trimAuthority(code);
0600: final Object cached = get(key);
0601: if (cached instanceof SphericalCS) {
0602: cs = (SphericalCS) cached;
0603: } else {
0604: cs = getBackingStore().createSphericalCS(code);
0605: }
0606: put(key, cs);
0607: return cs;
0608: }
0609:
0610: /**
0611: * Returns an ellipsoidal coordinate system from a code.
0612: */
0613: public synchronized EllipsoidalCS createEllipsoidalCS(
0614: final String code) throws FactoryException {
0615: final EllipsoidalCS cs;
0616: final String key = trimAuthority(code);
0617: final Object cached = get(key);
0618: if (cached instanceof EllipsoidalCS) {
0619: cs = (EllipsoidalCS) cached;
0620: } else {
0621: cs = getBackingStore().createEllipsoidalCS(code);
0622: }
0623: put(key, cs);
0624: return cs;
0625: }
0626:
0627: /**
0628: * Returns a vertical coordinate system from a code.
0629: */
0630: public synchronized VerticalCS createVerticalCS(final String code)
0631: throws FactoryException {
0632: final VerticalCS cs;
0633: final String key = trimAuthority(code);
0634: final Object cached = get(key);
0635: if (cached instanceof VerticalCS) {
0636: cs = (VerticalCS) cached;
0637: } else {
0638: cs = getBackingStore().createVerticalCS(code);
0639: }
0640: put(key, cs);
0641: return cs;
0642: }
0643:
0644: /**
0645: * Returns a temporal coordinate system from a code.
0646: */
0647: public synchronized TimeCS createTimeCS(final String code)
0648: throws FactoryException {
0649: final TimeCS cs;
0650: final String key = trimAuthority(code);
0651: final Object cached = get(key);
0652: if (cached instanceof TimeCS) {
0653: cs = (TimeCS) cached;
0654: } else {
0655: cs = getBackingStore().createTimeCS(code);
0656: }
0657: put(key, cs);
0658: return cs;
0659: }
0660:
0661: /**
0662: * Returns a coordinate system axis from a code.
0663: */
0664: public synchronized CoordinateSystemAxis createCoordinateSystemAxis(
0665: final String code) throws FactoryException {
0666: final CoordinateSystemAxis axis;
0667: final String key = trimAuthority(code);
0668: final Object cached = get(key);
0669: if (cached instanceof CoordinateSystemAxis) {
0670: axis = (CoordinateSystemAxis) cached;
0671: } else {
0672: axis = getBackingStore().createCoordinateSystemAxis(code);
0673: }
0674: put(key, axis);
0675: return axis;
0676: }
0677:
0678: /**
0679: * Returns an unit from a code.
0680: */
0681: public synchronized Unit createUnit(final String code)
0682: throws FactoryException {
0683: final Unit unit;
0684: final String key = trimAuthority(code);
0685: final Object cached = get(key);
0686: if (cached instanceof Unit) {
0687: unit = (Unit) cached;
0688: } else {
0689: unit = getBackingStore().createUnit(code);
0690: }
0691: put(key, unit);
0692: return unit;
0693: }
0694:
0695: /**
0696: * Returns an arbitrary coordinate reference system from a code.
0697: */
0698: public synchronized CoordinateReferenceSystem createCoordinateReferenceSystem(
0699: final String code) throws FactoryException {
0700: final CoordinateReferenceSystem crs;
0701: final String key = trimAuthority(code);
0702: final Object cached = get(key);
0703: if (cached instanceof CoordinateReferenceSystem) {
0704: crs = (CoordinateReferenceSystem) cached;
0705: } else {
0706: crs = getBackingStore().createCoordinateReferenceSystem(
0707: code);
0708: }
0709: put(key, crs);
0710: return crs;
0711: }
0712:
0713: /**
0714: * Returns a 3D coordinate reference system from a code.
0715: */
0716: public synchronized CompoundCRS createCompoundCRS(final String code)
0717: throws FactoryException {
0718: final CompoundCRS crs;
0719: final String key = trimAuthority(code);
0720: final Object cached = get(key);
0721: if (cached instanceof CompoundCRS) {
0722: crs = (CompoundCRS) cached;
0723: } else {
0724: crs = getBackingStore().createCompoundCRS(code);
0725: }
0726: put(key, crs);
0727: return crs;
0728: }
0729:
0730: /**
0731: * Returns a derived coordinate reference system from a code.
0732: */
0733: public synchronized DerivedCRS createDerivedCRS(final String code)
0734: throws FactoryException {
0735: final DerivedCRS crs;
0736: final String key = trimAuthority(code);
0737: final Object cached = get(key);
0738: if (cached instanceof DerivedCRS) {
0739: crs = (DerivedCRS) cached;
0740: } else {
0741: crs = getBackingStore().createDerivedCRS(code);
0742: }
0743: put(key, crs);
0744: return crs;
0745: }
0746:
0747: /**
0748: * Returns an engineering coordinate reference system from a code.
0749: */
0750: public synchronized EngineeringCRS createEngineeringCRS(
0751: final String code) throws FactoryException {
0752: final EngineeringCRS crs;
0753: final String key = trimAuthority(code);
0754: final Object cached = get(key);
0755: if (cached instanceof EngineeringCRS) {
0756: crs = (EngineeringCRS) cached;
0757: } else {
0758: crs = getBackingStore().createEngineeringCRS(code);
0759: }
0760: put(key, crs);
0761: return crs;
0762: }
0763:
0764: /**
0765: * Returns a geographic coordinate reference system from a code.
0766: */
0767: public synchronized GeographicCRS createGeographicCRS(
0768: final String code) throws FactoryException {
0769: final GeographicCRS crs;
0770: final String key = trimAuthority(code);
0771: final Object cached = get(key);
0772: if (cached instanceof GeographicCRS) {
0773: crs = (GeographicCRS) cached;
0774: } else {
0775: crs = getBackingStore().createGeographicCRS(code);
0776: }
0777: put(key, crs);
0778: return crs;
0779: }
0780:
0781: /**
0782: * Returns a geocentric coordinate reference system from a code.
0783: */
0784: public synchronized GeocentricCRS createGeocentricCRS(
0785: final String code) throws FactoryException {
0786: final GeocentricCRS crs;
0787: final String key = trimAuthority(code);
0788: final Object cached = get(key);
0789: if (cached instanceof GeocentricCRS) {
0790: crs = (GeocentricCRS) cached;
0791: } else {
0792: crs = getBackingStore().createGeocentricCRS(code);
0793: }
0794: put(key, crs);
0795: return crs;
0796: }
0797:
0798: /**
0799: * Returns an image coordinate reference system from a code.
0800: */
0801: public synchronized ImageCRS createImageCRS(final String code)
0802: throws FactoryException {
0803: final ImageCRS crs;
0804: final String key = trimAuthority(code);
0805: final Object cached = get(key);
0806: if (cached instanceof ImageCRS) {
0807: crs = (ImageCRS) cached;
0808: } else {
0809: crs = getBackingStore().createImageCRS(code);
0810: }
0811: put(key, crs);
0812: return crs;
0813: }
0814:
0815: /**
0816: * Returns a projected coordinate reference system from a code.
0817: */
0818: public synchronized ProjectedCRS createProjectedCRS(
0819: final String code) throws FactoryException {
0820: final ProjectedCRS crs;
0821: final String key = trimAuthority(code);
0822: final Object cached = get(key);
0823: if (cached instanceof ProjectedCRS) {
0824: crs = (ProjectedCRS) cached;
0825: } else {
0826: crs = getBackingStore().createProjectedCRS(code);
0827: }
0828: put(key, crs);
0829: return crs;
0830: }
0831:
0832: /**
0833: * Returns a temporal coordinate reference system from a code.
0834: */
0835: public synchronized TemporalCRS createTemporalCRS(final String code)
0836: throws FactoryException {
0837: final TemporalCRS crs;
0838: final String key = trimAuthority(code);
0839: final Object cached = get(key);
0840: if (cached instanceof TemporalCRS) {
0841: crs = (TemporalCRS) cached;
0842: } else {
0843: crs = getBackingStore().createTemporalCRS(code);
0844: }
0845: put(key, crs);
0846: return crs;
0847: }
0848:
0849: /**
0850: * Returns a vertical coordinate reference system from a code.
0851: */
0852: public synchronized VerticalCRS createVerticalCRS(final String code)
0853: throws FactoryException {
0854: final VerticalCRS crs;
0855: final String key = trimAuthority(code);
0856: final Object cached = get(key);
0857: if (cached instanceof VerticalCRS) {
0858: crs = (VerticalCRS) cached;
0859: } else {
0860: crs = getBackingStore().createVerticalCRS(code);
0861: }
0862: put(key, crs);
0863: return crs;
0864: }
0865:
0866: /**
0867: * Returns a parameter descriptor from a code.
0868: *
0869: * @since 2.2
0870: */
0871: public synchronized ParameterDescriptor createParameterDescriptor(
0872: final String code) throws FactoryException {
0873: final ParameterDescriptor parameter;
0874: final String key = trimAuthority(code);
0875: final Object cached = get(key);
0876: if (cached instanceof ParameterDescriptor) {
0877: parameter = (ParameterDescriptor) cached;
0878: } else {
0879: parameter = getBackingStore().createParameterDescriptor(
0880: code);
0881: }
0882: put(key, parameter);
0883: return parameter;
0884: }
0885:
0886: /**
0887: * Returns an operation method from a code.
0888: *
0889: * @since 2.2
0890: */
0891: public synchronized OperationMethod createOperationMethod(
0892: final String code) throws FactoryException {
0893: final OperationMethod method;
0894: final String key = trimAuthority(code);
0895: final Object cached = get(key);
0896: if (cached instanceof OperationMethod) {
0897: method = (OperationMethod) cached;
0898: } else {
0899: method = getBackingStore().createOperationMethod(code);
0900: }
0901: put(key, method);
0902: return method;
0903: }
0904:
0905: /**
0906: * Returns an operation from a single operation code.
0907: *
0908: * @since 2.2
0909: */
0910: public synchronized CoordinateOperation createCoordinateOperation(
0911: final String code) throws FactoryException {
0912: final CoordinateOperation operation;
0913: final String key = trimAuthority(code);
0914: final Object cached = get(key);
0915: if (cached instanceof CoordinateOperation) {
0916: operation = (CoordinateOperation) cached;
0917: } else {
0918: operation = getBackingStore().createCoordinateOperation(
0919: code);
0920: }
0921: put(key, operation);
0922: return operation;
0923: }
0924:
0925: /**
0926: * Returns an operation from coordinate reference system codes.
0927: *
0928: * @since 2.2
0929: */
0930: public synchronized Set/*<CoordinateOperation>*/createFromCoordinateReferenceSystemCodes(
0931: final String sourceCode, final String targetCode)
0932: throws FactoryException {
0933: final Set/*<CoordinateOperation>*/operations;
0934: final CodePair key = new CodePair(trimAuthority(sourceCode),
0935: trimAuthority(targetCode));
0936: final Object cached = get(key);
0937: if (cached instanceof Set/*<CoordinateOperation>*/) {
0938: operations = (Set/*<CoordinateOperation>*/) cached;
0939: } else {
0940: operations = Collections.unmodifiableSet(getBackingStore()
0941: .createFromCoordinateReferenceSystemCodes(
0942: sourceCode, targetCode));
0943: }
0944: put(key, operations);
0945: return operations;
0946: }
0947:
0948: /**
0949: * A pair of codes for operations to cache with
0950: * {@link #createFromCoordinateReferenceSystemCodes}.
0951: */
0952: private static final class CodePair {
0953: private final String source, target;
0954:
0955: public CodePair(final String source, final String target) {
0956: this .source = source;
0957: this .target = target;
0958: }
0959:
0960: public int hashCode() {
0961: int code = 0;
0962: if (source != null)
0963: code = source.hashCode();
0964: if (target != null)
0965: code += target.hashCode() * 37;
0966: return code;
0967: }
0968:
0969: public boolean equals(final Object other) {
0970: if (other instanceof CodePair) {
0971: final CodePair that = (CodePair) other;
0972: return Utilities.equals(this .source, that.source)
0973: && Utilities.equals(this .target, that.target);
0974: }
0975: return false;
0976: }
0977:
0978: public String toString() {
0979: return source + " \u21E8 " + target;
0980: }
0981: }
0982:
0983: /**
0984: * Returns a finder which can be used for looking up unidentified objects.
0985: * The default implementation delegates lookup to the underlying backing
0986: * store and caches the result.
0987: *
0988: * @since 2.4
0989: */
0990: //@Override
0991: public synchronized IdentifiedObjectFinder getIdentifiedObjectFinder(
0992: final Class/*<? extends IdentifiedObject>*/type)
0993: throws FactoryException {
0994: return new Finder(getBackingStore().getIdentifiedObjectFinder(
0995: type));
0996: }
0997:
0998: /**
0999: * An implementation of {@link IdentifiedObjectFinder} which delegates
1000: * the work to the underlying backing store and caches the result.
1001: * <p>
1002: * <b>Implementation note:</b> we will create objects using directly the underlying backing
1003: * store, not using the cache. This is because hundred of objects may be created during a
1004: * scan while only one will be typically retained. We don't want to overload the cache with
1005: * every false candidates that we encounter during the scan.
1006: */
1007: private final class Finder extends IdentifiedObjectFinder.Adapter {
1008: /**
1009: * Creates a finder for the underlying backing store.
1010: */
1011: Finder(final IdentifiedObjectFinder finder) {
1012: super (finder);
1013: }
1014:
1015: /**
1016: * Looks up an object from this authority factory which is equals, ignoring metadata,
1017: * to the specified object. The default implementation performs the same lookup than
1018: * the backing store and caches the result.
1019: */
1020: //@Override
1021: public IdentifiedObject find(final IdentifiedObject object)
1022: throws FactoryException {
1023: /*
1024: * Do not synchronize on 'BufferedAuthorityFactory.this'. This method may take a
1025: * while to execute and we don't want to block other threads. The synchronizations
1026: * in the 'create' methods and in the 'findPool' map should be suffisient.
1027: *
1028: * TODO: avoid to search for the same object twice. For now we consider that this
1029: * is not a big deal if the same object is searched twice; it is "just" a
1030: * waste of CPU.
1031: */
1032: IdentifiedObject candidate;
1033: synchronized (findPool) {
1034: candidate = (IdentifiedObject) findPool.get(object);
1035: }
1036: if (candidate == null) {
1037: // Must delegates to 'finder' (not to 'super') in order to take
1038: // advantage of the method overriden by AllAuthoritiesFactory.
1039: candidate = finder.find(object);
1040: if (candidate != null) {
1041: synchronized (findPool) {
1042: findPool.put(object, candidate);
1043: }
1044: }
1045: }
1046: return candidate;
1047: }
1048:
1049: /**
1050: * Returns the identifier for the specified object.
1051: */
1052: //@Override
1053: public String findIdentifier(final IdentifiedObject object)
1054: throws FactoryException {
1055: IdentifiedObject candidate;
1056: synchronized (findPool) {
1057: candidate = (IdentifiedObject) findPool.get(object);
1058: }
1059: if (candidate != null) {
1060: return getIdentifier(candidate);
1061: }
1062: // We don't rely on super-class implementation, because we want to
1063: // take advantage of the method overriden by AllAuthoritiesFactory.
1064: return finder.findIdentifier(object);
1065: }
1066: }
1067:
1068: /**
1069: * Releases resources immediately instead of waiting for the garbage collector.
1070: */
1071: public synchronized void dispose() throws FactoryException {
1072: if (backingStore != null) {
1073: backingStore.dispose();
1074: backingStore = null;
1075: }
1076: pool.clear();
1077: super .dispose();
1078: }
1079:
1080: /**
1081: * Returns an object from the pool for the specified code. If the object was retained as a
1082: * {@linkplain Reference weak reference}, the {@link Reference#get referent} is returned.
1083: *
1084: * @todo Consider logging a message here to the finer or finest level.
1085: */
1086: private Object get(final Object key) {
1087: assert Thread.holdsLock(this );
1088: Object object = pool.get(key);
1089: if (object instanceof Reference) {
1090: object = ((Reference) object).get();
1091: }
1092: return object;
1093: }
1094:
1095: /**
1096: * Put an element in the pool. This method is invoked everytime a {@code createFoo(...)}
1097: * method is invoked, even if an object was already in the pool for the given code, for
1098: * the following reasons: 1) Replaces weak reference by strong reference (if applicable)
1099: * and 2) Alters the linked hash set order, so that this object is declared as the last
1100: * one used.
1101: */
1102: private void put(final Object key, final Object object) {
1103: assert Thread.holdsLock(this );
1104: pool.put(key, object);
1105: int toReplace = pool.size() - maxStrongReferences;
1106: if (toReplace > 0) {
1107: for (final Iterator it = pool.entrySet().iterator(); it
1108: .hasNext();) {
1109: final Map.Entry entry = (Map.Entry) it.next();
1110: final Object value = entry.getValue();
1111: if (value instanceof Reference) {
1112: if (((Reference) value).get() == null) {
1113: it.remove();
1114: }
1115: continue;
1116: }
1117: entry.setValue(new WeakReference(value));
1118: if (--toReplace == 0) {
1119: break;
1120: }
1121: }
1122: }
1123: }
1124: }
|