net.dempsy.distconfig.apahcevfs.ApacheVfsPropertiesReader.java Source code

Java tutorial

Introduction

Here is the source code for net.dempsy.distconfig.apahcevfs.ApacheVfsPropertiesReader.java

Source

/*
 * Copyright 2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.dempsy.distconfig.apahcevfs;

import static net.dempsy.distconfig.apahcevfs.Utils.cleanPath;
import static net.dempsy.distconfig.apahcevfs.Utils.getLatest;
import static net.dempsy.distconfig.apahcevfs.Utils.getVersion;
import static net.dempsy.distconfig.apahcevfs.Utils.nextFile;
import static net.dempsy.util.Functional.mapChecked;

import java.io.IOException;
import java.util.function.Function;

import org.apache.commons.vfs2.FileChangeEvent;
import org.apache.commons.vfs2.FileListener;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.VFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.dempsy.distconfig.PropertiesReader;
import net.dempsy.distconfig.PropertiesWatcher;

public class ApacheVfsPropertiesReader implements PropertiesReader {
    private static Logger LOGGER = LoggerFactory.getLogger(ApacheVfsPropertiesReader.class);
    private final static Function<Exception, IOException> em = e -> IOException.class.isAssignableFrom(e.getClass())
            ? (IOException) e
            : new IOException(e);
    private final FileObject parentDirObj;

    public ApacheVfsPropertiesReader(final String parentUri, final String childPropertiesName) throws IOException {
        final FileObject baseDir = mapChecked(() -> VFS.getManager().resolveFile(parentUri), em);
        parentDirObj = mapChecked(() -> VFS.getManager().resolveFile(baseDir, cleanPath(childPropertiesName)), em);
    }

    public ApacheVfsPropertiesReader(final String pathUri) throws IOException {
        parentDirObj = mapChecked(() -> VFS.getManager().resolveFile(pathUri), em);
    }

    private static class Proxy implements FileListener {
        final FileObject beingWatched;
        final PropertiesWatcher watcher;

        Proxy(final FileObject beingWatched, final PropertiesWatcher watcher) {
            this.beingWatched = beingWatched;
            this.watcher = watcher;
        }

        @Override
        public void fileCreated(final FileChangeEvent event) throws Exception {
            doIt();
        }

        @Override
        public void fileDeleted(final FileChangeEvent event) throws Exception {
            doIt();
        }

        @Override
        public void fileChanged(final FileChangeEvent event) throws Exception {
            doIt();
        }

        void doIt() {
            beingWatched.getFileSystem().removeListener(beingWatched, this);
            try {
                watcher.propertiesChanged();
            } catch (final RuntimeException rte) {
                LOGGER.error("Failed processing notification that a properties file changed.", rte);
            }
        }
    }

    @Override
    public VersionedProperties read(final PropertiesWatcher watcher) throws IOException {
        final FileObject latest = getLatest(parentDirObj);
        final int ver = latest == null ? -1 : getVersion(latest);
        final VersionedProperties ret = new VersionedProperties(ver, Utils.read(latest));
        if (watcher != null) {
            // if there's a watcher ....
            final FileObject next = nextFile(latest, parentDirObj);
            final Proxy proxy = new Proxy(next, watcher);
            next.getFileSystem().addListener(next, proxy);

            // but now, if the file exists due to a race condition, lets at least address that.
            if (next.exists())
                proxy.doIt();
        }
        return ret;
    }

    @Override
    public boolean supportsNotification() {
        return true;
    }
}