/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.configuration;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URL;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
import org.apache.commons.configuration.reloading.ReloadingStrategy;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;

Partial implementation of the FileConfiguration interface. Developers of file based configuration may want to extend this class, the two methods left to implement are FileConfiguration.load(Reader) and FileConfiguration.save(Writer).

This base class already implements a couple of ways to specify the location of the file this configuration is based on. The following possibilities exist:

  • URLs: With the method setURL() a full URL to the configuration source can be specified. This is the most flexible way. Note that the save() methods support only file: URLs.
  • Files: The setFile() method allows to specify the configuration source as a file. This can be either a relative or an absolute file. In the former case the file is resolved based on the current directory.
  • As file paths in string form: With the setPath() method a full path to a configuration file can be provided as a string.
  • Separated as base path and file name: This is the native form in which the location is stored. The base path is a string defining either a local directory or a URL. It can be set using the setBasePath() method. The file name, non surprisingly, defines the name of the configuration file.

The configuration source to be loaded can be specified using one of the methods described above. Then the parameterless load() method can be called. Alternatively, one of the load() methods can be used which is passed the source directly. These methods typically do not change the internally stored file; however, if the configuration is not yet associated with a configuration source, the first call to one of the load() methods sets the base path and the source URL. This fact has to be taken into account when calling load() multiple times with different file paths.

Note that the load() methods do not wipe out the configuration's content before the new configuration file is loaded. Thus it is very easy to construct a union configuration by simply loading multiple configuration files, e.g.

config.load(configFile1);
config.load(configFile2);

After executing this code fragment, the resulting configuration will contain both the properties of configFile1 and configFile2. On the other hand, if the current configuration file is to be reloaded, clear() should be called first. Otherwise the properties are doubled. This behavior is analogous to the behavior of the load(InputStream) method in java.util.Properties.

Author:Emmanuel Bourg
Version:$Id: AbstractFileConfiguration.java 1234118 2012-01-20 20:36:04Z oheger $
Since:1.0-rc2
/** * <p>Partial implementation of the {@code FileConfiguration} interface. * Developers of file based configuration may want to extend this class, * the two methods left to implement are {@link FileConfiguration#load(Reader)} * and {@link FileConfiguration#save(Writer)}.</p> * <p>This base class already implements a couple of ways to specify the location * of the file this configuration is based on. The following possibilities * exist: * <ul><li>URLs: With the method {@code setURL()} a full URL to the * configuration source can be specified. This is the most flexible way. Note * that the {@code save()} methods support only <em>file:</em> URLs.</li> * <li>Files: The {@code setFile()} method allows to specify the * configuration source as a file. This can be either a relative or an * absolute file. In the former case the file is resolved based on the current * directory.</li> * <li>As file paths in string form: With the {@code setPath()} method a * full path to a configuration file can be provided as a string.</li> * <li>Separated as base path and file name: This is the native form in which * the location is stored. The base path is a string defining either a local * directory or a URL. It can be set using the {@code setBasePath()} * method. The file name, non surprisingly, defines the name of the configuration * file.</li></ul></p> * <p>The configuration source to be loaded can be specified using one of the * methods described above. Then the parameterless {@code load()} method can be * called. Alternatively, one of the {@code load()} methods can be used which is * passed the source directly. These methods typically do not change the * internally stored file; however, if the configuration is not yet associated * with a configuration source, the first call to one of the {@code load()} * methods sets the base path and the source URL. This fact has to be taken * into account when calling {@code load()} multiple times with different file * paths.</p> * <p>Note that the {@code load()} methods do not wipe out the configuration's * content before the new configuration file is loaded. Thus it is very easy to * construct a union configuration by simply loading multiple configuration * files, e.g.</p> * <p><pre> * config.load(configFile1); * config.load(configFile2); * </pre></p> * <p>After executing this code fragment, the resulting configuration will * contain both the properties of configFile1 and configFile2. On the other * hand, if the current configuration file is to be reloaded, {@code clear()} * should be called first. Otherwise the properties are doubled. This behavior * is analogous to the behavior of the {@code load(InputStream)} method * in {@code java.util.Properties}.</p> * * @author Emmanuel Bourg * @version $Id: AbstractFileConfiguration.java 1234118 2012-01-20 20:36:04Z oheger $ * @since 1.0-rc2 */
public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration, FileSystemBased {
Constant for the configuration reload event.
/** Constant for the configuration reload event.*/
public static final int EVENT_RELOAD = 20;
Constant fro the configuration changed event.
/** Constant fro the configuration changed event. */
public static final int EVENT_CONFIG_CHANGED = 21;
The root of the file scheme
/** The root of the file scheme */
private static final String FILE_SCHEME = "file:";
Stores the file name.
/** Stores the file name.*/
protected String fileName;
Stores the base path.
/** Stores the base path.*/
protected String basePath;
The auto save flag.
/** The auto save flag.*/
protected boolean autoSave;
Holds a reference to the reloading strategy.
/** Holds a reference to the reloading strategy.*/
protected ReloadingStrategy strategy;
A lock object for protecting reload operations.
/** A lock object for protecting reload operations.*/
protected Object reloadLock = new Lock("AbstractFileConfiguration");
Stores the encoding of the configuration file.
/** Stores the encoding of the configuration file.*/
private String encoding;
Stores the URL from which the configuration file was loaded.
/** Stores the URL from which the configuration file was loaded.*/
private URL sourceURL;
A counter that prohibits reloading.
/** A counter that prohibits reloading.*/
private int noReload;
The FileSystem being used for this Configuration
/** The FileSystem being used for this Configuration */
private FileSystem fileSystem = FileSystem.getDefaultFileSystem();
Default constructor
Since:1.1
/** * Default constructor * * @since 1.1 */
public AbstractFileConfiguration() { initReloadingStrategy(); setLogger(LogFactory.getLog(getClass())); addErrorLogListener(); }
Creates and loads the configuration from the specified file. The passed in string must be a valid file name, either absolute or relativ.
Params:
  • fileName – The name of the file to load.
Throws:
Since:1.1
/** * Creates and loads the configuration from the specified file. The passed * in string must be a valid file name, either absolute or relativ. * * @param fileName The name of the file to load. * * @throws ConfigurationException Error while loading the file * @since 1.1 */
public AbstractFileConfiguration(String fileName) throws ConfigurationException { this(); // store the file name setFileName(fileName); // load the file load(); }
Creates and loads the configuration from the specified file.
Params:
  • file – The file to load.
Throws:
Since:1.1
/** * Creates and loads the configuration from the specified file. * * @param file The file to load. * @throws ConfigurationException Error while loading the file * @since 1.1 */
public AbstractFileConfiguration(File file) throws ConfigurationException { this(); // set the file and update the url, the base path and the file name setFile(file); // load the file if (file.exists()) { load(); } }
Creates and loads the configuration from the specified URL.
Params:
  • url – The location of the file to load.
Throws:
Since:1.1
/** * Creates and loads the configuration from the specified URL. * * @param url The location of the file to load. * @throws ConfigurationException Error while loading the file * @since 1.1 */
public AbstractFileConfiguration(URL url) throws ConfigurationException { this(); // set the URL and update the base path and the file name setURL(url); // load the file load(); } public void setFileSystem(FileSystem fileSystem) { if (fileSystem == null) { throw new NullPointerException("A valid FileSystem must be specified"); } this.fileSystem = fileSystem; } public void resetFileSystem() { this.fileSystem = FileSystem.getDefaultFileSystem(); } public FileSystem getFileSystem() { return this.fileSystem; } public Object getReloadLock() { return reloadLock; }
Load the configuration from the underlying location.
Throws:
  • ConfigurationException – if loading of the configuration fails
/** * Load the configuration from the underlying location. * * @throws ConfigurationException if loading of the configuration fails */
public void load() throws ConfigurationException { if (sourceURL != null) { load(sourceURL); } else { load(getFileName()); } }
Locate the specified file and load the configuration. If the configuration is already associated with a source, the current source is not changed. Otherwise (i.e. this is the first load operation), the source URL and the base path are set now based on the source to be loaded.
Params:
  • fileName – the name of the file to be loaded
Throws:
/** * Locate the specified file and load the configuration. If the configuration is * already associated with a source, the current source is not changed. * Otherwise (i.e. this is the first load operation), the source URL and * the base path are set now based on the source to be loaded. * * @param fileName the name of the file to be loaded * @throws ConfigurationException if an error occurs */
public void load(String fileName) throws ConfigurationException { try { URL url = ConfigurationUtils.locate(this.fileSystem, basePath, fileName); if (url == null) { throw new ConfigurationException("Cannot locate configuration source " + fileName); } load(url); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration file " + fileName, e); } }
Load the configuration from the specified file. If the configuration is already associated with a source, the current source is not changed. Otherwise (i.e. this is the first load operation), the source URL and the base path are set now based on the source to be loaded.
Params:
  • file – the file to load
Throws:
/** * Load the configuration from the specified file. If the configuration is * already associated with a source, the current source is not changed. * Otherwise (i.e. this is the first load operation), the source URL and * the base path are set now based on the source to be loaded. * * @param file the file to load * @throws ConfigurationException if an error occurs */
public void load(File file) throws ConfigurationException { try { load(ConfigurationUtils.toURL(file)); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration file " + file, e); } }
Load the configuration from the specified URL. If the configuration is already associated with a source, the current source is not changed. Otherwise (i.e. this is the first load operation), the source URL and the base path are set now based on the source to be loaded.
Params:
  • url – the URL of the file to be loaded
Throws:
/** * Load the configuration from the specified URL. If the configuration is * already associated with a source, the current source is not changed. * Otherwise (i.e. this is the first load operation), the source URL and * the base path are set now based on the source to be loaded. * * @param url the URL of the file to be loaded * @throws ConfigurationException if an error occurs */
public void load(URL url) throws ConfigurationException { if (sourceURL == null) { if (StringUtils.isEmpty(getBasePath())) { // ensure that we have a valid base path setBasePath(url.toString()); } sourceURL = url; } InputStream in = null; try { in = fileSystem.getInputStream(url); load(in); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration from the URL " + url, e); } finally { // close the input stream try { if (in != null) { in.close(); } } catch (IOException e) { getLogger().warn("Could not close input stream", e); } } }
Load the configuration from the specified stream, using the encoding returned by getEncoding().
Params:
  • in – the input stream
Throws:
/** * Load the configuration from the specified stream, using the encoding * returned by {@link #getEncoding()}. * * @param in the input stream * * @throws ConfigurationException if an error occurs during the load operation */
public void load(InputStream in) throws ConfigurationException { load(in, getEncoding()); }
Load the configuration from the specified stream, using the specified encoding. If the encoding is null the default encoding is used.
Params:
  • in – the input stream
  • encoding – the encoding used. null to use the default encoding
Throws:
/** * Load the configuration from the specified stream, using the specified * encoding. If the encoding is null the default encoding is used. * * @param in the input stream * @param encoding the encoding used. {@code null} to use the default encoding * * @throws ConfigurationException if an error occurs during the load operation */
public void load(InputStream in, String encoding) throws ConfigurationException { Reader reader = null; if (encoding != null) { try { reader = new InputStreamReader(in, encoding); } catch (UnsupportedEncodingException e) { throw new ConfigurationException( "The requested encoding is not supported, try the default encoding.", e); } } if (reader == null) { reader = new InputStreamReader(in); } load(reader); }
Save the configuration. Before this method can be called a valid file name must have been set.
Throws:
  • ConfigurationException – if an error occurs or no file name has been set yet
/** * Save the configuration. Before this method can be called a valid file * name must have been set. * * @throws ConfigurationException if an error occurs or no file name has * been set yet */
public void save() throws ConfigurationException { if (getFileName() == null) { throw new ConfigurationException("No file name has been set!"); } if (sourceURL != null) { save(sourceURL); } else { save(fileName); } strategy.init(); }
Save the configuration to the specified file. This doesn't change the source of the configuration, use setFileName() if you need it.
Params:
  • fileName – the file name
Throws:
/** * Save the configuration to the specified file. This doesn't change the * source of the configuration, use setFileName() if you need it. * * @param fileName the file name * * @throws ConfigurationException if an error occurs during the save operation */
public void save(String fileName) throws ConfigurationException { try { URL url = this.fileSystem.getURL(basePath, fileName); if (url == null) { throw new ConfigurationException("Cannot locate configuration source " + fileName); } save(url); /*File file = ConfigurationUtils.getFile(basePath, fileName); if (file == null) { throw new ConfigurationException("Invalid file name for save: " + fileName); } save(file); */ } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to save the configuration to the file " + fileName, e); } }
Save the configuration to the specified URL. This doesn't change the source of the configuration, use setURL() if you need it.
Params:
  • url – the URL
Throws:
/** * Save the configuration to the specified URL. * This doesn't change the source of the configuration, use setURL() * if you need it. * * @param url the URL * * @throws ConfigurationException if an error occurs during the save operation */
public void save(URL url) throws ConfigurationException { OutputStream out = null; try { out = fileSystem.getOutputStream(url); save(out); if (out instanceof VerifiableOutputStream) { ((VerifiableOutputStream) out).verify(); } } catch (IOException e) { throw new ConfigurationException("Could not save to URL " + url, e); } finally { closeSilent(out); } }
Save the configuration to the specified file. The file is created automatically if it doesn't exist. This doesn't change the source of the configuration, use setFile if you need it.
Params:
  • file – the target file
Throws:
/** * Save the configuration to the specified file. The file is created * automatically if it doesn't exist. This doesn't change the source * of the configuration, use {@link #setFile} if you need it. * * @param file the target file * * @throws ConfigurationException if an error occurs during the save operation */
public void save(File file) throws ConfigurationException { OutputStream out = null; try { out = fileSystem.getOutputStream(file); save(out); } finally { closeSilent(out); } }
Save the configuration to the specified stream, using the encoding returned by getEncoding().
Params:
  • out – the output stream
Throws:
/** * Save the configuration to the specified stream, using the encoding * returned by {@link #getEncoding()}. * * @param out the output stream * * @throws ConfigurationException if an error occurs during the save operation */
public void save(OutputStream out) throws ConfigurationException { save(out, getEncoding()); }
Save the configuration to the specified stream, using the specified encoding. If the encoding is null the default encoding is used.
Params:
  • out – the output stream
  • encoding – the encoding to use
Throws:
/** * Save the configuration to the specified stream, using the specified * encoding. If the encoding is null the default encoding is used. * * @param out the output stream * @param encoding the encoding to use * @throws ConfigurationException if an error occurs during the save operation */
public void save(OutputStream out, String encoding) throws ConfigurationException { Writer writer = null; if (encoding != null) { try { writer = new OutputStreamWriter(out, encoding); } catch (UnsupportedEncodingException e) { throw new ConfigurationException( "The requested encoding is not supported, try the default encoding.", e); } } if (writer == null) { writer = new OutputStreamWriter(out); } save(writer); }
Return the name of the file.
Returns:the file name
/** * Return the name of the file. * * @return the file name */
public String getFileName() { return fileName; }
Set the name of the file. The passed in file name can contain a relative path. It must be used when referring files with relative paths from classpath. Use setPath() to set a full qualified file name.
Params:
  • fileName – the name of the file
/** * Set the name of the file. The passed in file name can contain a * relative path. * It must be used when referring files with relative paths from classpath. * Use {@link AbstractFileConfiguration#setPath(String) * setPath()} to set a full qualified file name. * * @param fileName the name of the file */
public void setFileName(String fileName) { if (fileName != null && fileName.startsWith(FILE_SCHEME) && !fileName.startsWith("file://")) { fileName = "file://" + fileName.substring(FILE_SCHEME.length()); } sourceURL = null; this.fileName = fileName; getLogger().debug("FileName set to " + fileName); }
Return the base path.
See Also:
Returns:the base path
/** * Return the base path. * * @return the base path * @see FileConfiguration#getBasePath() */
public String getBasePath() { return basePath; }
Sets the base path. The base path is typically either a path to a directory or a URL. Together with the value passed to the setFileName() method it defines the location of the configuration file to be loaded. The strategies for locating the file are quite tolerant. For instance if the file name is already an absolute path or a fully defined URL, the base path will be ignored. The base path can also be a URL, in which case the file name is interpreted in this URL's context. Because the base path is used by some of the derived classes for resolving relative file names it should contain a meaningful value. If other methods are used for determining the location of the configuration file (e.g. setFile() or setURL()), the base path is automatically set.
Params:
  • basePath – the base path.
/** * Sets the base path. The base path is typically either a path to a * directory or a URL. Together with the value passed to the * {@code setFileName()} method it defines the location of the * configuration file to be loaded. The strategies for locating the file are * quite tolerant. For instance if the file name is already an absolute path * or a fully defined URL, the base path will be ignored. The base path can * also be a URL, in which case the file name is interpreted in this URL's * context. Because the base path is used by some of the derived classes for * resolving relative file names it should contain a meaningful value. If * other methods are used for determining the location of the configuration * file (e.g. {@code setFile()} or {@code setURL()}), the * base path is automatically set. * * @param basePath the base path. */
public void setBasePath(String basePath) { if (basePath != null && basePath.startsWith(FILE_SCHEME) && !basePath.startsWith("file://")) { basePath = "file://" + basePath.substring(FILE_SCHEME.length()); } sourceURL = null; this.basePath = basePath; getLogger().debug("Base path set to " + basePath); }
Return the file where the configuration is stored. If the base path is a URL with a protocol different than "file", or the configuration file is within a compressed archive, the return value will not point to a valid file object.
Returns:the file where the configuration is stored; this can be null
/** * Return the file where the configuration is stored. If the base path is a * URL with a protocol different than &quot;file&quot;, or the configuration * file is within a compressed archive, the return value * will not point to a valid file object. * * @return the file where the configuration is stored; this can be <b>null</b> */
public File getFile() { if (getFileName() == null && sourceURL == null) { return null; } else if (sourceURL != null) { return ConfigurationUtils.fileFromURL(sourceURL); } else { return ConfigurationUtils.getFile(getBasePath(), getFileName()); } }
Set the file where the configuration is stored. The passed in file is made absolute if it is not yet. Then the file's path component becomes the base path and its name component becomes the file name.
Params:
  • file – the file where the configuration is stored
/** * Set the file where the configuration is stored. The passed in file is * made absolute if it is not yet. Then the file's path component becomes * the base path and its name component becomes the file name. * * @param file the file where the configuration is stored */
public void setFile(File file) { sourceURL = null; setFileName(file.getName()); setBasePath((file.getParentFile() != null) ? file.getParentFile() .getAbsolutePath() : null); }
Returns the full path to the file this configuration is based on. The return value is a valid File path only if this configuration is based on a file on the local disk. If the configuration was loaded from a packed archive the returned value is the string form of the URL from which the configuration was loaded.
Returns:the full path to the configuration file
/** * Returns the full path to the file this configuration is based on. The * return value is a valid File path only if this configuration is based on * a file on the local disk. * If the configuration was loaded from a packed archive the returned value * is the string form of the URL from which the configuration was loaded. * * @return the full path to the configuration file */
public String getPath() { return fileSystem.getPath(getFile(), sourceURL, getBasePath(), getFileName()); }
Sets the location of this configuration as a full or relative path name. The passed in path should represent a valid file name on the file system. It must not be used to specify relative paths for files that exist in classpath, either plain file system or compressed archive, because this method expands any relative path to an absolute one which may end in an invalid absolute path for classpath references.
Params:
  • path – the full path name of the configuration file
/** * Sets the location of this configuration as a full or relative path name. * The passed in path should represent a valid file name on the file system. * It must not be used to specify relative paths for files that exist * in classpath, either plain file system or compressed archive, * because this method expands any relative path to an absolute one which * may end in an invalid absolute path for classpath references. * * @param path the full path name of the configuration file */
public void setPath(String path) { setFile(new File(path)); } URL getSourceURL() { return sourceURL; }
Return the URL where the configuration is stored.
Returns:the configuration's location as URL
/** * Return the URL where the configuration is stored. * * @return the configuration's location as URL */
public URL getURL() { return (sourceURL != null) ? sourceURL : ConfigurationUtils.locate(this.fileSystem, getBasePath(), getFileName()); }
Set the location of this configuration as a URL. For loading this can be an arbitrary URL with a supported protocol. If the configuration is to be saved, too, a URL with the "file" protocol should be provided.
Params:
  • url – the location of this configuration as URL
/** * Set the location of this configuration as a URL. For loading this can be * an arbitrary URL with a supported protocol. If the configuration is to * be saved, too, a URL with the &quot;file&quot; protocol should be * provided. * * @param url the location of this configuration as URL */
public void setURL(URL url) { setBasePath(ConfigurationUtils.getBasePath(url)); setFileName(ConfigurationUtils.getFileName(url)); sourceURL = url; getLogger().debug("URL set to " + url); } public void setAutoSave(boolean autoSave) { this.autoSave = autoSave; } public boolean isAutoSave() { return autoSave; }
Save the configuration if the automatic persistence is enabled and if a file is specified.
/** * Save the configuration if the automatic persistence is enabled * and if a file is specified. */
protected void possiblySave() { if (autoSave && fileName != null) { try { save(); } catch (ConfigurationException e) { throw new ConfigurationRuntimeException("Failed to auto-save", e); } } }
Adds a new property to this configuration. This implementation checks if the auto save mode is enabled and saves the configuration if necessary.
Params:
  • key – the key of the new property
  • value – the value
/** * Adds a new property to this configuration. This implementation checks if * the auto save mode is enabled and saves the configuration if necessary. * * @param key the key of the new property * @param value the value */
@Override public void addProperty(String key, Object value) { synchronized (reloadLock) { super.addProperty(key, value); possiblySave(); } }
Sets a new value for the specified property. This implementation checks if the auto save mode is enabled and saves the configuration if necessary.
Params:
  • key – the key of the affected property
  • value – the value
/** * Sets a new value for the specified property. This implementation checks * if the auto save mode is enabled and saves the configuration if * necessary. * * @param key the key of the affected property * @param value the value */
@Override public void setProperty(String key, Object value) { synchronized (reloadLock) { super.setProperty(key, value); possiblySave(); } } @Override public void clearProperty(String key) { synchronized (reloadLock) { super.clearProperty(key); possiblySave(); } } public ReloadingStrategy getReloadingStrategy() { return strategy; } public void setReloadingStrategy(ReloadingStrategy strategy) { this.strategy = strategy; strategy.setConfiguration(this); strategy.init(); }
Performs a reload operation if necessary. This method is called on each access of this configuration. It asks the associated reloading strategy whether a reload should be performed. If this is the case, the configuration is cleared and loaded again from its source. If this operation causes an exception, the registered error listeners will be notified. The error event passed to the listeners is of type EVENT_RELOAD and contains the exception that caused the event.
/** * Performs a reload operation if necessary. This method is called on each * access of this configuration. It asks the associated reloading strategy * whether a reload should be performed. If this is the case, the * configuration is cleared and loaded again from its source. If this * operation causes an exception, the registered error listeners will be * notified. The error event passed to the listeners is of type * {@code EVENT_RELOAD} and contains the exception that caused the * event. */
public void reload() { reload(false); } public boolean reload(boolean checkReload) { synchronized (reloadLock) { if (noReload == 0) { try { enterNoReload(); // avoid reentrant calls if (strategy.reloadingRequired()) { if (getLogger().isInfoEnabled()) { getLogger().info("Reloading configuration. URL is " + getURL()); } refresh(); // notify the strategy strategy.reloadingPerformed(); } } catch (Exception e) { fireError(EVENT_RELOAD, null, null, e); // todo rollback the changes if the file can't be reloaded if (checkReload) { return false; } } finally { exitNoReload(); } } } return true; }
Reloads the associated configuration file. This method first clears the content of this configuration, then the associated configuration file is loaded again. Updates on this configuration which have not yet been saved are lost. Calling this method is like invoking reload() without checking the reloading strategy.
Throws:
Since:1.7
/** * Reloads the associated configuration file. This method first clears the * content of this configuration, then the associated configuration file is * loaded again. Updates on this configuration which have not yet been saved * are lost. Calling this method is like invoking {@code reload()} * without checking the reloading strategy. * * @throws ConfigurationException if an error occurs * @since 1.7 */
public void refresh() throws ConfigurationException { fireEvent(EVENT_RELOAD, null, getURL(), true); setDetailEvents(false); boolean autoSaveBak = this.isAutoSave(); // save the current state this.setAutoSave(false); // deactivate autoSave to prevent information loss try { clear(); load(); } finally { this.setAutoSave(autoSaveBak); // set autoSave to previous value setDetailEvents(true); } fireEvent(EVENT_RELOAD, null, getURL(), false); }
Send notification that the configuration has changed.
/** * Send notification that the configuration has changed. */
public void configurationChanged() { fireEvent(EVENT_CONFIG_CHANGED, null, getURL(), true); }
Enters the "No reloading mode". As long as this mode is active no reloading will be performed. This is necessary for some implementations of save() in derived classes, which may cause a reload while accessing the properties to save. This may cause the whole configuration to be erased. To avoid this, this method can be called first. After a call to this method there always must be a corresponding call of exitNoReload() later! (If necessary, finally blocks must be used to ensure this.
/** * Enters the &quot;No reloading mode&quot;. As long as this mode is active * no reloading will be performed. This is necessary for some * implementations of {@code save()} in derived classes, which may * cause a reload while accessing the properties to save. This may cause the * whole configuration to be erased. To avoid this, this method can be * called first. After a call to this method there always must be a * corresponding call of {@link #exitNoReload()} later! (If * necessary, {@code finally} blocks must be used to ensure this. */
protected void enterNoReload() { synchronized (reloadLock) { noReload++; } }
Leaves the "No reloading mode".
See Also:
  • enterNoReload()
/** * Leaves the &quot;No reloading mode&quot;. * * @see #enterNoReload() */
protected void exitNoReload() { synchronized (reloadLock) { if (noReload > 0) // paranoia check { noReload--; } } }
Sends an event to all registered listeners. This implementation ensures that no reloads are performed while the listeners are invoked. So infinite loops can be avoided that can be caused by event listeners accessing the configuration's properties when they are invoked.
Params:
  • type – the event type
  • propName – the name of the property
  • propValue – the value of the property
  • before – the before update flag
/** * Sends an event to all registered listeners. This implementation ensures * that no reloads are performed while the listeners are invoked. So * infinite loops can be avoided that can be caused by event listeners * accessing the configuration's properties when they are invoked. * * @param type the event type * @param propName the name of the property * @param propValue the value of the property * @param before the before update flag */
@Override protected void fireEvent(int type, String propName, Object propValue, boolean before) { enterNoReload(); try { super.fireEvent(type, propName, propValue, before); } finally { exitNoReload(); } } @Override public Object getProperty(String key) { synchronized (reloadLock) { reload(); return super.getProperty(key); } } @Override public boolean isEmpty() { reload(); synchronized (reloadLock) { return super.isEmpty(); } } @Override public boolean containsKey(String key) { reload(); synchronized (reloadLock) { return super.containsKey(key); } }
Returns an Iterator with the keys contained in this configuration. This implementation performs a reload if necessary before obtaining the keys. The Iterator returned by this method points to a snapshot taken when this method was called. Later changes at the set of keys (including those caused by a reload) won't be visible. This is because a reload can happen at any time during iteration, and it is impossible to determine how this reload affects the current iteration. When using the iterator a client has to be aware that changes of the configuration are possible at any time. For instance, if after a reload operation some keys are no longer present, the iterator will still return those keys because they were found when it was created.
Returns:an Iterator with the keys of this configuration
/** * Returns an {@code Iterator} with the keys contained in this * configuration. This implementation performs a reload if necessary before * obtaining the keys. The {@code Iterator} returned by this method * points to a snapshot taken when this method was called. Later changes at * the set of keys (including those caused by a reload) won't be visible. * This is because a reload can happen at any time during iteration, and it * is impossible to determine how this reload affects the current iteration. * When using the iterator a client has to be aware that changes of the * configuration are possible at any time. For instance, if after a reload * operation some keys are no longer present, the iterator will still return * those keys because they were found when it was created. * * @return an {@code Iterator} with the keys of this configuration */
@Override public Iterator<String> getKeys() { reload(); List<String> keyList = new LinkedList<String>(); enterNoReload(); try { for (Iterator<String> it = super.getKeys(); it.hasNext();) { keyList.add(it.next()); } return keyList.iterator(); } finally { exitNoReload(); } } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; }
Creates a copy of this configuration. The new configuration object will contain the same properties as the original, but it will lose any connection to a source file (if one exists); this includes setting the source URL, base path, and file name to null. This is done to avoid race conditions if both the original and the copy are modified and then saved.
Returns:the copy
Since:1.3
/** * Creates a copy of this configuration. The new configuration object will * contain the same properties as the original, but it will lose any * connection to a source file (if one exists); this includes setting the * source URL, base path, and file name to <b>null</b>. This is done to * avoid race conditions if both the original and the copy are modified and * then saved. * * @return the copy * @since 1.3 */
@Override public Object clone() { AbstractFileConfiguration copy = (AbstractFileConfiguration) super.clone(); copy.setBasePath(null); copy.setFileName(null); copy.initReloadingStrategy(); return copy; }
Helper method for initializing the reloading strategy.
/** * Helper method for initializing the reloading strategy. */
private void initReloadingStrategy() { setReloadingStrategy(new InvariantReloadingStrategy()); }
A helper method for closing an output stream. Occurring exceptions will be ignored.
Params:
  • out – the output stream to be closed (may be null)
Since:1.5
/** * A helper method for closing an output stream. Occurring exceptions will * be ignored. * * @param out the output stream to be closed (may be <b>null</b>) * @since 1.5 */
protected void closeSilent(OutputStream out) { try { if (out != null) { out.close(); } } catch (IOException e) { getLogger().warn("Could not close output stream", e); } } }