001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.configuration.reloading;
019
020 import java.io.File;
021 import java.net.MalformedURLException;
022 import java.net.URL;
023
024 import org.apache.commons.configuration.ConfigurationUtils;
025 import org.apache.commons.configuration.FileConfiguration;
026
027 /**
028 * <p>A reloading strategy that will reload the configuration every time its
029 * underlying file is changed.</p>
030 * <p>This reloading strategy does not actively monitor a configuration file,
031 * but is triggered by its associated configuration whenever properties are
032 * accessed. It then checks the configuration file's last modification date
033 * and causes a reload if this has changed.</p>
034 * <p>To avoid permanent disc access on successive property lookups a refresh
035 * delay can be specified. This has the effect that the configuration file's
036 * last modification date is only checked once in this delay period. The default
037 * value for this refresh delay is 5 seconds.</p>
038 * <p>This strategy only works with FileConfiguration instances.</p>
039 *
040 * @author Emmanuel Bourg
041 * @version $Revision: 606798 $, $Date: 2007-12-25 20:05:58 +0100 (Di, 25 Dez 2007) $
042 * @since 1.1
043 */
044 public class FileChangedReloadingStrategy implements ReloadingStrategy
045 {
046 /** Constant for the jar URL protocol.*/
047 private static final String JAR_PROTOCOL = "jar";
048
049 /** Constant for the default refresh delay.*/
050 private static final int DEFAULT_REFRESH_DELAY = 5000;
051
052 /** Stores a reference to the configuration to be monitored.*/
053 protected FileConfiguration configuration;
054
055 /** The last time the configuration file was modified. */
056 protected long lastModified;
057
058 /** The last time the file was checked for changes. */
059 protected long lastChecked;
060
061 /** The minimum delay in milliseconds between checks. */
062 protected long refreshDelay = DEFAULT_REFRESH_DELAY;
063
064 /** A flag whether a reload is required.*/
065 private boolean reloading;
066
067 public void setConfiguration(FileConfiguration configuration)
068 {
069 this.configuration = configuration;
070 }
071
072 public void init()
073 {
074 updateLastModified();
075 }
076
077 public boolean reloadingRequired()
078 {
079 if (!reloading)
080 {
081 long now = System.currentTimeMillis();
082
083 if (now > lastChecked + refreshDelay)
084 {
085 lastChecked = now;
086 if (hasChanged())
087 {
088 reloading = true;
089 }
090 }
091 }
092
093 return reloading;
094 }
095
096 public void reloadingPerformed()
097 {
098 updateLastModified();
099 }
100
101 /**
102 * Return the minimal time in milliseconds between two reloadings.
103 *
104 * @return the refresh delay (in milliseconds)
105 */
106 public long getRefreshDelay()
107 {
108 return refreshDelay;
109 }
110
111 /**
112 * Set the minimal time between two reloadings.
113 *
114 * @param refreshDelay refresh delay in milliseconds
115 */
116 public void setRefreshDelay(long refreshDelay)
117 {
118 this.refreshDelay = refreshDelay;
119 }
120
121 /**
122 * Update the last modified time.
123 */
124 protected void updateLastModified()
125 {
126 File file = getFile();
127 if (file != null)
128 {
129 lastModified = file.lastModified();
130 }
131 reloading = false;
132 }
133
134 /**
135 * Check if the configuration has changed since the last time it was loaded.
136 *
137 * @return a flag whether the configuration has changed
138 */
139 protected boolean hasChanged()
140 {
141 File file = getFile();
142 if (file == null || !file.exists())
143 {
144 return false;
145 }
146
147 return file.lastModified() > lastModified;
148 }
149
150 /**
151 * Returns the file that is monitored by this strategy. Note that the return
152 * value can be <b>null </b> under some circumstances.
153 *
154 * @return the monitored file
155 */
156 protected File getFile()
157 {
158 return (configuration.getURL() != null) ? fileFromURL(configuration
159 .getURL()) : configuration.getFile();
160 }
161
162 /**
163 * Helper method for transforming a URL into a file object. This method
164 * handles file: and jar: URLs.
165 *
166 * @param url the URL to be converted
167 * @return the resulting file or <b>null </b>
168 */
169 private File fileFromURL(URL url)
170 {
171 if (JAR_PROTOCOL.equals(url.getProtocol()))
172 {
173 String path = url.getPath();
174 try
175 {
176 return ConfigurationUtils.fileFromURL(new URL(path.substring(0,
177 path.indexOf('!'))));
178 }
179 catch (MalformedURLException mex)
180 {
181 return null;
182 }
183 }
184 else
185 {
186 return ConfigurationUtils.fileFromURL(url);
187 }
188 }
189 }