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 018package org.apache.commons.configuration.reloading; 019 020import org.apache.commons.configuration.ConfigurationRuntimeException; 021import org.apache.commons.configuration.FileConfiguration; 022import org.apache.commons.configuration.FileSystem; 023import org.apache.commons.configuration.FileSystemBased; 024import org.apache.commons.logging.Log; 025import org.apache.commons.logging.LogFactory; 026import org.apache.commons.vfs2.FileObject; 027import org.apache.commons.vfs2.FileSystemException; 028import org.apache.commons.vfs2.FileSystemManager; 029import 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 */ 052public 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}