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      /** Stores the logger. */
47      private final Log log = LogFactory.getLog(getClass());
48  
49      /**
50       * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and initializes it with an empty
51       * {@code FileHandler} object.
52       */
53      public VFSFileHandlerReloadingDetector() {
54      }
55  
56      /**
57       * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and initializes it with the given
58       * {@code FileHandler} object.
59       *
60       * @param handler the {@code FileHandler}
61       */
62      public VFSFileHandlerReloadingDetector(final FileHandler handler) {
63          super(handler);
64      }
65  
66      /**
67       * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and initializes it with the given
68       * {@code FileHandler} object and the given refresh delay.
69       *
70       * @param handler the {@code FileHandler}
71       * @param refreshDelay the refresh delay
72       */
73      public VFSFileHandlerReloadingDetector(final FileHandler handler, final long refreshDelay) {
74          super(handler, refreshDelay);
75      }
76  
77      /**
78       * Gets the file that is monitored by this strategy. Note that the return value can be <strong>null </strong> under some
79       * circumstances.
80       *
81       * @return the monitored file
82       */
83      protected FileObject getFileObject() {
84          if (!getFileHandler().isLocationDefined()) {
85              return null;
86          }
87  
88          try {
89              final FileSystemManager fsManager = VFS.getManager();
90              final String uri = resolveFileURI();
91              if (uri == null) {
92                  throw new ConfigurationRuntimeException("Unable to determine file to monitor");
93              }
94              return fsManager.resolveFile(uri);
95          } catch (final FileSystemException fse) {
96              final String msg = "Unable to monitor " + getFileHandler().getURL().toString();
97              log.error(msg);
98              throw new ConfigurationRuntimeException(msg, fse);
99          }
100     }
101 
102     /**
103      * {@inheritDoc} This implementation uses Commons VFS to obtain a {@code FileObject} and read the date of the last
104      * modification.
105      */
106     @Override
107     protected long getLastModificationDate() {
108         final FileObject file = getFileObject();
109         try {
110             if (file == null || !file.exists()) {
111                 return 0;
112             }
113 
114             return file.getContent().getLastModifiedTime();
115         } catch (final FileSystemException ex) {
116             log.error("Unable to get last modified time for" + file.getName().getURI(), ex);
117             return 0;
118         }
119     }
120 
121     /**
122      * Resolves the URI of the monitored file.
123      *
124      * @return the URI of the monitored file or <strong>null</strong> if it cannot be resolved
125      */
126     protected String resolveFileURI() {
127         final FileSystem fs = getFileHandler().getFileSystem();
128         return fs.getPath(null, getFileHandler().getURL(), getFileHandler().getBasePath(), getFileHandler().getFileName());
129     }
130 }