CPD Results

The following document contains the results of PMD's CPD 4.3.

Duplications

FileProjectLine
com\github\sworisbreathing\sfmf4j\jpathwatch\WatchServiceFileMonitorServiceImpl.javaSFMF4J :: JPathWatch71
com\github\sworisbreathing\sfmf4j\nio2\WatchServiceFileMonitorServiceImpl.javaSFMF4J :: NIO271
    private static final Kind[] interested_types = new Kind[]{StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_DELETE, StandardWatchEventKind.ENTRY_MODIFY};

    /**
     * The executor service which runs the task of polling the watch service.
     */
    private ExecutorService executorService;

    /**
     * Flag to indicate that the watch service should be stopped during
     * shutdown.
     */
    private volatile boolean closeWatchServiceOnShutdown = false;

    /**
     * Flag to indiate that the executor service should be stopped during
     * shutdown.
     */
    private volatile boolean shutdownExecutorServiceOnShutdown = false;


    /**
     * Package-protected getter (for automated testing).
     *
     * @return
     */
    ExecutorService getExecutorService() {
        return executorService;
    }

    /**
     * Package-protected getter (for automated testing).
     *
     * @return
     */
    WatchService getWatchService() {
        return watchService;
    }

    /**
     * The registered watch keys for each path.
     */
    private final ConcurrentMap<String, WatchKey> watchKeysByPath;

    /**
     * The registered paths for each watch key.
     */
    private final ConcurrentMap<WatchKey, String> pathsByWatchKey;

    /**
     * The listeners for each watch key.
     */
    private final ConcurrentMap<WatchKey, Collection<SFMF4JWatchListener>> listenersByWatchKey;

    /**
     * Creates a new WatchServiceFileMonitorServiceImpl.
     * @param watchService the watch service to use.  When this argument is
     * {@code null}, the watch service will be created during {@link
     * #initialize()} and stopped during {@link #shutdown()}.  If this argument
     * is not {@code null}, then it is assumed that the watch service is running
     * and will be closed elsewhere (for example, an IoC container)
     * @param executorService the executor service to use.  When this argument
     * is {@code null}, the executor service will be created during {@link
     * #initialize()} and stopped during {@link #shutdown()}.  If this argument
     * is not {@code null}, then it is assumed that the executor service is
     * running and will be closed elsewhere (for example, in an IoC container)
     */
    public WatchServiceFileMonitorServiceImpl(final WatchService watchService, final ExecutorService executorService) {
        this.watchService = watchService;
        this.executorService = executorService;
        this.watchKeysByPath = new ConcurrentHashMap<String, WatchKey>();
        this.pathsByWatchKey = new ConcurrentHashMap<WatchKey, String>();
        this.listenersByWatchKey = new ConcurrentHashMap<WatchKey, Collection<SFMF4JWatchListener>>();
    }

    /**
     * Gets the watch key for a path with lazy initialization.
     * @param path the path
     * @return a registered watch key for the path
     * @throws IOException if lazy initialization fails
     */
    private synchronized WatchKey getWatchKeyForPath(final String path) throws IOException {
        WatchKey key = watchKeysByPath.get(path);
        if (key == null) {
            logger.debug("Lazy-instantiating watch key for path: {}", path);
            key = Paths.get(path).register(watchService, interested_types);
            watchKeysByPath.put(path, key);
            pathsByWatchKey.put(key, path);
            listenersByWatchKey.put(key, Collections.newSetFromMap(new ConcurrentHashMap<SFMF4JWatchListener, Boolean>()));
        }
        return key;
    }

    @Override
    public void registerDirectoryListener(File directory, DirectoryListener directoryListener) {
        String path = directory.getAbsolutePath();
        try {
            synchronized (this) {
                WatchKey key = getWatchKeyForPath(path);
                SFMF4JWatchListener listener = new SFMF4JWatchListener(directoryListener);
                listenersByWatchKey.get(key).add(listener);
            }
        } catch (IOException ex) {
            logger.error(ex.getMessage(), ex);
        }
    }

    @Override
    public void unregisterDirectoryListener(File directory, DirectoryListener directoryListener) {
        String path = directory.getAbsolutePath();
        synchronized (this) {
            final WatchKey key = watchKeysByPath.get(path);
            if (key != null) {
                Collection<SFMF4JWatchListener> listeners = listenersByWatchKey.get(key);
                listeners.remove(new SFMF4JWatchListener(directoryListener)); // note the equals implementation
                if (listeners.isEmpty()) {
                    //no longer listening on that path.
                    cleanup(key);
                } else {
                    logger.debug("somebody is still listening: {}", path);
                }
            }
        }
    }

    /**
     * Resolves a watch event with its absolute path.
     * @param key the watch key (used to look up the parent path)
     * @param event the event to resolve
     * @return a copy of the event, with a resolved path
     */
    private synchronized WatchEvent<Path> resolveEventWithCorrectPath(final WatchKey key, final WatchEvent<Path> event) {
        Path correctPath = Paths.get(pathsByWatchKey.get(key));
        return new ResolvedPathWatchEvent(event, correctPath);
    }

    /**
     * Properly unregisters and removes a watch key.
     * @param key the watch key
     */
    @SuppressWarnings("PMD.EmptyCatchBlock")
    private synchronized void cleanup(final WatchKey key) {
        logger.trace("cleanUp {}", key);
        try {
            key.cancel();
        }catch(Exception ex) {
            //trap
        }
        Collection<SFMF4JWatchListener> listeners = listenersByWatchKey.remove(key);
        if (listeners != null && !listeners.isEmpty()) {
            logger.warn("Cleaning up key but listeners are still registered.");
        }
        String path = pathsByWatchKey.remove(key);
        if (path != null) {
            watchKeysByPath.remove(path);
        }
    }

    @Override
    public synchronized void initialize() {
        if (watchService==null) {
            logger.warn("No watch service was explicitly set.  Setting one now.");
            closeWatchServiceOnShutdown = true;
FileProjectLine
com\github\sworisbreathing\sfmf4j\jpathwatch\WatchServiceFileMonitorServiceImpl.javaSFMF4J :: JPathWatch242
com\github\sworisbreathing\sfmf4j\nio2\WatchServiceFileMonitorServiceImpl.javaSFMF4J :: NIO2246
                    return new Thread(r, "jpathwatchFileMonitorService");
                }
            });
        }
        if (watchFuture==null || watchFuture.isCancelled() || watchFuture.isDone()) {
            watchFuture = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            Collection<SFMF4JWatchListener> listeners;
                            List<WatchEvent<?>> events;
                            final WatchKey key = watchService.take();
                            synchronized (WatchServiceFileMonitorServiceImpl.this) {
                                listeners = listenersByWatchKey.get(key);
                                if (listeners != null && !listeners.isEmpty()) {
                                    listeners = new LinkedList<SFMF4JWatchListener>(listeners);
                                    events = key.pollEvents();
                                    boolean stillValid = key.reset();
                                    if (!stillValid) {
                                        logger.warn("Key no longer valid.");
                                        cleanup(key);
                                    } else {
                                        logger.debug("Key is still valid.");
                                        if (events != null && !events.isEmpty()) {
                                            for (WatchEvent event : events) {
                                                WatchEvent<Path> resolvedEvent = resolveEventWithCorrectPath(key, event);
                                                logger.debug("Event kind={} count={} path={}", new Object[]{resolvedEvent.kind().name(), resolvedEvent.count(), resolvedEvent.context()});
                                                for (SFMF4JWatchListener listener : listeners) {
                                                    listener.onEvent(resolvedEvent);
                                                }
                                            }
                                        }
                                    }
                                } else {
                                    logger.debug("No listeners found for valid key... cleaning up.");
                                    cleanup(key);
                                }
                            }
                        } catch (InterruptedException ex) {
                            return;
                        } catch (ClosedWatchServiceException ex) {
                            return;
                        }
                    }
                }
            });
        }
    }

    @Override
    @SuppressWarnings("PMD.EmptyCatchBlock")
    public synchronized void shutdown() {
        watchFuture.cancel(true);
        watchFuture = null;
        for (WatchKey key : pathsByWatchKey.keySet()) {
            cleanup(key);
        }
        if (shutdownExecutorServiceOnShutdown) {
            executorService.shutdownNow();
            executorService = null;
        }
        if (closeWatchServiceOnShutdown) {
            try {
                watchService.close();
            }catch(IOException ex) {
                //trap
            }catch(ClosedWatchServiceException ex) {
                //trap
            }finally {
                watchService = null;
            }
        }
    }

    @Override
    public synchronized boolean isMonitoringDirectory(File directory) {
        ExecutorService es = getExecutorService();
        return es != null && !es.isShutdown() && watchKeysByPath.containsKey(directory.getAbsolutePath());
    }


}
FileProjectLine
com\github\sworisbreathing\sfmf4j\jpathwatch\ResolvedPathWatchEvent.javaSFMF4J :: JPathWatch26
com\github\sworisbreathing\sfmf4j\nio2\ResolvedPathWatchEvent.javaSFMF4J :: NIO226
public class ResolvedPathWatchEvent extends WatchEvent<Path> {

    /**
     * The path.
     */
    private final Path context;

    /**
     * The event count.
     */
    private final int count;

    /**
     * The kind.
     */
    private final Kind<Path> kind;

    /**
     * Copy constructor for a watch event, which ensures the path is fully
     * resolved.
     * @param source the event to copy
     * @param parentPath the parent path
     * @see Path#resolve(Path)
     */
    public ResolvedPathWatchEvent(final WatchEvent<Path> source, final Path parentPath) {
        if (source==null) {
            throw new IllegalArgumentException("source is null");
        } else if (parentPath==null) {
            throw new IllegalArgumentException("parentPath is null");
        } else {
            this.context = parentPath.resolve(source.context());
            this.count = source.count();
            this.kind = source.kind();
        }
    }

    @Override
    public Path context() {
        return context;
    }

    @Override
    public int count() {
        return count;
    }

    @Override
    public Kind<Path> kind() {
        return kind;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 53 * hash + (this.context != null ? this.context.hashCode() : 0);
        hash = 53 * hash + this.count;
        hash = 53 * hash + (this.kind != null ? this.kind.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ResolvedPathWatchEvent other = (ResolvedPathWatchEvent) obj;
        if (this.context != other.context && (this.context == null || !this.context.equals(other.context))) {
            return false;
        }
        if (this.count != other.count) {
            return false;
        }
        if (this.kind != other.kind && (this.kind == null || !this.kind.equals(other.kind))) {
            return false;
        }
        return true;
    }
}