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

org.apache.commons.configuration2.reloading.FileHandlerReloadingDetector Maven / Gradle / Ivy

Go to download

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

There is a newer version: 2.10.1
Show 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.reloading;

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

import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.configuration2.io.FileLocatorUtils;

/**
 * 

* A specialized implementation of {@code ReloadingDetector} which monitors a * file specified by a {@link FileHandler}. *

*

* An instance of this class is passed a {@code FileHandler} at construction * time. Each time the {@code isReloadingRequired()} method is called, it checks * whether the {@code FileHandler} points to a valid location. If this is the * case, the file's last modification time is obtained and compared with the * last stored time. If it has changed, a reload operation should be performed. *

*

* Because file I/O may be expensive it is possible to configure a refresh delay * as a time in milliseconds. This is the minimum interval between two checks. * If the {@code isReloadingRequired()} method is called in shorter intervals, * it does not perform a check, but directly returns false. *

*

* To initialize an instance either {@code isReloadingRequired()} or * {@code reloadingPerformed()} can be called. The first call of * {@code isReloadingRequired} does not perform a check, but obtains the initial * modification date of the monitored file. {@code reloadingPerformed()} always * obtains the file's modification date and stores it internally. *

* * @since 2.0 */ public class FileHandlerReloadingDetector implements ReloadingDetector { /** Constant for the jar URL protocol. */ private static final String JAR_PROTOCOL = "jar"; /** Constant for the default refresh delay. */ private static final int DEFAULT_REFRESH_DELAY = 5000; /** The associated file handler. */ private final FileHandler fileHandler; /** The refresh delay. */ private final long refreshDelay; /** The last time the configuration file was modified. */ private long lastModified; /** The last time the file was checked for changes. */ private long lastChecked; /** * Creates a new instance of {@code FileHandlerReloadingDetector} and * initializes it with the {@code FileHandler} to monitor and the refresh * delay. The handler is directly used, no copy is created. So it is * possible to change the location monitored by manipulating the * {@code FileHandler} object. * * @param handler the {@code FileHandler} associated with this detector (can * be null) * @param refreshDelay the refresh delay; a value of 0 means that a check is * performed in all cases */ public FileHandlerReloadingDetector(final FileHandler handler, final long refreshDelay) { fileHandler = handler != null ? handler : new FileHandler(); this.refreshDelay = refreshDelay; } /** * Creates a new instance of {@code FileHandlerReloadingDetector} and * initializes it with the {@code FileHandler} to monitor and a default * refresh delay. * * @param handler the {@code FileHandler} associated with this detector (can * be null) */ public FileHandlerReloadingDetector(final FileHandler handler) { this(handler, DEFAULT_REFRESH_DELAY); } /** * Creates a new instance of {@code FileHandlerReloadingDetector} with an * uninitialized {@code FileHandler} object. The file to be monitored has to * be set later by manipulating the handler object returned by * {@code getFileHandler()}. */ public FileHandlerReloadingDetector() { this(null); } /** * Returns the {@code FileHandler} associated with this object. The * underlying handler is directly returned, so changing its location also * changes the file monitored by this detector. * * @return the associated {@code FileHandler} */ public FileHandler getFileHandler() { return fileHandler; } /** * Returns the refresh delay. This is a time in milliseconds. The * {@code isReloadingRequired()} method first checks whether the time since * the previous check is more than this value in the past. Otherwise, no * check is performed. This is a means to limit file I/O caused by this * class. * * @return the refresh delay used by this object */ public long getRefreshDelay() { return refreshDelay; } /** * {@inheritDoc} This implementation checks whether the associated * {@link FileHandler} points to a valid file and whether the last * modification time of this time has changed since the last check. The * refresh delay is taken into account, too; a check is only performed if at * least this time has passed since the last check. */ @Override public boolean isReloadingRequired() { final long now = System.currentTimeMillis(); if (now >= lastChecked + getRefreshDelay()) { lastChecked = now; final long modified = getLastModificationDate(); if (modified > 0) { if (lastModified == 0) { // initialization updateLastModified(modified); } else { if (modified != lastModified) { return true; } } } } return false; } /** * {@inheritDoc} This implementation updates the internally stored last * modification date with the current modification date of the monitored * file. So the next change is detected when this file is changed again. */ @Override public void reloadingPerformed() { updateLastModified(getLastModificationDate()); } /** * Tells this implementation that the internally stored state should be * refreshed. This method is intended to be called after the creation * of an instance. */ public void refresh() { updateLastModified(getLastModificationDate()); } /** * Returns the date of the last modification of the monitored file. A return * value of 0 indicates, that the monitored file does not exist. * * @return the last modification date */ protected long getLastModificationDate() { final File file = getExistingFile(); return file != null ? file.lastModified() : 0; } /** * Updates the last modification date of the monitored file. The need for a * reload is detected only if the file's modification date is different from * this value. * * @param time the new last modification date */ protected void updateLastModified(final long time) { lastModified = time; } /** * Returns the {@code File} object which is monitored by this object. This * method is called every time the file's last modification time is needed. * If it returns null, no check is performed. This base * implementation obtains the {@code File} from the associated * {@code FileHandler}. It can also deal with URLs to jar files. * * @return the {@code File} to be monitored (can be null) */ protected File getFile() { final URL url = getFileHandler().getURL(); return url != null ? fileFromURL(url) : getFileHandler().getFile(); } /** * Returns the monitored {@code File} or null if it does not exist. * * @return the monitored {@code File} or null */ private File getExistingFile() { File file = getFile(); if (file != null && !file.exists()) { file = null; } return file; } /** * 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 null */ private static File fileFromURL(final URL url) { if (JAR_PROTOCOL.equals(url.getProtocol())) { final String path = url.getPath(); try { return FileLocatorUtils.fileFromURL(new URL(path.substring(0, path.indexOf('!')))); } catch (final MalformedURLException mex) { return null; } } return FileLocatorUtils.fileFromURL(url); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy