/* (c) 2015 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.ogr.core; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.geoserver.config.util.SecureXStream; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.platform.GeoServerResourceLoader; import org.geoserver.platform.resource.Resource; import org.geoserver.platform.resource.Resource.Type; import org.geoserver.platform.resource.ResourceListener; import org.geoserver.platform.resource.ResourceNotification; import org.geotools.util.logging.Logging; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.extended.NamedMapConverter; /** * Loads the tool configuration file and configures the output formats accordingly. * * <p>Also keeps tabs on the configuration file, reloading it as needed. * * @author Andrea Aime, GeoSolutions * @author Stefano Costa, GeoSolutions */ public abstract class AbstractToolConfigurator implements ApplicationListener<ContextClosedEvent> { private static final Logger LOGGER = Logging.getLogger(AbstractToolConfigurator.class); public FormatConverter of; protected ToolWrapperFactory wrapperFactory; protected Resource configFile; // ConfigurationPoller protected ResourceListener listener = new ResourceListener() { public void changed(ResourceNotification notify) { loadConfiguration(); } }; /** * @param formatConverter the format converter tool */ public AbstractToolConfigurator(FormatConverter formatConverter, ToolWrapperFactory wrapperFactory) { this.of = formatConverter; this.wrapperFactory = wrapperFactory; GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class); configFile = loader.get(getConfigurationFile()); loadConfiguration(); configFile.addListener( listener ); } /** * @return the name of the tool configuration file, relative to GeoServer's data directory. */ protected abstract String getConfigurationFile(); /** * @return the tool's default configuration */ protected abstract ToolConfiguration getDefaultConfiguration(); /** * Loads configuration from file, if any; otherwise, loads internal defaults. */ public void loadConfiguration() { // start with the default configuration, override if we can load the file ToolConfiguration configuration = getDefaultConfiguration(); try { if (configFile.getType() == Type.RESOURCE) { InputStream in = configFile.in(); try { XStream xstream = buildXStream(); configuration = (ToolConfiguration) xstream.fromXML( in); } finally { in.close(); } } } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error reading the " + getConfigurationFile() + " configuration file", e); } if (configuration == null) { LOGGER.log(Level.INFO, "Could not find/load the " + getConfigurationFile() + " configuration file, using internal defaults"); configuration = getDefaultConfiguration(); } // should never happen, but just in case... if (configuration == null) { throw new IllegalStateException("No default configuration available, giving up"); } // let's load the configuration ToolWrapper wrapper = wrapperFactory.createWrapper(configuration.getExecutable(), configuration.getEnvironment()); Set<String> supported = wrapper.getSupportedFormats(); of.setExecutable(configuration.getExecutable()); of.setEnvironment(configuration.getEnvironment()); List<Format> toBeAdded = new ArrayList<Format>(); for (Format format : configuration.getFormats()) { if (supported.contains(format.getToolFormat())) { toBeAdded.add(format); } else { LOGGER.severe("Skipping '" + format.getGeoserverFormat() + "' as its tool format '" + format.getToolFormat() + "' is not among the ones supported by " + configuration.getExecutable()); } } // update configured formats at once, potentially alleviating locking overhead of.replaceFormats(toBeAdded); } /** * Builds and configures the XStream used for de-serializing the configuration * */ protected XStream buildXStream() { XStream xstream = new SecureXStream(); xstream.alias("ToolConfiguration", ToolConfiguration.class); xstream.alias("Format", Format.class); xstream.allowTypes(new Class[] { ToolConfiguration.class, Format.class }); xstream.allowTypeHierarchy(FormatAdapter.class); xstream.addImplicitCollection(Format.class, "options", "option", String.class); NamedMapConverter environmentConverter = new NamedMapConverter(xstream .getMapper(), "variable", "name", String.class, "value", String.class, true, true, xstream.getConverterLookup()); xstream.registerConverter(environmentConverter); return xstream; } /** * Kill all threads on web app context shutdown to avoid permgen leaks */ public void onApplicationEvent(ContextClosedEvent event) { if( configFile != null ){ configFile.removeListener(listener); } } }