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

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.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_MILLIS = 5000; /** * 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); } /** The associated file handler. */ private final FileHandler fileHandler; /** The refresh delay. */ private final long refreshDelayMillis; /** The last time the configuration file was modified. */ private long lastModifiedMillis; /** The last time the file was checked for changes. */ private long lastCheckedMillis; /** * 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); } /** * 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_MILLIS); } /** * 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 refreshDelayMillis the refresh delay; a value of 0 means that a check is performed in all cases */ public FileHandlerReloadingDetector(final FileHandler handler, final long refreshDelayMillis) { fileHandler = handler != null ? handler : new FileHandler(); this.refreshDelayMillis = refreshDelayMillis; } /** * Gets 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; } /** * Gets 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(); } /** * Gets 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; } /** * Gets 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 in milliseconds. */ protected long getLastModificationDate() { final File file = getExistingFile(); return file != null ? file.lastModified() : 0; } /** * Gets 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 refreshDelayMillis; } /** * {@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 nowMillis = System.currentTimeMillis(); if (nowMillis >= lastCheckedMillis + getRefreshDelay()) { lastCheckedMillis = nowMillis; final long modifiedMillis = getLastModificationDate(); if (modifiedMillis > 0) { if (lastModifiedMillis != 0) { return modifiedMillis != lastModifiedMillis; } // initialization updateLastModified(modifiedMillis); } } return false; } /** * 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()); } /** * {@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()); } /** * 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 timeMillis the new last modification date */ protected void updateLastModified(final long timeMillis) { lastModifiedMillis = timeMillis; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy