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="https://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 * @since 1.7
046 */
047public class VFSFileHandlerReloadingDetector extends FileHandlerReloadingDetector
048{
049    /** Stores the logger.*/
050    private final Log log = LogFactory.getLog(getClass());
051
052    /**
053     * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and
054     * initializes it with an empty {@code FileHandler} object.
055     */
056    public VFSFileHandlerReloadingDetector()
057    {
058        super();
059    }
060
061    /**
062     * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and
063     * initializes it with the given {@code FileHandler} object and the given
064     * refresh delay.
065     *
066     * @param handler the {@code FileHandler}
067     * @param refreshDelay the refresh delay
068     */
069    public VFSFileHandlerReloadingDetector(final FileHandler handler,
070            final long refreshDelay)
071    {
072        super(handler, refreshDelay);
073    }
074
075    /**
076     * Creates a new instance of {@code VFSFileHandlerReloadingDetector} and
077     * initializes it with the given {@code FileHandler} object.
078     *
079     * @param handler the {@code FileHandler}
080     */
081    public VFSFileHandlerReloadingDetector(final FileHandler handler)
082    {
083        super(handler);
084    }
085
086    /**
087     * {@inheritDoc} This implementation uses Commons VFS to obtain a
088     * {@code FileObject} and read the date of the last modification.
089     */
090    @Override
091    protected long getLastModificationDate()
092    {
093        final FileObject file = getFileObject();
094        try
095        {
096            if (file == null || !file.exists())
097            {
098                return 0;
099            }
100
101            return file.getContent().getLastModifiedTime();
102        }
103        catch (final FileSystemException ex)
104        {
105            log.error("Unable to get last modified time for"
106                    + file.getName().getURI(), ex);
107            return 0;
108        }
109    }
110
111    /**
112     * Returns the file that is monitored by this strategy. Note that the return
113     * value can be <b>null </b> under some circumstances.
114     *
115     * @return the monitored file
116     */
117    protected FileObject getFileObject()
118    {
119        if (!getFileHandler().isLocationDefined())
120        {
121            return null;
122        }
123
124        try
125        {
126            final FileSystemManager fsManager = VFS.getManager();
127            final String uri = resolveFileURI();
128            if (uri == null)
129            {
130                throw new ConfigurationRuntimeException("Unable to determine file to monitor");
131            }
132            return fsManager.resolveFile(uri);
133        }
134        catch (final FileSystemException fse)
135        {
136            final String msg = "Unable to monitor " + getFileHandler().getURL().toString();
137            log.error(msg);
138            throw new ConfigurationRuntimeException(msg, fse);
139        }
140    }
141
142    /**
143     * Resolves the URI of the monitored file.
144     *
145     * @return the URI of the monitored file or <b>null</b> if it cannot be
146     *         resolved
147     */
148    protected String resolveFileURI()
149    {
150        final FileSystem fs = getFileHandler().getFileSystem();
151        final String uri =
152                fs.getPath(null, getFileHandler().getURL(), getFileHandler()
153                        .getBasePath(), getFileHandler().getFileName());
154        return uri;
155    }
156}