/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.config; import org.geotools.util.logging.Logging; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.core.io.Resource; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; /** * A spring placeholder configurer that loads properties from the data directory. * <p> * This class is used by declaring an instance in a spring context: * <pre> * <bean id="myPropertyConfigurer" class="org.geoserver.config.GeoServerPropertyConfigurer"> * <constructor-arg ref="dataDirectory"/> * <property name="location" value="file:myDirectory/myFile.properties"/> * <property name="properties"> * <props> * <prop key="prop1">value1</prop> * <prop key="prop2">value2</prop> * </props> * </property> * </bean> * </pre> * The location <tt>myDirectory/myFile.properties</tt> will be resolved relative to the data directory. * </p> * <p> * In the same spring context the configurer is used as follows: * <pre> * <bean id="myBean" class="com.xyz.MyClass"> * <property name="someProperty" value="${prop1}"/> * <property name="someOtherProperty" value="${prop2}"/> * </bean> * </pre> * If the file <tt>myDirectory/myFile.properties</tt> exists then the property values will be loaded * from it, otherwise the defaults declared on the property configurer will be used. By default when * the resource is not found it will be copied out into the data directory. However * {@link #setCopyOutTemplate(boolean)} can be used to control this. * </p> * * @author Justin Deoliveira, OpenGeo * */ public class GeoServerPropertyConfigurer extends PropertyPlaceholderConfigurer { static Logger LOGGER = Logging.getLogger("org.geoserver.config"); org.geoserver.platform.resource.Resource configFile; protected GeoServerDataDirectory data; boolean copyOutTemplate = true; String comments; public GeoServerPropertyConfigurer(GeoServerDataDirectory data) { this.data = data; } public void setCopyOutTemplate(boolean copyOutTemplate) { this.copyOutTemplate = copyOutTemplate; } public void setComments(String comments) { this.comments = comments; } /** * @return the configLocation */ public org.geoserver.platform.resource.Resource getConfigFile() { return configFile; } @Override public void setLocation(Resource location) { try { location = SpringResourceAdaptor.relative(location, data.getResourceStore()); if (location instanceof SpringResourceAdaptor) { configFile = ((SpringResourceAdaptor) location).getResource(); } } catch(IOException e) { LOGGER.log(Level.WARNING, "Error reading resource " + location, e); } super.setLocation(location); } @Override public void setLocations(Resource[] locations) { throw new UnsupportedOperationException("Only a single location is supported"); } @Override protected void loadProperties(Properties props) throws IOException { try { super.loadProperties(props); } catch(FileNotFoundException e) { //location was not found, create if (configFile != null && copyOutTemplate) { try (OutputStream fout = configFile.out()) { props.store(fout, comments); fout.flush(); } } } } /** * Force reloading the properties which may have been updated in the meanwhile; * after a restore as an instance. * * @throws IOException */ public void reload() throws IOException { if (localProperties != null) { for (Properties props : localProperties) { loadProperties(props); } } } }