/*
 * 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.configuration2.builder;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.configuration2.FileBasedConfiguration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.XMLPropertiesConfiguration;
import org.apache.commons.configuration2.event.ConfigurationEvent;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;

A specialized ConfigurationBuilder implementation which can handle configurations read from a FileHandler.

This class extends its base class by the support of a FileBasedBuilderParametersImpl object, and especially of the FileHandler contained in this object. When the builder creates a new object the resulting Configuration instance is associated with the FileHandler. If the FileHandler has a location set, the Configuration is directly loaded from this location.

The FileHandler is kept by this builder and can be queried later on. It can be used for instance to save the current Configuration after it was modified. Some care has to be taken when changing the location of the FileHandler: The new location is recorded and also survives an invocation of the resetResult() method. However, when the builder's initialization parameters are reset by calling resetParameters() the location is reset, too.

Type parameters:
  • <T> – the concrete type of Configuration objects created by this builder
Since:2.0
/** * <p> * A specialized {@code ConfigurationBuilder} implementation which can handle * configurations read from a {@link FileHandler}. * </p> * <p> * This class extends its base class by the support of a * {@link FileBasedBuilderParametersImpl} object, and especially of the * {@link FileHandler} contained in this object. When the builder creates a new * object the resulting {@code Configuration} instance is associated with the * {@code FileHandler}. If the {@code FileHandler} has a location set, the * {@code Configuration} is directly loaded from this location. * </p> * <p> * The {@code FileHandler} is kept by this builder and can be queried later on. * It can be used for instance to save the current {@code Configuration} after * it was modified. Some care has to be taken when changing the location of the * {@code FileHandler}: The new location is recorded and also survives an * invocation of the {@code resetResult()} method. However, when the builder's * initialization parameters are reset by calling {@code resetParameters()} the * location is reset, too. * </p> * * @since 2.0 * @param <T> the concrete type of {@code Configuration} objects created by this * builder */
public class FileBasedConfigurationBuilder<T extends FileBasedConfiguration> extends BasicConfigurationBuilder<T> {
A map for storing default encodings for specific configuration classes.
/** A map for storing default encodings for specific configuration classes. */
private static final Map<Class<?>, String> DEFAULT_ENCODINGS = initializeDefaultEncodings();
Stores the FileHandler associated with the current configuration.
/** Stores the FileHandler associated with the current configuration. */
private FileHandler currentFileHandler;
A specialized listener for the auto save mechanism.
/** A specialized listener for the auto save mechanism. */
private AutoSaveListener autoSaveListener;
A flag whether the builder's parameters were reset.
/** A flag whether the builder's parameters were reset. */
private boolean resetParameters;
Creates a new instance of FileBasedConfigurationBuilder which produces result objects of the specified class.
Params:
  • resCls – the result class (must not be null
Throws:
/** * Creates a new instance of {@code FileBasedConfigurationBuilder} which * produces result objects of the specified class. * * @param resCls the result class (must not be <b>null</b> * @throws IllegalArgumentException if the result class is <b>null</b> */
public FileBasedConfigurationBuilder(final Class<? extends T> resCls) { super(resCls); }
Creates a new instance of FileBasedConfigurationBuilder which produces result objects of the specified class and sets initialization parameters.
Params:
  • resCls – the result class (must not be null
  • params – a map with initialization parameters
Throws:
/** * Creates a new instance of {@code FileBasedConfigurationBuilder} which * produces result objects of the specified class and sets initialization * parameters. * * @param resCls the result class (must not be <b>null</b> * @param params a map with initialization parameters * @throws IllegalArgumentException if the result class is <b>null</b> */
public FileBasedConfigurationBuilder(final Class<? extends T> resCls, final Map<String, Object> params) { super(resCls, params); }
Creates a new instance of FileBasedConfigurationBuilder which produces result objects of the specified class and sets initialization parameters and the allowFailOnInit flag.
Params:
  • resCls – the result class (must not be null
  • params – a map with initialization parameters
  • allowFailOnInit – the allowFailOnInit flag
Throws:
/** * Creates a new instance of {@code FileBasedConfigurationBuilder} which * produces result objects of the specified class and sets initialization * parameters and the <em>allowFailOnInit</em> flag. * * @param resCls the result class (must not be <b>null</b> * @param params a map with initialization parameters * @param allowFailOnInit the <em>allowFailOnInit</em> flag * @throws IllegalArgumentException if the result class is <b>null</b> */
public FileBasedConfigurationBuilder(final Class<? extends T> resCls, final Map<String, Object> params, final boolean allowFailOnInit) { super(resCls, params, allowFailOnInit); }
Returns the default encoding for the specified configuration class. If an encoding has been set for the specified class (or one of its super classes), it is returned. Otherwise, result is null.
Params:
  • configClass – the configuration class in question
Returns:the default encoding for this class (may be null)
/** * Returns the default encoding for the specified configuration class. If an * encoding has been set for the specified class (or one of its super * classes), it is returned. Otherwise, result is <b>null</b>. * * @param configClass the configuration class in question * @return the default encoding for this class (may be <b>null</b>) */
public static String getDefaultEncoding(final Class<?> configClass) { String enc = DEFAULT_ENCODINGS.get(configClass); if (enc != null || configClass == null) { return enc; } final List<Class<?>> superclasses = ClassUtils.getAllSuperclasses(configClass); for (final Class<?> cls : superclasses) { enc = DEFAULT_ENCODINGS.get(cls); if (enc != null) { return enc; } } final List<Class<?>> interfaces = ClassUtils.getAllInterfaces(configClass); for (final Class<?> cls : interfaces) { enc = DEFAULT_ENCODINGS.get(cls); if (enc != null) { return enc; } } return null; }
Sets a default encoding for a specific configuration class. This encoding is used if an instance of this configuration class is to be created and no encoding has been set in the parameters object for this builder. The encoding passed here not only applies to the specified class but also to its sub classes. If the encoding is null, it is removed.
Params:
  • configClass – the name of the configuration class (must not be null)
  • encoding – the default encoding for this class
Throws:
/** * Sets a default encoding for a specific configuration class. This encoding * is used if an instance of this configuration class is to be created and * no encoding has been set in the parameters object for this builder. The * encoding passed here not only applies to the specified class but also to * its sub classes. If the encoding is <b>null</b>, it is removed. * * @param configClass the name of the configuration class (must not be * <b>null</b>) * @param encoding the default encoding for this class * @throws IllegalArgumentException if the class is <b>null</b> */
public static void setDefaultEncoding(final Class<?> configClass, final String encoding) { if (configClass == null) { throw new IllegalArgumentException( "Configuration class must not be null!"); } if (encoding == null) { DEFAULT_ENCODINGS.remove(configClass); } else { DEFAULT_ENCODINGS.put(configClass, encoding); } }
{@inheritDoc} This method is overridden here to change the result type.
/** * {@inheritDoc} This method is overridden here to change the result type. */
@Override public FileBasedConfigurationBuilder<T> configure( final BuilderParameters... params) { super.configure(params); return this; }
Returns the FileHandler associated with this builder. If already a result object has been created, this FileHandler can be used to save it. Otherwise, the FileHandler from the initialization parameters is returned (which is not associated with a FileBased object). Result is never null.
Returns:the FileHandler associated with this builder
/** * Returns the {@code FileHandler} associated with this builder. If already * a result object has been created, this {@code FileHandler} can be used to * save it. Otherwise, the {@code FileHandler} from the initialization * parameters is returned (which is not associated with a {@code FileBased} * object). Result is never <b>null</b>. * * @return the {@code FileHandler} associated with this builder */
public synchronized FileHandler getFileHandler() { return currentFileHandler != null ? currentFileHandler : fetchFileHandlerFromParameters(); }
{@inheritDoc} This implementation just records the fact that new parameters have been set. This means that the next time a result object is created, the FileHandler has to be initialized from initialization parameters rather than reusing the existing one.
/** * {@inheritDoc} This implementation just records the fact that new * parameters have been set. This means that the next time a result object * is created, the {@code FileHandler} has to be initialized from * initialization parameters rather than reusing the existing one. */
@Override public synchronized BasicConfigurationBuilder<T> setParameters( final Map<String, Object> params) { super.setParameters(params); resetParameters = true; return this; }
Convenience method which saves the associated configuration. This method expects that the managed configuration has already been created and that a valid file location is available in the current FileHandler. The file handler is then used to store the configuration.
Throws:
/** * Convenience method which saves the associated configuration. This method * expects that the managed configuration has already been created and that * a valid file location is available in the current {@code FileHandler}. * The file handler is then used to store the configuration. * * @throws ConfigurationException if an error occurs */
public void save() throws ConfigurationException { getFileHandler().save(); }
Returns a flag whether auto save mode is currently active.
Returns:true if auto save is enabled, false otherwise
/** * Returns a flag whether auto save mode is currently active. * * @return <b>true</b> if auto save is enabled, <b>false</b> otherwise */
public synchronized boolean isAutoSave() { return autoSaveListener != null; }
Enables or disables auto save mode. If auto save mode is enabled, every update of the managed configuration causes it to be saved automatically; so changes are directly written to disk.
Params:
  • enabled – true if auto save mode is to be enabled, false otherwise
/** * Enables or disables auto save mode. If auto save mode is enabled, every * update of the managed configuration causes it to be saved automatically; * so changes are directly written to disk. * * @param enabled <b>true</b> if auto save mode is to be enabled, * <b>false</b> otherwise */
public synchronized void setAutoSave(final boolean enabled) { if (enabled) { installAutoSaveListener(); } else { removeAutoSaveListener(); } }
{@inheritDoc} This implementation deals with the creation and initialization of a FileHandler associated with the new result object.
/** * {@inheritDoc} This implementation deals with the creation and * initialization of a {@code FileHandler} associated with the new result * object. */
@Override protected void initResultInstance(final T obj) throws ConfigurationException { super.initResultInstance(obj); final FileHandler srcHandler = currentFileHandler != null && !resetParameters ? currentFileHandler : fetchFileHandlerFromParameters(); currentFileHandler = new FileHandler(obj, srcHandler); if (autoSaveListener != null) { autoSaveListener.updateFileHandler(currentFileHandler); } initFileHandler(currentFileHandler); resetParameters = false; }
Initializes the new current FileHandler. When a new result object is created, a new FileHandler is created, too, and associated with the result object. This new handler is passed to this method. If a location is defined, the result object is loaded from this location. Note: This method is called from a synchronized block.
Params:
  • handler – the new current FileHandler
Throws:
/** * Initializes the new current {@code FileHandler}. When a new result object * is created, a new {@code FileHandler} is created, too, and associated * with the result object. This new handler is passed to this method. If a * location is defined, the result object is loaded from this location. * Note: This method is called from a synchronized block. * * @param handler the new current {@code FileHandler} * @throws ConfigurationException if an error occurs */
protected void initFileHandler(final FileHandler handler) throws ConfigurationException { initEncoding(handler); if (handler.isLocationDefined()) { handler.locate(); handler.load(); } }
Obtains the FileHandler from this builder's parameters. If no FileBasedBuilderParametersImpl object is found in this builder's parameters, a new one is created now and stored. This makes it possible to change the location of the associated file even if no parameters object was provided.
Returns:the FileHandler from initialization parameters
/** * Obtains the {@code FileHandler} from this builder's parameters. If no * {@code FileBasedBuilderParametersImpl} object is found in this builder's * parameters, a new one is created now and stored. This makes it possible * to change the location of the associated file even if no parameters * object was provided. * * @return the {@code FileHandler} from initialization parameters */
private FileHandler fetchFileHandlerFromParameters() { FileBasedBuilderParametersImpl fileParams = FileBasedBuilderParametersImpl.fromParameters(getParameters(), false); if (fileParams == null) { fileParams = new FileBasedBuilderParametersImpl(); addParameters(fileParams.getParameters()); } return fileParams.getFileHandler(); }
Installs the listener for the auto save mechanism if it is not yet active.
/** * Installs the listener for the auto save mechanism if it is not yet * active. */
private void installAutoSaveListener() { if (autoSaveListener == null) { autoSaveListener = new AutoSaveListener(this); addEventListener(ConfigurationEvent.ANY, autoSaveListener); autoSaveListener.updateFileHandler(getFileHandler()); } }
Removes the listener for the auto save mechanism if it is currently active.
/** * Removes the listener for the auto save mechanism if it is currently * active. */
private void removeAutoSaveListener() { if (autoSaveListener != null) { removeEventListener(ConfigurationEvent.ANY, autoSaveListener); autoSaveListener.updateFileHandler(null); autoSaveListener = null; } }
Initializes the encoding of the specified file handler. If already an encoding is set, it is used. Otherwise, the default encoding for the result configuration class is obtained and set.
Params:
  • handler – the handler to be initialized
/** * Initializes the encoding of the specified file handler. If already an * encoding is set, it is used. Otherwise, the default encoding for the * result configuration class is obtained and set. * * @param handler the handler to be initialized */
private void initEncoding(final FileHandler handler) { if (StringUtils.isEmpty(handler.getEncoding())) { final String encoding = getDefaultEncoding(getResultClass()); if (encoding != null) { handler.setEncoding(encoding); } } }
Creates a map with default encodings for configuration classes and populates it with default entries.
Returns:the map with default encodings
/** * Creates a map with default encodings for configuration classes and * populates it with default entries. * * @return the map with default encodings */
private static Map<Class<?>, String> initializeDefaultEncodings() { final Map<Class<?>, String> enc = new ConcurrentHashMap<>(); enc.put(PropertiesConfiguration.class, PropertiesConfiguration.DEFAULT_ENCODING); enc.put(XMLPropertiesConfiguration.class, XMLPropertiesConfiguration.DEFAULT_ENCODING); return enc; } }