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 org.apache.commons.configuration.ConfigurationRuntimeException;
021 import org.apache.commons.configuration.FileConfiguration;
022 import org.apache.commons.configuration.FileSystem;
023 import org.apache.commons.configuration.FileSystemBased;
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026 import org.apache.commons.vfs2.FileObject;
027 import org.apache.commons.vfs2.FileSystemException;
028 import org.apache.commons.vfs2.FileSystemManager;
029 import org.apache.commons.vfs2.VFS;
030
031 /**
032 * <p>
033 * A file-based reloading strategy that uses <a
034 * href="http://commons.apache.org/vfs/">Commons VFS</a> to determine when a
035 * file was changed.
036 * </p>
037 * <p>
038 * This reloading strategy is very similar to
039 * {@link FileChangedReloadingStrategy}, except for the fact that it uses VFS
040 * and thus can deal with a variety of different configuration sources.
041 * </p>
042 * <p>
043 * This strategy only works with FileConfiguration instances.
044 * </p>
045 *
046 * @author <a
047 * href="http://commons.apache.org/configuration/team-list.html">Commons
048 * Configuration team</a>
049 * @version $Id: VFSFileChangedReloadingStrategy.java 1162383 2011-08-27 15:57:11Z oheger $
050 * @since 1.7
051 */
052 public class VFSFileChangedReloadingStrategy implements ReloadingStrategy
053 {
054 /** Constant for the default refresh delay.*/
055 private static final int DEFAULT_REFRESH_DELAY = 5000;
056
057 /** Stores a reference to the configuration to be monitored.*/
058 protected FileConfiguration configuration;
059
060 /** The last time the configuration file was modified. */
061 protected long lastModified;
062
063 /** The last time the file was checked for changes. */
064 protected long lastChecked;
065
066 /** The minimum delay in milliseconds between checks. */
067 protected long refreshDelay = DEFAULT_REFRESH_DELAY;
068
069 /** A flag whether a reload is required.*/
070 private boolean reloading;
071
072 /** Stores the logger.*/
073 private Log log = LogFactory.getLog(getClass());
074
075 public void setConfiguration(FileConfiguration configuration)
076 {
077 this.configuration = configuration;
078 }
079
080 public void init()
081 {
082 if (configuration.getURL() == null && configuration.getFileName() == null)
083 {
084 return;
085 }
086 if (this.configuration == null)
087 {
088 throw new IllegalStateException("No configuration has been set for this strategy");
089 }
090 updateLastModified();
091 }
092
093 public boolean reloadingRequired()
094 {
095 if (!reloading)
096 {
097 long now = System.currentTimeMillis();
098
099 if (now > lastChecked + refreshDelay)
100 {
101 lastChecked = now;
102 if (hasChanged())
103 {
104 reloading = true;
105 }
106 }
107 }
108
109 return reloading;
110 }
111
112 public void reloadingPerformed()
113 {
114 updateLastModified();
115 }
116
117 /**
118 * Return the minimal time in milliseconds between two reloadings.
119 *
120 * @return the refresh delay (in milliseconds)
121 */
122 public long getRefreshDelay()
123 {
124 return refreshDelay;
125 }
126
127 /**
128 * Set the minimal time between two reloadings.
129 *
130 * @param refreshDelay refresh delay in milliseconds
131 */
132 public void setRefreshDelay(long refreshDelay)
133 {
134 this.refreshDelay = refreshDelay;
135 }
136
137 /**
138 * Update the last modified time.
139 */
140 protected void updateLastModified()
141 {
142 FileObject file = getFile();
143 if (file != null)
144 {
145 try
146 {
147 lastModified = file.getContent().getLastModifiedTime();
148 }
149 catch (FileSystemException fse)
150 {
151 log.error("Unable to get last modified time for" + file.getName().getURI());
152 }
153 }
154 reloading = false;
155 }
156
157 /**
158 * Check if the configuration has changed since the last time it was loaded.
159 *
160 * @return a flag whether the configuration has changed
161 */
162 protected boolean hasChanged()
163 {
164 FileObject file = getFile();
165 try
166 {
167 if (file == null || !file.exists())
168 {
169 return false;
170 }
171
172 return file.getContent().getLastModifiedTime() > lastModified;
173 }
174 catch (FileSystemException ex)
175 {
176 log.error("Unable to get last modified time for" + file.getName().getURI());
177 return false;
178 }
179 }
180
181 /**
182 * Returns the file that is monitored by this strategy. Note that the return
183 * value can be <b>null </b> under some circumstances.
184 *
185 * @return the monitored file
186 */
187 protected FileObject getFile()
188 {
189 try
190 {
191 FileSystemManager fsManager = VFS.getManager();
192 FileSystem fs = ((FileSystemBased) configuration).getFileSystem();
193 String uri = fs.getPath(null, configuration.getURL(), configuration.getBasePath(),
194 configuration.getFileName());
195 if (uri == null)
196 {
197 throw new ConfigurationRuntimeException("Unable to determine file to monitor");
198 }
199 return fsManager.resolveFile(uri);
200 }
201 catch (FileSystemException fse)
202 {
203 String msg = "Unable to monitor " + configuration.getURL().toString();
204 log.error(msg);
205 throw new ConfigurationRuntimeException(msg, fse);
206 }
207 }
208 }