All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder Maven / Gradle / Ivy

Go to download

Tools to assist in the reading of configuration/preferences files in various formats

The newest version!
/*
 * 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.Map;

import org.apache.commons.configuration2.FileBasedConfiguration;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.configuration2.reloading.ReloadingController;
import org.apache.commons.configuration2.reloading.ReloadingControllerSupport;
import org.apache.commons.configuration2.reloading.ReloadingDetector;

/**
 * 

* A specialized {@code ConfigurationBuilder} implementation which can handle configurations read from a * {@link FileHandler} and supports reloading. *

*

* This builder class exposes a {@link ReloadingController} object controlling reload operations on the file-based * configuration produced as result object. For the {@code FileHandler} defining the location of the configuration a * configurable {@link ReloadingDetector} is created and associated with the controller. So changes on the source file * can be detected. When ever such a change occurs, the result object of this builder is reset. This means that the next * time {@code getConfiguration()} is called a new {@code Configuration} object is created which is loaded from the * modified file. *

*

* Client code interested in notifications can register a listener at this builder to receive reset events. When such an * event is received the new result object can be requested. This way client applications can be sure to work with an * up-to-date configuration. It is also possible to register a listener directly at the {@code ReloadingController}. *

*

* This builder does not actively trigger the {@code ReloadingController} to perform a reload check. This has to be done * by an external component, e.g. a timer. *

* * @since 2.0 * @param the concrete type of {@code Configuration} objects created by this builder */ public class ReloadingFileBasedConfigurationBuilder extends FileBasedConfigurationBuilder implements ReloadingControllerSupport { /** The default factory for creating reloading detector objects. */ private static final ReloadingDetectorFactory DEFAULT_DETECTOR_FACTORY = new DefaultReloadingDetectorFactory(); /** * Returns a {@code ReloadingDetectorFactory} either from the passed in parameters or a default factory. * * @param params the current parameters object * @return the {@code ReloadingDetectorFactory} to be used */ private static ReloadingDetectorFactory fetchDetectorFactory(final FileBasedBuilderParametersImpl params) { final ReloadingDetectorFactory factory = params.getReloadingDetectorFactory(); return factory != null ? factory : DEFAULT_DETECTOR_FACTORY; } /** The reloading controller associated with this object. */ private final ReloadingController reloadingController; /** * The reloading detector which does the actual reload check for the current result object. A new instance is created * whenever a new result object (and thus a new current file handler) becomes available. The field must be volatile * because it is accessed by the reloading controller probably from within another thread. */ private volatile ReloadingDetector resultReloadingDetector; /** * Creates a new instance of {@code ReloadingFileBasedConfigurationBuilder} which produces result objects of the * specified class. * * @param resCls the result class (must not be null * @throws IllegalArgumentException if the result class is null */ public ReloadingFileBasedConfigurationBuilder(final Class resCls) { super(resCls); reloadingController = createReloadingController(); } /** * Creates a new instance of {@code ReloadingFileBasedConfigurationBuilder} which produces result objects of the * specified class and sets initialization parameters. * * @param resCls the result class (must not be null * @param params a map with initialization parameters * @throws IllegalArgumentException if the result class is null */ public ReloadingFileBasedConfigurationBuilder(final Class resCls, final Map params) { super(resCls, params); reloadingController = createReloadingController(); } /** * Creates a new instance of {@code ReloadingFileBasedConfigurationBuilder} which produces result objects of the * specified class and sets initialization parameters and the allowFailOnInit flag. * * @param resCls the result class (must not be null * @param params a map with initialization parameters * @param allowFailOnInit the allowFailOnInit flag * @throws IllegalArgumentException if the result class is null */ public ReloadingFileBasedConfigurationBuilder(final Class resCls, final Map params, final boolean allowFailOnInit) { super(resCls, params, allowFailOnInit); reloadingController = createReloadingController(); } /** * {@inheritDoc} This method is overridden here to change the result type. */ @Override public ReloadingFileBasedConfigurationBuilder configure(final BuilderParameters... params) { super.configure(params); return this; } /** * Creates the {@code ReloadingController} associated with this object. The controller is assigned a specialized * reloading detector which delegates to the detector for the current result object. ( * {@code FileHandlerReloadingDetector} does not support changing the file handler, and {@code ReloadingController} does * not support changing the reloading detector; therefore, this level of indirection is needed to change the monitored * file dynamically.) * * @return the new {@code ReloadingController} */ private ReloadingController createReloadingController() { final ReloadingDetector ctrlDetector = createReloadingDetectorForController(); final ReloadingController ctrl = new ReloadingController(ctrlDetector); connectToReloadingController(ctrl); return ctrl; } /** * Creates a {@code ReloadingDetector} which monitors the passed in {@code FileHandler}. This method is called each time * a new result object is created with the current {@code FileHandler}. This implementation checks whether a * {@code ReloadingDetectorFactory} is specified in the current parameters. If this is the case, it is invoked. * Otherwise, a default factory is used to create a {@code FileHandlerReloadingDetector} object. Note: This method is * called from a synchronized block. * * @param handler the current {@code FileHandler} * @param fbparams the object with parameters related to file-based builders * @return a {@code ReloadingDetector} for this {@code FileHandler} * @throws ConfigurationException if an error occurs */ protected ReloadingDetector createReloadingDetector(final FileHandler handler, final FileBasedBuilderParametersImpl fbparams) throws ConfigurationException { return fetchDetectorFactory(fbparams).createReloadingDetector(handler, fbparams); } /** * Creates a {@code ReloadingDetector} wrapper to be passed to the associated {@code ReloadingController}. This detector * wrapper simply delegates to the current {@code ReloadingDetector} if it is available. * * @return the wrapper {@code ReloadingDetector} */ private ReloadingDetector createReloadingDetectorForController() { return new ReloadingDetector() { @Override public boolean isReloadingRequired() { final ReloadingDetector detector = resultReloadingDetector; return detector != null && detector.isReloadingRequired(); } @Override public void reloadingPerformed() { final ReloadingDetector detector = resultReloadingDetector; if (detector != null) { detector.reloadingPerformed(); } } }; } /** * Gets the {@code ReloadingController} associated with this builder. This controller is directly created. However, * it becomes active (i.e. associated with a meaningful reloading detector) not before a result object was created. * * @return the {@code ReloadingController} */ @Override public ReloadingController getReloadingController() { return reloadingController; } /** * {@inheritDoc} This implementation also takes care that a new {@code ReloadingDetector} for the new current * {@code FileHandler} is created. Also, the reloading controller's reloading state has to be reset; after the creation * of a new result object changes in the underlying configuration source have to be monitored again. */ @Override protected void initFileHandler(final FileHandler handler) throws ConfigurationException { super.initFileHandler(handler); resultReloadingDetector = createReloadingDetector(handler, FileBasedBuilderParametersImpl.fromParameters(getParameters(), true)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy