io.spikex.core.util.NioDirWatcher.java Source code

Java tutorial

Introduction

Here is the source code for io.spikex.core.util.NioDirWatcher.java

Source

/**
 *
 * Copyright (c) 2015 NG Modular Oy.
 *
 * 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 io.spikex.core.util;

import com.google.common.eventbus.EventBus;
import com.sun.nio.file.SensitivityWatchEventModifier;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author cli
 */
public final class NioDirWatcher {

    private final EventBus m_eventBus; // Used for resource events
    private WatcherThread m_watcher;

    private static final AtomicInteger m_count = new AtomicInteger();

    private final Logger m_logger = LoggerFactory.getLogger(NioDirWatcher.class);

    public NioDirWatcher() {
        m_eventBus = new EventBus(NioDirWatcher.class.getSimpleName() + "-" + m_count.getAndIncrement());
    }

    public void watch(final Path dir, final Kind<Path>[] kinds) throws IOException {

        WatchService service = FileSystems.getDefault().newWatchService();
        // Rationale for SensitivityWatchEventModifier.HIGH: 
        // http://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-else
        dir.register(service, kinds, SensitivityWatchEventModifier.HIGH);

        m_logger.info("Watching directory: {}", dir);
        m_watcher = new WatcherThread(service, m_eventBus);
        m_watcher.start(); // Start watcher thread
    }

    public void close() {
        m_watcher.close();
    }

    public void register(final Object listener) {
        m_eventBus.register(listener);
    }

    public void unregister(final Object listener) {
        m_eventBus.unregister(listener);
    }

    private static final class WatcherThread extends Thread {

        private final WatchService m_service;
        private final EventBus m_eventBus;

        private final Logger m_logger = LoggerFactory.getLogger(WatcherThread.class);

        public WatcherThread(final WatchService service, final EventBus eventBus) {

            super("WatcherThread-" + m_count.getAndIncrement());
            m_service = service;
            m_eventBus = eventBus;
        }

        @Override
        public void run() {
            while (true) {

                WatchKey key;
                try {
                    key = m_service.take();
                } catch (InterruptedException e) {
                    m_logger.warn("Directory watcher interrupted", e);
                    break;
                }

                for (final WatchEvent<?> event : key.pollEvents()) {
                    Kind kind = event.kind();
                    if (kind != OVERFLOW) {
                        m_eventBus.post(event);
                    } else {
                        m_logger.trace("Overflow");
                    }
                }

                // Reset key and stop watching if dir removed (or other problem)
                if (!key.reset()) {
                    break;
                }
            }
            m_logger.debug("Directory watcher stopped");
        }

        public void close() {
            try {
                m_service.close();
            } catch (IOException e) {
                m_logger.error("Failed to close directory watch service", e);
            }
        }
    }
}