/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2010-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2010-2012, Geomatys * * 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.geotoolkit.lang; import java.util.Locale; import java.util.Properties; import java.util.ServiceLoader; import javax.imageio.spi.IIORegistry; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; import org.apache.sis.util.logging.Logging; import org.apache.sis.util.logging.MonolineFormatter; import org.geotoolkit.factory.FactoryFinder; import org.geotoolkit.factory.ShutdownHook; import org.geotoolkit.internal.io.JNDI; import org.geotoolkit.internal.SetupService; import org.geotoolkit.internal.io.Installation; import org.geotoolkit.resources.Errors; /** * A central place where to perform initialization and shutdown of all Geotk services. * Users are not required to perform explicit initialization and shutdown for most services * (except a few cases like <cite>World File Image Readers</cite>), since services are automatically * discovered when needed (using {@link ServiceLoader}) and disposed on JVM termination (using * {@linkplain Runtime#addShutdownHook shutdown hook}). However the above-cited mechanism is not * sufficient when an application is undeployed and re-deployed in a JEE environment without * restarting the JVM. For example the {@linkplain org.geotoolkit.image.io.plugin Geotk Image I/O * plugins} needs to be {@linkplain IIORegistry#deregisterServiceProvider(Object) deregistered} * during the <cite>undeploy</cite> phase before they get * {@linkplain IIORegistry#registerServiceProvider(Object) registered} again during the * <cite>re-deploy</cite> phase. Explicit invocations of {@link #initialize(Properties)} and * {@link #shutdown()} methods can improve the system stability in such cases. * <p> * The amount of works performed by this class depends on the modules available in the classpath. * The table below lists the work performed by current implementation. Users wanting more control * can perform those tasks themselves instead than relying on the methods defined in this * {@code Setup} class. * <p> * <table border="3" cellpadding="6"> * <tr bgcolor="lightblue"> * <th nowrap>Module</th> * <th nowrap>Methods invoked by {@link #initialize(Properties)}</th> * <th nowrap>Work done by {@link #shutdown()}</th> * </tr><tr> * <td nowrap>{@code geotk-utility}</td> * <td><ul> * <li>If {@code platform != "server"}: * <ul><li><code>{@linkplain Logging#forceMonolineConsoleOutput Logging.forceMonolineConsoleOutput}(null)</code></li></ul> * </li> * </ul></td> * <td> </td> * </tr><tr> * <td nowrap>{@code geotk-coverage}</td> * <td><ul> * <li>{@link org.geotoolkit.image.jai.Registry#setDefaultCodecPreferences()}</li> * </ul></td> * <td> * Remove from the JAI {@link javax.media.jai.OperationRegistry} every * plugins defined in any {@code org.geotoolkit} package. * </td> * </tr><tr> * <td nowrap>{@code geotk-coverageio}</td> * <td><ul> * <li><code>{@linkplain org.geotoolkit.image.io.plugin.WorldFileImageReader.Spi#registerDefaults WorldFileImageReader.Spi.registerDefaults}(null)</code></li> * <li><code>{@linkplain org.geotoolkit.image.io.plugin.WorldFileImageWriter.Spi#registerDefaults WorldFileImageWriter.Spi.registerDefaults}(null)</code></li> * </ul></td> * <td> * Remove from {@link IIORegistry} every plugins defined in any {@code org.geotoolkit} package. * </td> * </tr><tr> * <td nowrap>{@code geotk-coverageio-netcdf}</td> * <td><ul> * <li>If {@code netcdfCacheLimit != 0}: * <ul><li>{@link ucar.nc2.dataset.NetcdfDataset#initNetcdfFileCache(int,int,int)}</li></ul> * </li> * </ul></td> * <td> * {@link ucar.nc2.dataset.NetcdfDataset#shutdown()}. * </td> * </tr> * </table> * * {@section Note on system preferences} * In current implementation, invoking {@link #initialize(Properties)} * with a property entry {@code platform=server} also disable the usage of * {@linkplain java.util.prefs.Preferences#systemRoot() system preferences}. This is a temporary * workaround for the JDK 6 behavior on Unix system, which display "<cite>WARNING: Couldn't flush * system prefs</cite>" if the {@code etc/.java} directory has not been created during the Java * installation process. * <p> * This workaround may be removed in a future version if JDK 7 uses its new {@code java.nio.file} * package for performing a better work with system preferences. * * @author Martin Desruisseaux (Geomatys) * @version 3.11 * * @since 3.10 * @module */ public final class Setup extends Static { /** * The setup state. * <ul> * <li>0: initial state.</li> * <li>1: {@link #initialize(Properties)} has been invoked.</li> * <li>2: {@link #shutdown()} has been invoked.</li> * </ul> */ private static int state; /** * Do not allow instantiation of this class. */ private Setup() { } /** * Returns the value for the given key in the given properties map, or the default value * if none. The given properties map is allowed to be {@code null}. */ private static String get(final Properties properties, final String key, final String def) { return (properties != null) ? properties.getProperty(key, def) : def; } /** * Performs the initialization of all Geotk services. This method is typically invoked only * once. If it is invoked more than once and {@link #shutdown()} has not been invoked, then * every calls after the first method call are ignored. * <p> * The {@code properties} map allows some control on the initialization process. Current * implementation recognizes the entries listed in the table below. Any entry not listed * in this table are silently ignored. * <p> * <table border="1" cellspacing="0"> * <tr bgcolor="lightblue"> * <th nowrap> Key </th> * <th nowrap> Valid values </th> * <th nowrap> Default </th> * <th nowrap> Meaning </th> * </tr> * <tr> * <td nowrap> {@code platform} </td> * <td nowrap> {@code server}|{@code desktop} </td> * <td nowrap> {@code desktop} </td> * <td nowrap> Whatever the library is run for a desktop application or a server. </td> * </tr> * <tr> * <td nowrap> {@code netcdfCacheLimit} </td> * <td nowrap> Positive integer </td> * <td nowrap> 0 </td> * <td nowrap> Maximum number of elements in the NetCDF cache (0 for no cache). </td> * </tr> * <tr> * <td nowrap> {@code force} </td> * <td nowrap> {@code true}|{@code false} </td> * <td nowrap> {@code false} </td> * <td nowrap> If {@code true}, attempt a re-initialization after a shutdown. </td> * </tr> * </table> * * @param properties Optional set of properties controlling the initialization process, * or {@code null}. * @throws IllegalStateException If the Geotk library has been {@linkplain #shutdown() shutdown} * and the given properties map doesn't contain a {@code force=true} entry. */ @Configuration public static synchronized void initialize(final Properties properties) throws IllegalStateException { if (state == 1) { return; } final boolean reinit = (state == 2); if (reinit && !Boolean.parseBoolean(get(properties, "force", "false"))) { throw new IllegalStateException(); } state = 1; if ("server".equalsIgnoreCase(get(properties, "platform", "desktop"))) { Installation.allowSystemPreferences = false; } else { MonolineFormatter.install(); } JNDI.install(); /* * Following are normally not needed, since the factory registry scans automatically * the classpath when first needed. However some factories may have been unregistered * during the shutdown process, so we need to scan the classpath to re-register them. */ if (reinit) { FactoryFinder.scanForPlugins(); } /* * Now performs every module-specific initialization. */ for (final SetupService service : ServiceLoader.load(SetupService.class)) { service.initialize(properties, reinit); } } /** * Shutdowns all Geotk services. This method can be safely invoked even if the * {@link #initialize(Properties)} method has never been invoked. * <p> * The Geotk library should not be used anymore after this method call. */ @Configuration public static synchronized void shutdown() { if (state != 2) { state = 2; JNDI.uninstall(); for (final SetupService service : ServiceLoader.load(SetupService.class)) { service.shutdown(); } ShutdownHook.runAndremove(); } } /** * Shows the <cite>Swing</cite> Graphical User Interface for configuring the Geotk library. * This method requires the {@code geotk-setup} module to be present on the classpath. * <p> * Users can also display the same GUI from the command line by running the following * command in the shell (replace {@code SNAPSHOT} by the actual Geotk version number): * * {@preformat shell * java -jar geotk-setup-SNAPSHOT.jar * } * * @throws UnsupportedOperationException if the {@code geotk-setup} module is not on the classpath. */ public static void showControlPanel() throws UnsupportedOperationException { try { Class.forName("org.geotoolkit.internal.setup.ControlPanel") .getMethod("show", Locale.class).invoke(null, new Object[] {null}); } catch (ClassNotFoundException exception) { throw new UnsupportedOperationException(Errors.format( Errors.Keys.MissingModule_1, "geotk-setup"), exception); } catch (InvocationTargetException exception) { final Throwable cause = exception.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new UndeclaredThrowableException(cause); } catch (Exception exception) { // Should never happen if we didn't broke our ControlPanel class. throw new AssertionError(exception); } } }