/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2007-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.factory; import java.awt.RenderingHints; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import org.geotools.resources.Arguments; import org.geotools.resources.Classes; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; import org.geotools.util.Utilities; import org.geotools.util.Version; import org.geotools.util.logging.LoggerFactory; import org.geotools.util.logging.Logging; /** * Static methods relative to the global GeoTools configuration. GeoTools can be configured * in a system-wide basis through {@linkplain System#getProperties system properties}, some * of them are declared as {@link String} constants in this class. *
* There are many aspects to the configuration of GeoTools: *
* * Note that this system property applies mostly to the default EPSG factory. Most other * factories ({@code "CRS"}, {@code "AUTO"}, etc.) don't need this property * since they use (longitude, latitude) axis order by design. * * @see Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER * @see #getDefaultHints */ public static final String FORCE_LONGITUDE_FIRST_AXIS_ORDER = "org.geotools.referencing.forceXY"; static { bind(FORCE_LONGITUDE_FIRST_AXIS_ORDER, Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER); } /** * The {@linkplain System#getProperty(String) system property} key for the default * value to be assigned to the {@link Hints# * RESAMPLE_TOLERANCE} hint. * * This setting specifies the tolerance used when linearizing warp transformation into * piecewise linear ones, by default it is 0.333 pixels * * @see Hints#RESAMPLE_TOLERANCE * @see #getDefaultHints */ public static final String RESAMPLE_TOLERANCE = "org.geotools.referencing.resampleTolerance"; static { bind(RESAMPLE_TOLERANCE, Hints.RESAMPLE_TOLERANCE); } /** * The initial context. Will be created only when first needed. */ private static InitialContext context; /** * Class loaders to be added to the list in ${link {@link FactoryRegistry#getClassLoaders()}} * which are used to look-up plug-ins. Class loaders are added via * {@link #addClassLoader(ClassLoader)} */ private static final Set* System.setProperty(FORCE_LONGITUDE_FIRST_AXIS_ORDER, "true"); *
*
* In addition, the {@linkplain #getDefaultHints default hints} are initialized to the * specified {@code hints}. *
* Note that invoking this method is usually not needed for proper working * of the Geotools library. It is just a convenience method for overwriting some Java and * Geotools default settings in a way that seems to be common in server environment. Such * overwriting may not be wanted for every situations. *
* Example of typical invocation in a Geoserver environment: * *
* * @param hints The hints to use. * * @see Logging#setLoggerFactory(String) * @see Logging#forceMonolineConsoleOutput * @see Hints#putSystemDefault * @see #getDefaultHints */ public static void init(final Hints hints) { final Logging log = Logging.GEOTOOLS; try { log.setLoggerFactory("org.geotools.util.logging.CommonsLoggerFactory"); } catch (ClassNotFoundException commonsException) { try { log.setLoggerFactory("org.geotools.util.logging.Log4JLoggerFactory"); } catch (ClassNotFoundException log4jException) { // Nothing to do, we already tried our best. } } // If java logging is used, force monoline console output. if (log.getLoggerFactory() == null) { log.forceMonolineConsoleOutput(); } if (hints != null) { Hints.putSystemDefault(hints); // fireConfigurationChanged() is invoked in the above method call. } } /** * Forces the initial context for test cases, or as needed. * * @param applicationContext The initial context to use. * * @see #getInitialContext * * @since 2.4 */ public static void init(final InitialContext applicationContext) { synchronized (GeoTools.class) { context = applicationContext; } fireConfigurationChanged(); } /** * Scans {@linkplain System#getProperties system properties} for any property keys * defined in this class, and add their values to the specified map of hints. For * example if the {@value #FORCE_LONGITUDE_FIRST_AXIS_ORDER} system property is * defined, then the {@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER * FORCE_LONGITUDE_FIRST_AXIS_ORDER} hint will be added to the set of hints. * * @return {@code true} if at least one hint changed as a result of this scan, * or {@code false} otherwise. */ static boolean scanForSystemHints(final Hints hints) { assert Thread.holdsLock(hints); boolean changed = false; synchronized (BINDINGS) { for (final Map.Entry* Hints hints = new Hints(); * hints.put({@linkplain Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER}, Boolean.TRUE); * hints.put({@linkplain Hints#FORCE_AXIS_ORDER_HONORING}, "http"); * GeoTools.init(hints); *
*
* Long term plan:
* We would like to transition the utility classes to being injected with their
* required factories, either by taking Hints as part of their constructor, or
* otherwise. Making this change would be a three step process 1) create instance
* methods for each static final class method 2) create an singleton instance of the
* class 3) change each static final class method into a call to the singleton. With
* this in place we could then encourage client code to make use of utility class
* instances before eventually retiring the static final methods.
*
* @return A copy of the default hints. It is safe to add to it.
*/
public static Hints getDefaultHints() {
return Hints.getDefaults(false);
}
/**
* Used to combine provided hints with global GeoTools defaults.
*
* @param hints
* @return
*/
public static Hints addDefaultHints(final Hints hints) {
final Hints completed = getDefaultHints();
if (hints != null) {
completed.add(hints);
}
return completed;
}
/**
* Returns the default initial context.
*
* @param hints An optional set of hints, or {@code null} if none.
* @return The initial context (never {@code null}).
* @throws NamingException if the initial context can't be created.
*
* @see #init(InitialContext)
*
* @since 2.4
*/
public static synchronized InitialContext getInitialContext(final Hints hints)
throws NamingException
{
if (context == null) {
context = new InitialContext();
}
return context;
}
/**
* Converts a GeoTools name to the syntax used by the {@linkplain #getInitialContext
* GeoTools JNDI context}. Names may be constructed in a variety of ways depending on
* the implementation of {@link InitialContext}. GeoTools uses {@code "jdbc:EPSG"}
* internally, but many implementaitons use the form {@code "jdbc/EPSG"}. Calling
* this method before use will set the name right.
*
* @param name Name of the form {@code "jdbc:EPSG"}, or {@code null}.
* @return Name fixed up with {@link Context#composeName(String,String)},
* or {@code null} if the given name was null.
*
* @since 2.4
*/
public static String fixName(final String name) {
return fixName(null, name, null);
}
/**
* Converts a GeoTools name to the syntax used by the specified JNDI context.
* This method is similar to {@link #fixName(String)}, but uses the specified
* context instead of the GeoTools one.
*
* @param context The context to use, or {@code null} if none.
* @param name Name of the form {@code "jdbc:EPSG"}, or {@code null}.
* @return Name fixed up with {@link Context#composeName(String,String)},
* or {@code null} if the given name was null.
*
* @since 2.4
*/
public static String fixName(final Context context, final String name) {
return (context != null) ? fixName(context, name, null) : name;
}
/**
* Implementation of {@code fixName} method. If the context is {@code null}, then
* the {@linkplain #getInitialContext GeoTools initial context} will be fetch only
* when first needed.
*/
private static String fixName(Context context, final String name, final Hints hints) {
String fixed = null;
if (name != null) {
final StringTokenizer tokens = new StringTokenizer(name, ":/");
while (tokens.hasMoreTokens()) {
final String part = tokens.nextToken();
if (fixed == null) {
fixed = part;
} else try {
if (context == null) {
context = getInitialContext(hints);
}
fixed = context.composeName(fixed, part);
} catch (NamingException e) {
Logging.unexpectedException(GeoTools.class, "fixName", e);
return name;
}
}
}
return fixed;
}
/**
* Adds an alternative way to search for factory implementations. {@link FactoryRegistry} has
* a default mechanism bundled in it, which uses the content of all {@code META-INF/services}
* directories found on the classpath. This {@code addFactoryIteratorProvider} method allows
* to specify additional discovery algorithms. It may be useful in the context of some
* frameworks that use the constructor injection pattern, like the
* Spring framework.
*
* @param provider A new provider for factory iterators.
*/
public static void addFactoryIteratorProvider(final FactoryIteratorProvider provider) {
FactoryIteratorProviders.addFactoryIteratorProvider(provider);
}
/**
* Removes a provider that was previously {@linkplain #addFactoryIteratorProvider added}.
* Note that factories already obtained from the specified provider will not be
* {@linkplain FactoryRegistry#deregisterServiceProvider deregistered} by this method.
*
* @param provider The provider to remove.
*/
public static void removeFactoryIteratorProvider(final FactoryIteratorProvider provider) {
FactoryIteratorProviders.removeFactoryIteratorProvider(provider);
}
/**
* Adds the specified listener to the list of objects to inform when system-wide
* configuration changed.
*
* @param listener The listener to add.
*/
public static void addChangeListener(final ChangeListener listener) {
removeChangeListener(listener); // Ensure singleton.
LISTENERS.add(ChangeListener.class, listener);
}
/**
* Removes the specified listener from the list of objects to inform when system-wide
* configuration changed.
*
* @param listener The listener to remove.
*/
public static void removeChangeListener(final ChangeListener listener) {
LISTENERS.remove(ChangeListener.class, listener);
}
/**
* Informs every listeners that system-wide configuration changed.
*/
public static void fireConfigurationChanged() {
final ChangeEvent event = new ChangeEvent(GeoTools.class);
final Object[] listeners = LISTENERS.getListenerList();
for (int i=0; i