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

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.configuration.ConfigurationUtils;
import org.apache.commons.configuration.FileConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

A reloading strategy that will reload the configuration every time its underlying file is changed.

This reloading strategy does not actively monitor a configuration file, but is triggered by its associated configuration whenever properties are accessed. It then checks the configuration file's last modification date and causes a reload if this has changed.

To avoid permanent disc access on successive property lookups a refresh delay can be specified. This has the effect that the configuration file's last modification date is only checked once in this delay period. The default value for this refresh delay is 5 seconds.

This strategy only works with FileConfiguration instances.

Author:Emmanuel Bourg
Version:$Id: FileChangedReloadingStrategy.java 1210646 2011-12-05 21:25:01Z oheger $
Since:1.1
/** * <p>A reloading strategy that will reload the configuration every time its * underlying file is changed.</p> * <p>This reloading strategy does not actively monitor a configuration file, * but is triggered by its associated configuration whenever properties are * accessed. It then checks the configuration file's last modification date * and causes a reload if this has changed.</p> * <p>To avoid permanent disc access on successive property lookups a refresh * delay can be specified. This has the effect that the configuration file's * last modification date is only checked once in this delay period. The default * value for this refresh delay is 5 seconds.</p> * <p>This strategy only works with FileConfiguration instances.</p> * * @author Emmanuel Bourg * @version $Id: FileChangedReloadingStrategy.java 1210646 2011-12-05 21:25:01Z oheger $ * @since 1.1 */
public class FileChangedReloadingStrategy implements ReloadingStrategy {
Constant for the jar URL protocol.
/** Constant for the jar URL protocol.*/
private static final String JAR_PROTOCOL = "jar";
Constant for the default refresh delay.
/** Constant for the default refresh delay.*/
private static final int DEFAULT_REFRESH_DELAY = 5000;
Stores a reference to the configuration to be monitored.
/** Stores a reference to the configuration to be monitored.*/
protected FileConfiguration configuration;
The last time the configuration file was modified.
/** The last time the configuration file was modified. */
protected long lastModified;
The last time the file was checked for changes.
/** The last time the file was checked for changes. */
protected long lastChecked;
The minimum delay in milliseconds between checks.
/** The minimum delay in milliseconds between checks. */
protected long refreshDelay = DEFAULT_REFRESH_DELAY;
A flag whether a reload is required.
/** A flag whether a reload is required.*/
private boolean reloading;
The Log to use for diagnostic messages
/** The Log to use for diagnostic messages */
private Log logger = LogFactory.getLog(FileChangedReloadingStrategy.class); public void setConfiguration(FileConfiguration configuration) { this.configuration = configuration; } public void init() { updateLastModified(); } public boolean reloadingRequired() { if (!reloading) { long now = System.currentTimeMillis(); if (now > lastChecked + refreshDelay) { lastChecked = now; if (hasChanged()) { if (logger.isDebugEnabled()) { logger.debug("File change detected: " + getName()); } reloading = true; } } } return reloading; } public void reloadingPerformed() { updateLastModified(); }
Return the minimal time in milliseconds between two reloadings.
Returns:the refresh delay (in milliseconds)
/** * Return the minimal time in milliseconds between two reloadings. * * @return the refresh delay (in milliseconds) */
public long getRefreshDelay() { return refreshDelay; }
Set the minimal time between two reloadings.
Params:
  • refreshDelay – refresh delay in milliseconds
/** * Set the minimal time between two reloadings. * * @param refreshDelay refresh delay in milliseconds */
public void setRefreshDelay(long refreshDelay) { this.refreshDelay = refreshDelay; }
Update the last modified time.
/** * Update the last modified time. */
protected void updateLastModified() { File file = getFile(); if (file != null) { lastModified = file.lastModified(); } reloading = false; }
Check if the configuration has changed since the last time it was loaded.
Returns:a flag whether the configuration has changed
/** * Check if the configuration has changed since the last time it was loaded. * * @return a flag whether the configuration has changed */
protected boolean hasChanged() { File file = getFile(); if (file == null || !file.exists()) { if (logger.isWarnEnabled() && lastModified != 0) { logger.warn("File was deleted: " + getName(file)); lastModified = 0; } return false; } return file.lastModified() > lastModified; }
Returns the file that is monitored by this strategy. Note that the return value can be null under some circumstances.
Returns:the monitored file
/** * Returns the file that is monitored by this strategy. Note that the return * value can be <b>null </b> under some circumstances. * * @return the monitored file */
protected File getFile() { return (configuration.getURL() != null) ? fileFromURL(configuration .getURL()) : configuration.getFile(); }
Helper method for transforming a URL into a file object. This method handles file: and jar: URLs.
Params:
  • url – the URL to be converted
Returns:the resulting file or null
/** * Helper method for transforming a URL into a file object. This method * handles file: and jar: URLs. * * @param url the URL to be converted * @return the resulting file or <b>null </b> */
private File fileFromURL(URL url) { if (JAR_PROTOCOL.equals(url.getProtocol())) { String path = url.getPath(); try { return ConfigurationUtils.fileFromURL(new URL(path.substring(0, path.indexOf('!')))); } catch (MalformedURLException mex) { return null; } } else { return ConfigurationUtils.fileFromURL(url); } } private String getName() { return getName(getFile()); } private String getName(File file) { String name = configuration.getURL().toString(); if (name == null) { if (file != null) { name = file.getAbsolutePath(); } else { name = "base: " + configuration.getBasePath() + "file: " + configuration.getFileName(); } } return name; } }