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.configuration2.reloading;
019
020import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
021import org.apache.commons.configuration2.io.FileHandler;
022import org.apache.commons.configuration2.io.FileSystem;
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.apache.commons.vfs2.FileObject;
026import org.apache.commons.vfs2.FileSystemException;
027import org.apache.commons.vfs2.FileSystemManager;
028import org.apache.commons.vfs2.VFS;
029
030/**
031 * <p>
032 * A file-based reloading strategy that uses <a
033 * href="http://commons.apache.org/vfs/">Commons VFS</a> to determine when a
034 * file was changed.
035 * </p>
036 * <p>
037 * This reloading strategy is very similar to
038 * {@link FileHandlerReloadingDetector}, except for the fact that it uses VFS
039 * and thus can deal with a variety of different configuration sources.
040 * </p>
041 * <p>
042 * This strategy only works with FileConfiguration instances.
043 * </p>
044 *
045 * @author <a
046 *         href="http://commons.apache.org/configuration/team-list.html">Commons
047 *         Configuration team</a>
048 * @version $Id: VFSFileHandlerReloadingDetector.java 1624601 2014-09-12 18:04:36Z oheger $
049 * @since 1.7
050 */
051public class VFSFileHandlerReloadingDetector extends FileHandlerReloadingDetector
052{
053    /** Stores the logger.*/
054    private final Log log = LogFactory.getLog(getClass());
055
056    /**
057     * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and
058     * initializes it with an empty {@code FileHandler} object.
059     */
060    public VFSFileHandlerReloadingDetector()
061    {
062        super();
063    }
064
065    /**
066     * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and
067     * initializes it with the given {@code FileHandler} object and the given
068     * refresh delay.
069     *
070     * @param handler the {@code FileHandler}
071     * @param refreshDelay the refresh delay
072     */
073    public VFSFileHandlerReloadingDetector(FileHandler handler,
074            long refreshDelay)
075    {
076        super(handler, refreshDelay);
077    }
078
079    /**
080     * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and
081     * initializes it with the given {@code FileHandler} object.
082     *
083     * @param handler the {@code FileHandler}
084     */
085    public VFSFileHandlerReloadingDetector(FileHandler handler)
086    {
087        super(handler);
088    }
089
090    /**
091     * {@inheritDoc} This implementation uses Commons VFS to obtain a
092     * {@code FileObject} and read the date of the last modification.
093     */
094    @Override
095    protected long getLastModificationDate()
096    {
097        FileObject file = getFileObject();
098        try
099        {
100            if (file == null || !file.exists())
101            {
102                return 0;
103            }
104
105            return file.getContent().getLastModifiedTime();
106        }
107        catch (FileSystemException ex)
108        {
109            log.error("Unable to get last modified time for"
110                    + file.getName().getURI(), ex);
111            return 0;
112        }
113    }
114
115    /**
116     * Returns the file that is monitored by this strategy. Note that the return
117     * value can be <b>null </b> under some circumstances.
118     *
119     * @return the monitored file
120     */
121    protected FileObject getFileObject()
122    {
123        if (!getFileHandler().isLocationDefined())
124        {
125            return null;
126        }
127
128        try
129        {
130            FileSystemManager fsManager = VFS.getManager();
131            String uri = resolveFileURI();
132            if (uri == null)
133            {
134                throw new ConfigurationRuntimeException("Unable to determine file to monitor");
135            }
136            return fsManager.resolveFile(uri);
137        }
138        catch (FileSystemException fse)
139        {
140            String msg = "Unable to monitor " + getFileHandler().getURL().toString();
141            log.error(msg);
142            throw new ConfigurationRuntimeException(msg, fse);
143        }
144    }
145
146    /**
147     * Resolves the URI of the monitored file.
148     *
149     * @return the URI of the monitored file or <b>null</b> if it cannot be
150     *         resolved
151     */
152    protected String resolveFileURI()
153    {
154        FileSystem fs = getFileHandler().getFileSystem();
155        String uri =
156                fs.getPath(null, getFileHandler().getURL(), getFileHandler()
157                        .getBasePath(), getFileHandler().getFileName());
158        return uri;
159    }
160}