View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.configuration2.reloading;
19  
20  import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
21  import org.apache.commons.configuration2.io.FileHandler;
22  import org.apache.commons.configuration2.io.FileSystem;
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.commons.vfs2.FileObject;
26  import org.apache.commons.vfs2.FileSystemException;
27  import org.apache.commons.vfs2.FileSystemManager;
28  import org.apache.commons.vfs2.VFS;
29  
30  /**
31   * <p>
32   * A file-based reloading strategy that uses <a href="https://commons.apache.org/vfs/">Commons VFS</a> to determine when
33   * a file was changed.
34   * </p>
35   * <p>
36   * This reloading strategy is very similar to {@link FileHandlerReloadingDetector}, except for the fact that it uses VFS
37   * and thus can deal with a variety of different configuration sources.
38   * </p>
39   * <p>
40   * This strategy only works with FileConfiguration instances.
41   * </p>
42   *
43   * @since 1.7
44   */
45  public class VFSFileHandlerReloadingDetector extends FileHandlerReloadingDetector {
46  
47      /** Stores the logger. */
48      private final Log log = LogFactory.getLog(getClass());
49  
50      /**
51       * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and initializes it with an empty
52       * {@code FileHandler} object.
53       */
54      public VFSFileHandlerReloadingDetector() {
55      }
56  
57      /**
58       * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and initializes it with the given
59       * {@code FileHandler} object.
60       *
61       * @param handler the {@code FileHandler}
62       */
63      public VFSFileHandlerReloadingDetector(final FileHandler handler) {
64          super(handler);
65      }
66  
67      /**
68       * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and initializes it with the given
69       * {@code FileHandler} object and the given refresh delay.
70       *
71       * @param handler the {@code FileHandler}
72       * @param refreshDelay the refresh delay
73       */
74      public VFSFileHandlerReloadingDetector(final FileHandler handler, final long refreshDelay) {
75          super(handler, refreshDelay);
76      }
77  
78      /**
79       * Gets the file that is monitored by this strategy. Note that the return value can be <strong>null </strong> under some
80       * circumstances.
81       *
82       * @return the monitored file
83       */
84      protected FileObject getFileObject() {
85          if (!getFileHandler().isLocationDefined()) {
86              return null;
87          }
88  
89          try {
90              final FileSystemManager fsManager = VFS.getManager();
91              final String uri = resolveFileURI();
92              if (uri == null) {
93                  throw new ConfigurationRuntimeException("Unable to determine file to monitor");
94              }
95              return fsManager.resolveFile(uri);
96          } catch (final FileSystemException e) {
97              final String msg = "Unable to monitor " + getFileHandler().getURL().toString();
98              log.error(msg);
99              throw new ConfigurationRuntimeException(msg, e);
100         }
101     }
102 
103     /**
104      * {@inheritDoc} This implementation uses Commons VFS to obtain a {@code FileObject} and read the date of the last
105      * modification.
106      */
107     @Override
108     protected long getLastModificationDate() {
109         final FileObject file = getFileObject();
110         try {
111             if (file == null || !file.exists()) {
112                 return 0;
113             }
114 
115             return file.getContent().getLastModifiedTime();
116         } catch (final FileSystemException ex) {
117             log.error("Unable to get last modified time for" + file.getName().getURI(), ex);
118             return 0;
119         }
120     }
121 
122     /**
123      * Resolves the URI of the monitored file.
124      *
125      * @return the URI of the monitored file or <strong>null</strong> if it cannot be resolved
126      */
127     protected String resolveFileURI() {
128         final FileSystem fs = getFileHandler().getFileSystem();
129         return fs.getPath(null, getFileHandler().getURL(), getFileHandler().getBasePath(), getFileHandler().getFileName());
130     }
131 }