0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2005-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.factory;
0017:
0018: // J2SE dependencies
0019: import java.awt.RenderingHints;
0020: import java.io.File;
0021: import java.util.Arrays;
0022: import java.util.Collections;
0023: import java.util.Iterator;
0024: import java.util.Map;
0025: import java.util.HashMap;
0026: import java.util.Set;
0027: import java.util.TreeSet;
0028: import java.lang.reflect.Field;
0029: import java.lang.reflect.Modifier;
0030: import javax.sql.DataSource;
0031:
0032: import org.opengis.util.InternationalString;
0033:
0034: import org.geotools.util.logging.Logging;
0035: import org.geotools.resources.Utilities;
0036:
0037: /**
0038: * A set of hints providing control on factories to be used. Those hints are typically used by
0039: * renderers or {@linkplain org.opengis.coverage.processing.GridCoverageProcessor grid coverage
0040: * processors} for example. They provides a way to control low-level details. Example:
0041: * <p>
0042: * <blockquote><pre>
0043: * CoordinateOperationFactory myFactory = &hellip
0044: * Hints hints = new Hints(Hints.{@linkplain #COORDINATE_OPERATION_FACTORY}, myFactory);
0045: * AbstractProcessor processor = new DefaultProcessor(hints);
0046: * </pre></blockquote>
0047: * <p>
0048: * Any hint mentioned by this class is considered to be API, failure to make
0049: * use of a hint by a GeoTools factory implementation is considered a bug (as
0050: * it will prevent the use of this library for application specific tasks).
0051: * <p>
0052: * When hints are used in conjuction with the {@linkplain FactoryRegistry factory service
0053: * discovery mechanism} we have the complete geotools plugin system. By using hints to
0054: * allow application code to effect service discovery we allow client code to
0055: * retarget the geotools library for their needs.
0056: *
0057: * @since 2.1
0058: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
0059: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
0060: * @author Martin Desruisseaux
0061: * @author Jody Garnett
0062: */
0063: public class Hints extends RenderingHints {
0064: /**
0065: * A set of system-wide hints to use by default.
0066: */
0067: private static final Hints GLOBAL = new Hints(Collections.EMPTY_MAP);
0068:
0069: /**
0070: * {@code true} if {@link #scanSystemProperties} needs to be invoked.
0071: */
0072: private static boolean needScan = true;
0073:
0074: ////////////////////////////////////////////////////////////////////////
0075: //////// ////////
0076: //////// Factories ////////
0077: //////// ////////
0078: //////// The following keys are mainly about getting instances ////////
0079: //////// of the right factory. Keys for factory configuration ////////
0080: //////// other than JTS are defined in their own categories ////////
0081: //////// after this one. JTS factories are treated especially ////////
0082: //////// because they are implemented outside Geotools. ////////
0083: //////// ////////
0084: ////////////////////////////////////////////////////////////////////////
0085:
0086: /**
0087: * The {@link com.vividsolutions.jts.geom.GeometryFactory} instance to use.
0088: *
0089: * @see org.geotools.geometry.jts.FactoryFinder#getGeometryFactory
0090: */
0091: public static final ClassKey JTS_GEOMETRY_FACTORY = new ClassKey(
0092: "com.vividsolutions.jts.geom.GeometryFactory");
0093:
0094: /**
0095: * The {@link com.vividsolutions.jts.geom.CoordinateSequenceFactory} instance to use.
0096: *
0097: * @see org.geotools.geometry.jts.FactoryFinder#getCoordinateSequenceFactory
0098: */
0099: public static final ClassKey JTS_COORDINATE_SEQUENCE_FACTORY = new ClassKey(
0100: "com.vividsolutions.jts.geom.CoordinateSequenceFactory");
0101:
0102: /**
0103: * The {@link com.vividsolutions.jts.geom.PrecisionModel} instance to use.
0104: *
0105: * @see org.geotools.geometry.jts.FactoryFinder#getPrecisionModel
0106: */
0107: public static final Key JTS_PRECISION_MODEL = new Key(
0108: "com.vividsolutions.jts.geom.PrecisionModel");
0109:
0110: /**
0111: * The spatial reference ID for {@link com.vividsolutions.jts.geom.GeometryFactory}.
0112: *
0113: * @see org.geotools.geometry.jts.FactoryFinder#getGeometryFactory
0114: */
0115: public static final Key JTS_SRID = new Key(Integer.class);
0116:
0117: /**
0118: * The {@link org.opengis.referencing.crs.CRSAuthorityFactory} instance to use.
0119: *
0120: * @see org.geotools.referencing.FactoryFinder#getCRSAuthorityFactory
0121: */
0122: public static final ClassKey CRS_AUTHORITY_FACTORY = new ClassKey(
0123: "org.opengis.referencing.crs.CRSAuthorityFactory");
0124:
0125: /**
0126: * The {@link org.opengis.referencing.cs.CSAuthorityFactory} instance to use.
0127: *
0128: * @see org.geotools.referencing.FactoryFinder#getCSAuthorityFactory
0129: */
0130: public static final ClassKey CS_AUTHORITY_FACTORY = new ClassKey(
0131: "org.opengis.referencing.cs.CSAuthorityFactory");
0132:
0133: /**
0134: * The {@link org.opengis.referencing.datum.DatumAuthorityFactory} instance to use.
0135: *
0136: * @see org.geotools.referencing.FactoryFinder#getDatumAuthorityFactory
0137: */
0138: public static final ClassKey DATUM_AUTHORITY_FACTORY = new ClassKey(
0139: "org.opengis.referencing.datum.DatumAuthorityFactory");
0140:
0141: /**
0142: * The {@link org.opengis.referencing.crs.CRSFactory} instance to use.
0143: *
0144: * @see org.geotools.referencing.FactoryFinder#getCRSFactory
0145: */
0146: public static final ClassKey CRS_FACTORY = new ClassKey(
0147: "org.opengis.referencing.crs.CRSFactory");
0148:
0149: /**
0150: * The {@link org.opengis.referencing.cs.CSFactory} instance to use.
0151: *
0152: * @see org.geotools.referencing.FactoryFinder#getCSFactory
0153: */
0154: public static final ClassKey CS_FACTORY = new ClassKey(
0155: "org.opengis.referencing.cs.CSFactory");
0156:
0157: /**
0158: * The {@link org.opengis.referencing.datum.DatumFactory} instance to use.
0159: *
0160: * @see org.geotools.referencing.FactoryFinder#getDatumFactory
0161: */
0162: public static final ClassKey DATUM_FACTORY = new ClassKey(
0163: "org.opengis.referencing.datum.DatumFactory");
0164:
0165: /**
0166: * The {@link org.opengis.referencing.operation.CoordinateOperationFactory} instance to use.
0167: *
0168: * @see org.geotools.referencing.FactoryFinder#getCoordinateOperationFactory
0169: */
0170: public static final ClassKey COORDINATE_OPERATION_FACTORY = new ClassKey(
0171: "org.opengis.referencing.operation.CoordinateOperationFactory");
0172:
0173: /**
0174: * The {@link org.opengis.referencing.operation.CoordinateOperationAuthorityFactory} instance
0175: * to use.
0176: *
0177: * @see org.geotools.referencing.FactoryFinder#getCoordinateOperationAuthorityFactory
0178: */
0179: public static final ClassKey COORDINATE_OPERATION_AUTHORITY_FACTORY = new ClassKey(
0180: "org.opengis.referencing.operation.CoordinateOperationAuthorityFactory");
0181:
0182: /**
0183: * The {@link org.opengis.referencing.operation.MathTransformFactory} instance to use.
0184: *
0185: * @see org.geotools.referencing.FactoryFinder#getMathTransformFactory
0186: */
0187: public static final ClassKey MATH_TRANSFORM_FACTORY = new ClassKey(
0188: "org.opengis.referencing.operation.MathTransformFactory");
0189:
0190: /**
0191: * The {@link org.geotools.data.FeatureLockFactory} instance to use.
0192: *
0193: * @see CommonFactoryFinder#getFeatureLockFactory
0194: *
0195: * @since 2.4
0196: */
0197: public static final ClassKey FEATURE_LOCK_FACTORY = new ClassKey(
0198: "org.geotools.data.FeatureLockFactory");
0199:
0200: /**
0201: * The {@link org.geotools.feature.FeatureCollections} instance to use.
0202: *
0203: * @see CommonFactoryFinder#getFeatureCollections
0204: *
0205: * @since 2.4
0206: */
0207: public static final ClassKey FEATURE_COLLECTIONS = new ClassKey(
0208: "org.geotools.feature.FeatureCollections");
0209:
0210: /**
0211: * The {@link org.geotools.feature.FeatureTypeFactory} instance to use.
0212: *
0213: * @see CommonFactoryFinder#getFeatureTypeFactory
0214: *
0215: * @since 2.4
0216: */
0217: public static final ClassKey FEATURE_TYPE_FACTORY = new ClassKey(
0218: "org.geotools.feature.FeatureTypeFactory");
0219:
0220: /**
0221: * Used to provide the <cite>type name</cite> for the returned
0222: * {@link org.geotools.feature.FeatureTypeFactory}. Values should
0223: * be instances of {@link String}.
0224: *
0225: * @since 2.4
0226: */
0227: public static final Key FEATURE_TYPE_FACTORY_NAME = new Key(
0228: String.class);
0229:
0230: /**
0231: * Whether the features returned by the feature collections should be considered detached from the
0232: * datastore, that is, they are updatable without altering the backing store (makes sense only
0233: * if features are kept in memory or if there is some transparent persistent mechanism in place,
0234: * such as the Hibernate one)
0235: *
0236: * @since 2.4
0237: */
0238: public static final Key FEATURE_DETACHED = new Key(Boolean.class);
0239:
0240: /**
0241: * Request that the features returned by the feature collections should
0242: * be 2D only, can be used to prevent the request of the third ordinate
0243: * when only two are going to be used.
0244: *
0245: * @since 2.4.1
0246: */
0247: public static final Key FEATURE_2D = new Key(Boolean.class);
0248:
0249: /**
0250: * The {@link org.geotools.styling.StyleFactory} instance to use.
0251: *
0252: * @see CommonFactoryFinder#getStyleFactory
0253: *
0254: * @since 2.4
0255: */
0256: public static final ClassKey STYLE_FACTORY = new ClassKey(
0257: "org.geotools.styling.StyleFactory");
0258:
0259: /**
0260: * The {@link org.geotools.feature.AttributeTypeFactory} instance to use.
0261: *
0262: * @see CommonFactoryFinder#getAttributeTypeFactory
0263: *
0264: * @since 2.4
0265: */
0266: public static final ClassKey ATTRIBUTE_TYPE_FACTORY = new ClassKey(
0267: "org.geotools.feature.AttributeTypeFactory");
0268:
0269: /**
0270: * The {@link org.opengis.filter.FilterFactory} instance to use.
0271: *
0272: * @see CommonFactoryFinder#getFilterFactory
0273: *
0274: * @since 2.4
0275: */
0276: public static final ClassKey FILTER_FACTORY = new ClassKey(
0277: "org.opengis.filter.FilterFactory");
0278:
0279: ////////////////////////////////////////////////////////////////////////
0280: //////// ////////
0281: //////// Coordinate Reference Systems ////////
0282: //////// ////////
0283: ////////////////////////////////////////////////////////////////////////
0284:
0285: /**
0286: * The default {@link org.opengis.referencing.crs.CoordinateReferenceSystem}
0287: * to use. This is used by some factories capable to provide a default CRS
0288: * when no one were explicitly specified by the user.
0289: *
0290: * @since 2.2
0291: */
0292: public static final Key DEFAULT_COORDINATE_REFERENCE_SYSTEM = new Key(
0293: "org.opengis.referencing.crs.CoordinateReferenceSystem");
0294:
0295: /**
0296: * Used to direct WKT CRS Authority to a directory containing extra definitions.
0297: * The value should be an instance of {@link File} or {@link String} refering to
0298: * an existing directory.
0299: * <p>
0300: * Filenames in the supplied directory should be of the form
0301: * <code><var>authority</var>.properties</code> where <var>authority</var>
0302: * is the authority name space to use. For example the
0303: * {@value org.geotools.referencing.factory.epsg.FactoryUsingWKT#FILENAME}
0304: * file contains extra CRS to add as new EPSG codes.
0305: * <p>
0306: * To set the directory on the command line:
0307: *
0308: * <blockquote><pre>
0309: * -D{@value GeoTools#CRS_AUTHORITY_EXTRA_DIRECTORY}=<var>path</var>
0310: * </pre></blockquote>
0311: *
0312: * @since 2.4
0313: */
0314: public static final FileKey CRS_AUTHORITY_EXTRA_DIRECTORY = new FileKey(
0315: false);
0316:
0317: /**
0318: * The {@linkplain javax.sql.DataSource data source} name to lookup from JNDI when
0319: * initializing the {@linkplain org.geotools.referencing.factory.epsg EPSG factory}.
0320: * Possible values:
0321: * <ul>
0322: * <li>{@link String} - used with JNDI to locate datasource. This hint has no effect if
0323: * there is no {@linkplain javax.naming.InitialContext JNDI initial context} setup.</li>
0324: * <li>{@linkplain javax.sql.DataSource} - used as is.</li>
0325: * <li>missing - default to
0326: * {@value org.geotools.referencing.factory.epsg.ThreadedEpsgFactory#DATASOURCE_NAME}.</li>
0327: * </ul>
0328: * <p>
0329: * To set on the command line:
0330: * <blockquote><pre>
0331: * -D{@value GeoTools#EPSG_DATA_SOURCE}=<var>jndiReference</var>
0332: * </pre></blockquote>
0333: *
0334: * @since 2.4
0335: */
0336: public static final Key EPSG_DATA_SOURCE = new DataSourceKey();
0337:
0338: /**
0339: * The preferred datum shift method to use for
0340: * {@linkplain org.opengis.referencing.operation.CoordinateOperation coordinate operations}.
0341: * Valid values are {@code "Molodenski"}, {@code "Abridged_Molodenski"} or {@code "Geocentric"}.
0342: * Other values may be supplied if a {@linkplain org.opengis.referencing.operation.MathTransform
0343: * math transform} exists for that name, but this is not guaranteed to work.
0344: *
0345: * @see org.geotools.referencing.FactoryFinder#getCoordinateOperationFactory
0346: */
0347: public static final OptionKey DATUM_SHIFT_METHOD = new OptionKey(
0348: "Molodenski", "Abridged_Molodenski", "Geocentric", "*");
0349:
0350: /**
0351: * Tells if {@linkplain org.opengis.referencing.operation.CoordinateOperation coordinate
0352: * operations} should be allowed even when a datum shift is required while no method is
0353: * found applicable. It may be for example that no
0354: * {@linkplain org.geotools.referencing.datum.BursaWolfParameters Bursa Wolf parameters}
0355: * were found for a datum shift. The default value is {@link Boolean#FALSE FALSE}, which means
0356: * that {@linkplain org.geotools.referencing.operation.DefaultCoordinateOperationFactory
0357: * coordinate operation factory} throws an exception if such a case occurs. If this hint is
0358: * set to {@code TRUE}, then the user is strongly encouraged to check the
0359: * {@linkplain org.opengis.referencing.operation.CoordinateOperation#getPositionalAccuracy
0360: * positional accuracy} for every transformation created. If the set of positional accuracy
0361: * contains {@link org.geotools.metadata.iso.quality.PositionalAccuracyImpl#DATUM_SHIFT_OMITTED
0362: * DATUM_SHIFT_OMITTED}, this means that an "ellipsoid shift" were applied without real datum
0363: * shift method available, and the transformed coordinates may have one kilometer error. The
0364: * application should warn the user (e.g. popup a message dialog box) in such case.
0365: *
0366: * @see org.geotools.referencing.FactoryFinder#getCoordinateOperationFactory
0367: */
0368: public static final Key LENIENT_DATUM_SHIFT = new Key(Boolean.class);
0369:
0370: /**
0371: * Tells if the {@linkplain org.opengis.referencing.cs.CoordinateSystem coordinate systems}
0372: * created by an {@linkplain org.opengis.referencing.cs.CSAuthorityFactory authority factory}
0373: * should be forced to (<var>longitude</var>,<var>latitude</var>) axis order. This hint is
0374: * especially useful for creating
0375: * {@linkplan org.opengis.referencing.crs.CoordinateReferenceSystem coordinate reference system}
0376: * objects from <A HREF="http://www.epsg.org">EPSG</A> codes. Most
0377: * {@linkplan org.opengis.referencing.crs.GeographicCRS geographic CRS} defined in the EPSG
0378: * database use (<var>latitude</var>,<var>longitude</var>) axis order. Unfortunatly, many data
0379: * sources available in the world uses the opposite axis order and still claim to use a CRS
0380: * described by an EPSG code. This hint allows to handle such data.
0381: * <p>
0382: * This hint shall be passed to the
0383: * <code>{@linkplain org.geotools.referencing.FactoryFinder#getCRSAuthorityFactory
0384: * FactoryFinder.getCRSAuthorityFactory}(...)</code> method. Whatever this hint is supported
0385: * or not is authority dependent. In the default Geotools configuration, this hint is supported
0386: * for the {@code "EPSG"} authority.
0387: * <p>
0388: * If this hint is not provided, then the default value depends on many factors including
0389: * {@linkplain System#getProperties system properties} and plugins available in the classpath.
0390: * In Geotools implementation, the default value is usually {@link Boolean#FALSE FALSE} with
0391: * one exception: If the <code>{@value
0392: * org.geotools.referencing.factory.epsg.LongitudeFirstFactory#SYSTEM_DEFAULT_KEY}</code>
0393: * system property is set to {@code true}, then the default value is {@code true} at least
0394: * for the {@linkplain org.geotools.referencing.factory.epsg.ThreadedEpsgFactory default EPSG
0395: * factory}.
0396: * <p>
0397: * If both the above-cited system property and this hint are provided, then
0398: * this hint has precedence. This allow axis order control on a data store
0399: * basis, and keep the system-wide property as the default value only for
0400: * cases where axis order is unspecified.
0401: * <p>
0402: * To set on the command line:
0403: * <blockquote><pre>
0404: * -D{@value GeoTools#FORCE_LONGITUDE_FIRST_AXIS_ORDER}=<var>longitudeFirst</var>
0405: * </pre></blockquote>
0406: *
0407: * @see org.geotools.referencing.FactoryFinder#getCSFactory
0408: * @see org.geotools.referencing.FactoryFinder#getCRSFactory
0409: * @see org.geotools.referencing.factory.OrderedAxisAuthorityFactory
0410: * @see org.geotools.referencing.factory.epsg.LongitudeFirstFactory
0411: * @tutorial http://docs.codehaus.org/display/GEOTOOLS/The+axis+order+issue
0412: *
0413: * @since 2.3
0414: */
0415: public static final Key FORCE_LONGITUDE_FIRST_AXIS_ORDER = new Key(
0416: Boolean.class);
0417:
0418: /**
0419: * Applies the {@link #FORCE_LONGITUDE_FIRST_AXIS_ORDER} hint to some factories that usually
0420: * ignore it. The <cite>axis order</cite> issue is of concern mostly to the {@code "EPSG"} name
0421: * space. Codes in the {@value org.geotools.referencing.factory.HTTP_AuthorityFactory#BASE_URL}
0422: * or {@code "urn:ogc"} name space usually ignore the axis order hint, especially the later
0423: * which is clearly defined by OGC - in theory users are not allowed to change its behavior.
0424: * If nevertheless a user really need to change its behavior, then he must provides explicitly
0425: * a comma separated list of authorities with this {@code FORCE_AXIS_ORDER_HONORING} hint in
0426: * addition to setting the {@link #FORCE_LONGITUDE_FIRST_AXIS_ORDER} hint.
0427: * <p>
0428: * <b>Example:</b> In order to apply the (<var>longitude</var>,<var>latitude</var>) axis order
0429: * to {@code "http://www.opengis.net/"} and {@code "urn:ogc"} name spaces in addition to EPSG,
0430: * use the following hints:
0431: *
0432: * <blockquote>
0433: * hints.put(FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
0434: * hints.put(FORCE_AXIS_ORDER_HONORING, "http, urn");
0435: * </blockquote>
0436: *
0437: * Note that the application of (<var>longitude</var>,<var>latitude</var>) axis order
0438: * to the {@code "urn:ogc"} name space is a clear violation of OGC specification.
0439: *
0440: * @since 2.4
0441: */
0442: public static final Key FORCE_AXIS_ORDER_HONORING = new Key(
0443: String.class);
0444:
0445: /**
0446: * Tells if the {@linkplain org.opengis.referencing.cs.CoordinateSystem coordinate systems}
0447: * created by an {@linkplain org.opengis.referencing.cs.CSAuthorityFactory authority factory}
0448: * should be forced to standard
0449: * {@linkplain org.opengis.referencing.cs.CoordinateSystemAxis#getDirection axis directions}.
0450: * If {@code true}, then {@linkplain org.opengis.referencing.cs.AxisDirection#SOUTH South} axis
0451: * directions are forced to {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North},
0452: * {@linkplain org.opengis.referencing.cs.AxisDirection#WEST West} axis directions are forced to
0453: * {@linkplain org.opengis.referencing.cs.AxisDirection#EAST East}, <cite>etc.</cite>
0454: * If {@code false}, then the axis directions are left unchanged.
0455: * <p>
0456: * This hint shall be passed to the
0457: * <code>{@linkplain org.geotools.referencing.FactoryFinder#getCRSAuthorityFactory
0458: * FactoryFinder.getCRSAuthorityFactory}(...)</code>
0459: * method. Whatever this hint is supported or not is authority dependent.
0460: *
0461: * @see org.geotools.referencing.FactoryFinder#getCSFactory
0462: * @see org.geotools.referencing.FactoryFinder#getCRSFactory
0463: * @see org.geotools.referencing.factory.OrderedAxisAuthorityFactory
0464: *
0465: * @since 2.3
0466: */
0467: public static final Key FORCE_STANDARD_AXIS_DIRECTIONS = new Key(
0468: Boolean.class);
0469:
0470: /**
0471: * Tells if the {@linkplain org.opengis.referencing.cs.CoordinateSystem coordinate systems}
0472: * created by an {@linkplain org.opengis.referencing.cs.CSAuthorityFactory authority factory}
0473: * should be forced to standard
0474: * {@linkplain org.opengis.referencing.cs.CoordinateSystemAxis#getUnit axis units}.
0475: * If {@code true}, then all angular units are forced to degrees and linear units to meters.
0476: * If {@code false}, then the axis units are left unchanged.
0477: * <p>
0478: * This hint shall be passed to the
0479: * <code>{@linkplain org.geotools.referencing.FactoryFinder#getCRSAuthorityFactory
0480: * FactoryFinder.getCRSAuthorityFactory}(...)</code> method. Whatever this hint is
0481: * supported or not is authority dependent.
0482: *
0483: * @see org.geotools.referencing.FactoryFinder#getCSFactory
0484: * @see org.geotools.referencing.FactoryFinder#getCRSFactory
0485: * @see org.geotools.referencing.factory.OrderedAxisAuthorityFactory
0486: *
0487: * @since 2.3
0488: */
0489: public static final Key FORCE_STANDARD_AXIS_UNITS = new Key(
0490: Boolean.class);
0491:
0492: /**
0493: * Policy to use for caching referencing objects. Valid values are:
0494: * <p>
0495: * <ul>
0496: * <li>{@code "weak"} for holding values through {@linkplain java.lang.ref.WeakReference
0497: * weak references}. This option do not actually cache the objects since the garbage
0498: * collector cleans weak references aggressively, but it allows sharing the instances
0499: * already created and still in use.</li>
0500: * <li>{@code "all"} for holding values through strong references.</li>
0501: * <li>{@code "none"} for disabling the cache.</li>
0502: * </ul>
0503: *
0504: * @since 2.4
0505: */
0506: public static final OptionKey BUFFER_POLICY = new OptionKey("weak",
0507: "all", "fixed", "none", "default");
0508:
0509: /**
0510: * The recommended maximum number of referencing objects to hold in a
0511: * {@linkplain org.opengis.referencing.AuthorityFactory authority factory}.
0512: *
0513: * @since 2.4
0514: */
0515: public static final IntegerKey BUFFER_LIMIT = new IntegerKey(50);
0516:
0517: /**
0518: * The maximum number of active AuthorityFactories.
0519: * <p>
0520: * This hint is treated as an absolute LIMIT for AbstractAuthorityMediator
0521: * instances such as as HsqlDialectEpsgMediator. As such this will be the
0522: * absolute limit on the number of database connections the mediator will
0523: * make use of. When non-positive there is no limit to the number of
0524: * connections used.
0525: * <p>
0526: * When this limit it reached, code will be forced to block while waiting
0527: * for a connection to become available.
0528: *
0529: * @since 2.4
0530: */
0531: public static final IntegerKey AUTHORITY_MAX_ACTIVE = new IntegerKey(
0532: 8);
0533:
0534: /**
0535: * Minimum number of objects required before the evictor will begin
0536: * removing objects. This value is also used by
0537: * AUTHORITY_SOFTMIN_EVICT_IDLETIME to keep this many idle workers
0538: * around.
0539: *
0540: * @since 2.4
0541: */
0542: public static final IntegerKey AUTHORITY_MIN_IDLE = new IntegerKey(
0543: 1);
0544:
0545: /**
0546: * The number of idle AuthorityFactories.
0547: * <p>
0548: * This hint is treated as a recommendation for AbstractAuthorityMediator
0549: * instances such as HsqlDialectEpsgMediator. As such this will control
0550: * the number of connections the mediator is comfortable having open.
0551: * <p>
0552: * If AUTHORITY_MAX_ACTIVE is set to 20, up to twenty connections will
0553: * be used during heavy load. If the AUTHORITY_MAX_IDLE is set to 10,
0554: * connections will be immediately reclaimed until only 10 are open.
0555: * <p>
0556: * When the amount of time specified by AUTHORITY_IDLE_WAIT
0557: * Max idle controls the maximum number of objects that can sit idle in the
0558: * pool at any time. When negative, there is no limit to the number of
0559: * objects that may be idle at one time.
0560: *
0561: * @since 2.4
0562: */
0563: public static final IntegerKey AUTHORITY_MAX_IDLE = new IntegerKey(
0564: 8);
0565:
0566: /**
0567: * When the evictor is run, if more time (in milliseconds) than the value in
0568: * AUTHORITY_MIN_EVICT_IDLETIME has passed, then the worker is destroyed.
0569: *
0570: * @since 2.4
0571: */
0572: public static final IntegerKey AUTHORITY_MIN_EVICT_IDLETIME = new IntegerKey(
0573: 2 * 60 * 000);
0574:
0575: /**
0576: * When the evictor is run, workers which have been idle for more than this
0577: * value will be destroyed iff the number of idle workers exceeds
0578: * AUTHORITY_MIN_IDLE.
0579: *
0580: * @since 2.4
0581: */
0582: public static final IntegerKey AUTHORITY_SOFTMIN_EVICT_IDLETIME = new IntegerKey(
0583: 10 * 000);
0584:
0585: /**
0586: * Time in milliseconds to wait between eviction runs.
0587: *
0588: * @since 2.4
0589: */
0590: public static final IntegerKey AUTHORITY_TIME_BETWEEN_EVICTION_RUNS = new IntegerKey(
0591: 5 * 000);
0592:
0593: /**
0594: * Version number of the requested service. This hint is used for example in order to get
0595: * a {@linkplain org.opengis.referencing.crs.CRSAuthorityFactory CRS authority factory}
0596: * backed by a particular version of EPSG database. The value should be an instance of
0597: * {@link org.geotools.util.Version}.
0598: *
0599: * @since 2.4
0600: */
0601: public static final Key VERSION = new Key(
0602: "org.geotools.util.Version");
0603:
0604: ////////////////////////////////////////////////////////////////////////
0605: //////// ////////
0606: //////// Grid Coverages ////////
0607: //////// ////////
0608: ////////////////////////////////////////////////////////////////////////
0609:
0610: /**
0611: * The {@link org.opengis.coverage.processing.GridCoverageProcessor} instance to use.
0612: *
0613: * @deprecated The {@code GridCoverageProcessor} interface is not yet
0614: * stable. Avoid dependencies if possible.
0615: */
0616: public static final Key GRID_COVERAGE_PROCESSOR = new Key(
0617: Object.class);
0618: // TODO new Key("org.opengis.coverage.processing.GridCoverageProcessor");
0619:
0620: /**
0621: * Tells to the {@link org.opengis.coverage.grid.GridCoverageReader} instances to ignore
0622: * the built-in overviews when creating a {@link org.opengis.coverage.grid.GridCoverage}
0623: * object during a read. This hints also implied that no decimation on reading is performed.
0624: *
0625: * @since 2.3
0626: */
0627: public static final Key IGNORE_COVERAGE_OVERVIEW = new Key(
0628: Boolean.class);
0629:
0630: /**
0631: * Tells to the {@link org.opengis.coverage.grid.GridCoverageReader} instances to read
0632: * the image using the JAI ImageRead operation (leveraging on Deferred Execution Model,
0633: * Tile Caching,...) or the direct {@code ImageReader}'s read methods.
0634: *
0635: * @since 2.4
0636: */
0637: public static final Key USE_JAI_IMAGEREAD = new Key(Boolean.class);
0638:
0639: /**
0640: * Forces the {@linkplain org.opengis.coverage.processing.GridCoverageProcessor grid coverage
0641: * processor} to perform operations on the non-geophysics view.
0642: * <p>
0643: * Some operation when called on a {@linkplain org.geotools.coverage.grid.GridCoverage grid
0644: * coverage} that is the non-geophysics view of another grid coverage try to go back to the
0645: * latter before executing even if they could execute fine without doing so. The rationale
0646: * behind this is that the non-geophysics view is just the rendered version of a coverage,
0647: * hence operations should be applied onto the geophysics companion.
0648: * <p>
0649: * However, in some cases like when doing pure rendering of photographic images, we might want
0650: * to force this operations to work on the non-geophysics view directly, even performing color
0651: * expansions as needed. This can be accomplished by setting this hint to {@code true}. Be
0652: * aware that interpolations in non-photographic images (i.e. a colormap like a <cite>Sea
0653: * Surface Temperature</cite> image) after color expansions may produce wrong colors.
0654: *
0655: * @since 2.4
0656: *
0657: * @todo We may need to find a more accurate name, especially when the enumeration in
0658: * {@link org.geotools.coverage.grid.ViewType} will be ready to work. Maybe
0659: * something like {@code PROCESS_ON_VISUAL_VIEW}.
0660: */
0661: public static final Key REPLACE_NON_GEOPHYSICS_VIEW = new Key(
0662: Boolean.class);
0663:
0664: /**
0665: * The {@linkplain javax.media.jai.tilecodec.TileEncoder tile encoder} name
0666: * (as a {@link String} value) to use during serialization of image data in
0667: * a {@link org.geotools.coverage.grid.GridCoverage2D} object. This encoding
0668: * is given to the {@link javax.media.jai.remote.SerializableRenderedImage}
0669: * constructor. Valid values include (but is not limited to) {@code "raw"},
0670: * {@code "gzip"} and {@code "jpeg"}.
0671: * <p>
0672: * <strong>Note:</strong> We recommand to avoid the {@code "jpeg"} codec
0673: * for grid coverages.
0674: *
0675: * @see org.geotools.coverage.FactoryFinder#getGridCoverageFactory
0676: *
0677: * @since 2.3
0678: */
0679: public static final Key TILE_ENCODING = new Key(String.class);
0680:
0681: /**
0682: * The {@link javax.media.jai.JAI} instance to use.
0683: */
0684: public static final Key JAI_INSTANCE = new Key(
0685: "javax.media.jai.JAI");
0686:
0687: /**
0688: * The {@link org.opengis.coverage.SampleDimensionType} to use.
0689: */
0690: public static final Key SAMPLE_DIMENSION_TYPE = new Key(
0691: "org.opengis.coverage.SampleDimensionType");
0692:
0693: /**
0694: * Constructs a new object with the specified key/value pair.
0695: *
0696: * @param key The key of the particular hint property.
0697: * @param value The value of the hint property specified with {@code key}.
0698: */
0699: public Hints(final RenderingHints.Key key, final Object value) {
0700: super (key, value);
0701: }
0702:
0703: /**
0704: * Constructs a new object with two key/value pair.
0705: *
0706: * @param key1 The key for the first pair
0707: * @param value1 The value for the first pair
0708: * @param key2 The key2 for the second pair
0709: * @param value2 The value2 for the second pair
0710: */
0711: public Hints(final RenderingHints.Key key1, final Object value1,
0712: final RenderingHints.Key key2, final Object value2) {
0713: this (fromPairs(new Object[] { key1, value1, key2, value2 }));
0714: }
0715:
0716: /**
0717: * Constructs a new object with key/value pairs from an array.
0718: *
0719: * @param pairs
0720: * An array containing pairs of RenderingHints keys and values
0721: */
0722: public Hints(final RenderingHints.Key key1, final Object value1,
0723: final Object[] pairs) {
0724: this (fromPairs(key1, value1, pairs));
0725: }
0726:
0727: /**
0728: * Constructs a new object from key/value pair.
0729: * <p>
0730: * This method is intended for use with Java5:
0731: * <code>new Hints( Hints.BUFFER_LIMIT,1,Hints.BUFFER_POLICY,"weak" )</code>
0732: *
0733: * @param pairs
0734: * Key value pairs
0735: */
0736: public Hints(final RenderingHints.Key key1, final Object value1,
0737: final RenderingHints.Key key2, final Object value2,
0738: Object[] pairs) {
0739: this (fromPairs(key1, value1, key2, value2, pairs));
0740: }
0741:
0742: /**
0743: * Utility method used to organize pairs into a Map.
0744: *
0745: * @param pairs
0746: * An array of Key/Value pairs
0747: * @return Map<Key,Value>
0748: * @throws ClassCastException
0749: * if Key/Value pairs do not match
0750: */
0751: private static Map fromPairs(RenderingHints.Key key1,
0752: Object value1, Object[] pairs) {
0753: Map map = fromPairs(pairs);
0754: map.put(key1, value1);
0755: return map;
0756: }
0757:
0758: /**
0759: * Utility method used to organize pairs into a Map.
0760: *
0761: * @param pairs
0762: * An array of Key/Value pairs
0763: * @return Map<Key,Value>
0764: * @throws ClassCastException
0765: * if Key/Value pairs do not match
0766: */
0767: private static Map fromPairs(RenderingHints.Key key1,
0768: Object value1, RenderingHints.Key key2, Object value2,
0769: Object[] pairs) {
0770: Map map = fromPairs(pairs);
0771: map.put(key1, value1);
0772: map.put(key2, value2);
0773: return map;
0774: }
0775:
0776: /**
0777: * Utility method used to organize pairs into a Map.
0778: *
0779: * @param pairs
0780: * An array of Key/Value pairs
0781: * @return Map<Key,Value>
0782: * @throws ClassCastException
0783: * if Key/Value pairs do not match
0784: */
0785: private static Map fromPairs(Object[] pairs) {
0786: Map map = new HashMap();
0787: for (int i = 0; i < pairs.length; i += 2) {
0788: Key key = (Key) pairs[i];
0789: Object value = pairs[i + 1];
0790: if (!key.isCompatibleValue(value)) {
0791: throw new ClassCastException(key + " requires "
0792: + key.getValueClass() + " - could cast "
0793: + value);
0794: }
0795: map.put(key, value);
0796: }
0797: return map;
0798: }
0799:
0800: /**
0801: * Constructs a new object with keys and values initialized from the
0802: * specified map (which may be null).
0803: *
0804: * @param hints A map of key/value pairs to initialize the hints, or
0805: * {@code null} if the object should be empty.
0806: */
0807: public Hints(final Map hints) {
0808: super (stripNonKeys(hints));
0809: }
0810:
0811: /**
0812: * Returns a map with the same hints than the specified one, minus every (key,value)
0813: * pairs where the key is not an instance of {@link RenderingHints.Key}. If the given
0814: * map contains only valid keys, then it is returned unchanged.
0815: */
0816: static Map stripNonKeys(final Map hints) {
0817: if (hints == null) {
0818: return null;
0819: }
0820: Map filtered = hints;
0821: for (final Iterator it = hints.keySet().iterator(); it
0822: .hasNext();) {
0823: final Object key = it.next();
0824: if (!(key instanceof RenderingHints.Key)) {
0825: if (filtered == hints) {
0826: // Copy the map only if needed.
0827: filtered = new HashMap(hints);
0828: }
0829: filtered.remove(key);
0830: }
0831: }
0832: return filtered;
0833: }
0834:
0835: /**
0836: * Notifies that {@linkplain System#getProperties system properties} will need to be scanned
0837: * for any property keys defined in the {@link GeoTools} class. New values found (if any) will
0838: * be added to the set of {@linkplain GeoTools#getDefaultHints default hints}. For example if
0839: * the {@value GeoTools#FORCE_LONGITUDE_FIRST_AXIS_ORDER} system property is defined, then the
0840: * {@link #FORCE_LONGITUDE_FIRST_AXIS_ORDER} hint will be added to the set of default hints.
0841: * <p>
0842: * This method is invoked automatically the first time it is needed. It usually don't
0843: * need to be invoked explicitly, except if the {@linkplain System#getProperties system
0844: * properties} changed. The scan may not be performed immediately, but rather when needed
0845: * at some later stage.
0846: *
0847: * @since 2.4
0848: */
0849: public static void scanSystemProperties() {
0850: synchronized (GLOBAL) {
0851: needScan = true;
0852: }
0853: }
0854:
0855: /**
0856: * Invokes {@link GeoTools#scanSystemProperties} when first needed. The caller is
0857: * responsible for invoking {@link GeoTools#fireConfigurationChanged} outside the
0858: * synchronized block if this method returns {@code true}.
0859: *
0860: * @return {@code true} if at least one hint changed as a result of this scan,
0861: * or {@code false} otherwise.
0862: */
0863: private static boolean ensureSystemDefaultLoaded() {
0864: assert Thread.holdsLock(GLOBAL);
0865: if (needScan) {
0866: needScan = false;
0867: return GeoTools.scanForSystemHints(GLOBAL);
0868: } else {
0869: return false;
0870: }
0871: }
0872:
0873: /**
0874: * Returns a copy of the system hints. This is for
0875: * {@link GeoTools#getDefaultHints} implementation only.
0876: */
0877: static Hints getDefaults(final boolean strict) {
0878: final boolean changed;
0879: final Hints hints;
0880: synchronized (GLOBAL) {
0881: changed = ensureSystemDefaultLoaded();
0882: if (strict) {
0883: hints = new StrictHints(GLOBAL);
0884: } else {
0885: hints = new Hints(GLOBAL);
0886: }
0887: }
0888: if (changed) {
0889: GeoTools.fireConfigurationChanged();
0890: }
0891: return hints;
0892: }
0893:
0894: /**
0895: * Adds all specified hints to the system hints. This
0896: * is for {@link GeoTools#init} implementation only.
0897: */
0898: static void putSystemDefault(final RenderingHints hints) {
0899: synchronized (GLOBAL) {
0900: ensureSystemDefaultLoaded();
0901: GLOBAL.add(hints);
0902: }
0903: GeoTools.fireConfigurationChanged();
0904: }
0905:
0906: /**
0907: * Returns the hint {@linkplain GeoTools#getDefaultHints default value}
0908: * for the specified key.
0909: *
0910: * @param key The hints key.
0911: * @return The value for the specified key, or {@code null}
0912: * if the key did not have a mapping.
0913: *
0914: * @since 2.4
0915: */
0916: public static Object getSystemDefault(final RenderingHints.Key key) {
0917: final boolean changed;
0918: final Object value;
0919: synchronized (GLOBAL) {
0920: changed = ensureSystemDefaultLoaded();
0921: value = GLOBAL.get(key);
0922: }
0923: if (changed) {
0924: GeoTools.fireConfigurationChanged();
0925: }
0926: return value;
0927: }
0928:
0929: /**
0930: * Adds a hint value to the set of {@linkplain GeoTools#getDefaultHints default hints}.
0931: * Default hints can be added by call to this {@code putDefaultHint} method, to the
0932: * {@link GeoTools#init} method or by {@linkplain System#getProperties system properties}
0933: * with keys defined by the {@link String} constants in the {@link GeoTools} class.
0934: *
0935: * @param key The hint key.
0936: * @param value The hint value.
0937: * @return The previous value of the specified key, or {@code null} if none.
0938: * @throws IllegalArgumentException If {@link Hints.Key#isCompatibleValue()}
0939: * returns {@code false} for the specified value.
0940: *
0941: * @since 2.4
0942: */
0943: public static Object putSystemDefault(final RenderingHints.Key key,
0944: final Object value) {
0945: final boolean changed;
0946: final Object old;
0947: synchronized (GLOBAL) {
0948: changed = ensureSystemDefaultLoaded();
0949: old = GLOBAL.put(key, value);
0950: }
0951: if (changed || !Utilities.equals(value, old)) {
0952: GeoTools.fireConfigurationChanged();
0953: }
0954: return old;
0955: }
0956:
0957: /**
0958: * Removes the specified hints from the set of
0959: * {@linkplain GeoTools#getDefaultHints default hints}.
0960: *
0961: * @param key The hints key that needs to be removed.
0962: * @return The value to which the key had previously been mapped,
0963: * or {@code null} if the key did not have a mapping.
0964: *
0965: * @since 2.4
0966: */
0967: public static Object removeSystemDefault(
0968: final RenderingHints.Key key) {
0969: final boolean changed;
0970: final Object old;
0971: synchronized (GLOBAL) {
0972: changed = ensureSystemDefaultLoaded();
0973: old = GLOBAL.remove(key);
0974: }
0975: if (changed || old != null) {
0976: GeoTools.fireConfigurationChanged();
0977: }
0978: return old;
0979: }
0980:
0981: /**
0982: * Returns a string representation of the hints. This method formats the set of hints
0983: * as a tree. If some system-wide {@linkplain GeoTools#getDefaultHints default hints}
0984: * exist, they are formatted after those hints for completeness.
0985: *
0986: * @since 2.4
0987: */
0988: public String toString() {
0989: final String lineSeparator = System.getProperty(
0990: "line.separator", "\n");
0991: final StringBuffer buffer = new StringBuffer("Hints:"); // TODO: localize
0992: buffer.append(lineSeparator).append(
0993: AbstractFactory.toString(this ));
0994: Map extra = null;
0995: final boolean changed;
0996: synchronized (GLOBAL) {
0997: changed = ensureSystemDefaultLoaded();
0998: if (!GLOBAL.isEmpty()) {
0999: extra = new HashMap(GLOBAL);
1000: }
1001: }
1002: if (changed) {
1003: GeoTools.fireConfigurationChanged();
1004: }
1005: if (extra != null) {
1006: extra.keySet().removeAll(keySet());
1007: if (!extra.isEmpty()) {
1008: buffer.append("System defaults:") // TODO: localize
1009: .append(lineSeparator).append(
1010: AbstractFactory.toString(extra));
1011: }
1012: }
1013: return buffer.toString();
1014: }
1015:
1016: /**
1017: * The type for keys used to control various aspects of the factory
1018: * creation. Factory creation impacts rendering (which is why extending
1019: * {@linkplain java.awt.RenderingHints.Key rendering key} is not a complete
1020: * non-sense), but may impact other aspects of an application as well.
1021: *
1022: * @since 2.1
1023: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
1024: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
1025: * @author Martin Desruisseaux
1026: */
1027: public static class Key/*<T>*/extends RenderingHints.Key {
1028: /**
1029: * The number of key created up to date.
1030: */
1031: private static int count;
1032:
1033: /**
1034: * The class name for {@link #valueClass}.
1035: */
1036: private final String className;
1037:
1038: /**
1039: * Base class of all values for this key. Will be created from {@link #className} only when
1040: * first required, in order to avoid too early class loading. This is significant for the
1041: * {@link #JAI_INSTANCE} key for example, in order to avoid JAI dependencies in applications
1042: * that do not need it.
1043: */
1044: private transient Class/*<T>*/valueClass;
1045:
1046: /**
1047: * Constructs a new key for values of the given class.
1048: *
1049: * @param classe
1050: * The base class for all valid values.
1051: */
1052: public Key(final Class/*<T>*/classe) {
1053: this (classe.getName());
1054: valueClass = classe;
1055: }
1056:
1057: /**
1058: * Constructs a new key for values of the given class. The class is
1059: * specified by name instead of a {@link Class} object. This allows to
1060: * defer class loading until needed.
1061: *
1062: * @param className
1063: * Name of base class for all valid values.
1064: */
1065: Key(final String className) {
1066: super (count());
1067: this .className = className;
1068: }
1069:
1070: /**
1071: * Workaround for RFE #4093999 ("Relax constraint on placement of this()/super()
1072: * call in constructors"): {@code count++} need to be executed in a synchronized
1073: * block since it is not an atomic operation.
1074: */
1075: private static synchronized int count() {
1076: return count++;
1077: }
1078:
1079: /**
1080: * Returns the expected class for values stored under this key.
1081: */
1082: public Class/*<T>*/getValueClass() {
1083: if (valueClass == null) {
1084: try {
1085: valueClass = Class.forName(className);
1086: } catch (ClassNotFoundException exception) {
1087: Logging.unexpectedException("org.geotools.factory",
1088: Key.class, "getValueClass", exception);
1089: valueClass = Object.class;
1090: }
1091: }
1092: return valueClass;
1093: }
1094:
1095: /**
1096: * Returns {@code true} if the specified object is a valid value for
1097: * this key. The default implementation checks if the specified value
1098: * {@linkplain Class#isInstance is an instance} of the {@linkplain
1099: * #getValueClass value class}.
1100: * <p>
1101: * Note that many hint keys defined in the {@link Hints} class relax this rule and accept
1102: * {@link Class} object assignable to the expected {@linkplain #getValueClass value class}
1103: * as well.
1104: *
1105: * @param value
1106: * The object to test for validity.
1107: * @return {@code true} if the value is valid; {@code false} otherwise.
1108: *
1109: * @see Hints.ClassKey#isCompatibleValue
1110: * @see Hints.FileKey#isCompatibleValue
1111: * @see Hints.IntegerKey#isCompatibleValue
1112: * @see Hints.OptionKey#isCompatibleValue
1113: */
1114: public boolean isCompatibleValue(final Object value) {
1115: return getValueClass().isInstance(value);
1116: }
1117:
1118: /**
1119: * Returns a string representation of this key. The string
1120: * representation is mostly for debugging purpose. The default
1121: * implementation tries to infer the key name using reflection.
1122: */
1123: public String toString() {
1124: int t = 0;
1125: while (true) {
1126: final Class type;
1127: switch (t++) {
1128: case 0:
1129: type = Hints.class;
1130: break;
1131: case 1:
1132: type = getValueClass();
1133: break;
1134: default:
1135: return super .toString();
1136: }
1137: final Field[] fields = type.getFields();
1138: for (int i = 0; i < fields.length; i++) {
1139: final Field f = fields[i];
1140: if (Modifier.isStatic(f.getModifiers())) {
1141: final Object v;
1142: try {
1143: v = f.get(null);
1144: } catch (IllegalAccessException e) {
1145: continue;
1146: }
1147: if (v == this ) {
1148: return f.getName();
1149: }
1150: }
1151: }
1152: }
1153: }
1154: }
1155:
1156: /**
1157: * A key for value that may be specified either as instance of {@code T}, or as
1158: * {@code Class<T>}.
1159: *
1160: * @since 2.4
1161: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
1162: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
1163: * @author Martin Desruisseaux
1164: */
1165: public static final class ClassKey/*<T>*/extends Key/*<T>*/{
1166: /**
1167: * Constructs a new key for values of the given class.
1168: *
1169: * @param classe
1170: * The base class for all valid values.
1171: */
1172: public ClassKey(final Class/*<T>*/classe) {
1173: super (classe);
1174: }
1175:
1176: /**
1177: * Constructs a new key for values of the given class. The class is
1178: * specified by name instead of a {@link Class} object. This allows to
1179: * defer class loading until needed.
1180: *
1181: * @param className
1182: * Name of base class for all valid values.
1183: */
1184: ClassKey(final String className) {
1185: super (className);
1186: }
1187:
1188: /**
1189: * Returns {@code true} if the specified object is a valid value for
1190: * this key. This method checks if the specified value is non-null and
1191: * is one of the following:
1192: * <p>
1193: * <ul>
1194: * <li>An instance of the {@linkplain #getValueClass expected value class}.</li>
1195: * <li>A {@link Class} assignable to the expected value class.</li>
1196: * <li>An array of {@code Class} objects assignable to the expected value class.</li>
1197: * </ul>
1198: */
1199: //@Override
1200: public boolean isCompatibleValue(final Object value) {
1201: if (value == null) {
1202: return false;
1203: }
1204: if (value instanceof Class[]) {
1205: final Class[] types = (Class[]) value;
1206: for (int i = 0; i < types.length; i++) {
1207: if (!isCompatibleValue(types[i])) {
1208: return false;
1209: }
1210: }
1211: return types.length != 0;
1212: }
1213: final Class type;
1214: if (value instanceof Class) {
1215: type = (Class) value;
1216: } else {
1217: type = value.getClass();
1218: }
1219: return getValueClass().isAssignableFrom(type);
1220: }
1221: }
1222:
1223: /**
1224: * Key for hints to be specified as a {@link File}.
1225: * The file may also be specified as a {@link String} object.
1226: *
1227: * @since 2.4
1228: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
1229: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
1230: * @author Jody Garnett
1231: * @author Martin Desruisseaux
1232: */
1233: public static final class FileKey extends Key {
1234: /**
1235: * {@code true} if write operations need to be allowed.
1236: */
1237: private final boolean writable;
1238:
1239: /**
1240: * Creates a new key for {@link File} value.
1241: *
1242: * @param writable
1243: * {@code true} if write operations need to be allowed.
1244: */
1245: public FileKey(final boolean writable) {
1246: super (File.class);
1247: this .writable = writable;
1248: }
1249:
1250: /**
1251: * Returns {@code true} if the specified object is a valid file or directory.
1252: */
1253: //@Override
1254: public boolean isCompatibleValue(final Object value) {
1255: final File file;
1256: if (value instanceof File) {
1257: file = (File) value;
1258: } else if (value instanceof String) {
1259: file = new File((String) value);
1260: } else {
1261: return false;
1262: }
1263: if (file.exists()) {
1264: return !writable || file.canWrite();
1265: }
1266: final File parent = file.getParentFile();
1267: return parent != null && parent.canWrite();
1268: }
1269: }
1270:
1271: /**
1272: * A hint used to capture a configuration setting as an integer.
1273: * A default value is provided and may be checked with {@link #getDefault()}.
1274: *
1275: * @since 2.4
1276: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
1277: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
1278: * @author Jody Garnett
1279: */
1280: public static final class IntegerKey extends Key {
1281: /**
1282: * The default value.
1283: */
1284: private final int number;
1285:
1286: /**
1287: * Creates a new key with the specified default value.
1288: */
1289: public IntegerKey(final int number) {
1290: super (Integer.class);
1291: this .number = number;
1292: }
1293:
1294: /**
1295: * Returns the default value.
1296: */
1297: public int getDefault() {
1298: return number;
1299: }
1300:
1301: /**
1302: * Returns the value from the specified hints as an integer. If no value were found
1303: * for this key, then this method returns the {@linkplain #getDefault default value}.
1304: *
1305: * @param hints The map where to fetch the hint value, or {@code null}.
1306: * @return The hint value as an integer, or the default value if not hint
1307: * was explicitly set.
1308: */
1309: public int toValue(final Hints hints) {
1310: if (hints != null) {
1311: final Object value = hints.get(this );
1312: if (value instanceof Number) {
1313: return ((Number) value).intValue();
1314: } else if (value instanceof CharSequence) {
1315: return Integer.parseInt(value.toString());
1316: }
1317: }
1318: return number;
1319: }
1320:
1321: /**
1322: * Returns {@code true} if the specified object is a valid integer.
1323: */
1324: //@Override
1325: public boolean isCompatibleValue(final Object value) {
1326: if (value instanceof Short || value instanceof Integer) {
1327: return true;
1328: }
1329: if (value instanceof String
1330: || value instanceof InternationalString) {
1331: try {
1332: Integer.parseInt(value.toString());
1333: } catch (NumberFormatException e) {
1334: Logging.getLogger("org.geotools.factory").finer(
1335: e.toString());
1336: }
1337: }
1338: return false;
1339: }
1340: }
1341:
1342: /**
1343: * Key that allows the choice of several options.
1344: * You can use {@code "*"} as a wild card to indicate that undocumented options
1345: * may be supported (but there is no assurances - {@link Hints#DATUM_SHIFT_METHOD}).
1346: *
1347: * @since 2.4
1348: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
1349: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
1350: * @author Jody Garnett
1351: */
1352: public static final class OptionKey extends Key {
1353: /**
1354: * The set of options allowed.
1355: */
1356: private final Set options;
1357:
1358: /**
1359: * {@code true} if the {@code "*"} wildcard was given in the set of options.
1360: */
1361: private final boolean wildcard;
1362:
1363: /**
1364: * Creates a new key for a configuration option.
1365: *
1366: * @todo Replace by variable arguments length when we will be allowed to compile for J2SE 1.5.
1367: */
1368: public OptionKey(String option1, String option2) {
1369: this (new String[] { option1, option2 });
1370: }
1371:
1372: /**
1373: * Creates a new key for a configuration option.
1374: *
1375: * @todo Replace by variable arguments length when we will be allowed to compile for J2SE 1.5.
1376: */
1377: public OptionKey(String option1, String option2, String option3) {
1378: this (new String[] { option1, option2, option3 });
1379: }
1380:
1381: /**
1382: * Creates a new key for a configuration option.
1383: *
1384: * @todo Replace by variable arguments length when we will be allowed to compile for J2SE 1.5.
1385: */
1386: public OptionKey(String option1, String option2,
1387: String option3, String option4) {
1388: this (new String[] { option1, option2, option3, option4 });
1389: }
1390:
1391: /**
1392: * Creates a new key for a configuration option.
1393: *
1394: * @todo Replace by variable arguments length when we will be allowed to compile for J2SE 1.5.
1395: */
1396: public OptionKey(String option1, String option2,
1397: String option3, String option4, String option5) {
1398: this (new String[] { option1, option2, option3, option4,
1399: option5 });
1400: }
1401:
1402: /**
1403: * Creates a new key for a configuration option.
1404: *
1405: * @todo Replace by variable arguments length when we will be allowed to compile for J2SE 1.5.
1406: */
1407: public OptionKey(final String[] alternatives) {
1408: super (String.class);
1409: final Set options = new TreeSet(Arrays.asList(alternatives));
1410: this .wildcard = options.remove("*");
1411: this .options = Collections.unmodifiableSet(options);
1412: }
1413:
1414: /**
1415: * Returns the set of available options.
1416: */
1417: public Set getOptions() {
1418: return options;
1419: }
1420:
1421: /**
1422: * Returns {@code true} if the specified object is one of the valid options. If the
1423: * options specified at construction time contains the {@code "*"} wildcard, then
1424: * this method returns {@code true} for every {@link String} object.
1425: */
1426: //@Override
1427: public boolean isCompatibleValue(final Object value) {
1428: return wildcard ? (value instanceof String) : options
1429: .contains(value);
1430: }
1431: }
1432:
1433: /**
1434: * Key for hints to be specified as a {@link javax.sql.DataSource}.
1435: * The file may also be specified as a {@link String} object.
1436: *
1437: * @since 2.4
1438: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/factory/Hints.java $
1439: * @version $Id: Hints.java 29443 2008-02-25 10:04:01Z jgarnett $
1440: * @author Martin Desruisseaux
1441: */
1442: static final class DataSourceKey extends Key {
1443: /**
1444: * Creates a new key for {@link javax.sql.DataSource} value.
1445: */
1446: public DataSourceKey() {
1447: super (DataSource.class);
1448: }
1449:
1450: /**
1451: * Returns {@code true} if the specified object is a data source or data source name.
1452: */
1453: //@Override
1454: public boolean isCompatibleValue(final Object value) {
1455: return (value instanceof DataSource)
1456: || (value instanceof String);
1457: }
1458: }
1459: }
|