package com.github.drapostolos.rdp4j; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import com.github.drapostolos.rdp4j.spi.FileElement; import com.github.drapostolos.rdp4j.spi.PolledDirectory; /** * A builder class that configures and then returns a started * {@link DirectoryPoller} instance. * * @see <a href="https://github.com/drapostolos/rdp4j/wiki/User-Guide">User-Guide</a> */ public final class DirectoryPollerBuilder { private static final String NULL_ARGUMENT_ERROR_MESSAGE = "null argument not allowed!"; static final String DEFAULT_THREAD_NAME = "DirectoryPoller-"; Set<PolledDirectory> directories = new LinkedHashSet<PolledDirectory>(); // Optional settings, with default values: long pollingIntervalInMillis = 1000; FileFilter filter = new DefaultFileFilter(); String threadName = DEFAULT_THREAD_NAME; boolean fileAddedEventEnabledForInitialContent = false; boolean parallelDirectoryPollingEnabled = false; Set<Rdp4jListener> listeners = new HashSet<Rdp4jListener>(); DirectoryPollerBuilder() { // package-private access only. } /** * Enable {@link FileAddedEvent} events to be fired for the initial * content of the directories added in the {@link DirectoryPoller}. * <p> * The initial content of a directory are the files/directories * it contains the first poll-cycle. * <p> * Optional setting. Disabled by default. * * @return {@link DirectoryPollerBuilder} */ public DirectoryPollerBuilder enableFileAddedEventsForInitialContent() { fileAddedEventEnabledForInitialContent = true; return this; } /** * Enable parallel polling of the directories added in the {@link DirectoryPoller}. * <p> * NOTE! * This puts constraints on the added listeners to be thread safe. * <p> * Optional setting. Disabled by default. * * @return {@link DirectoryPollerBuilder} */ public DirectoryPollerBuilder enableParallelPollingOfDirectories() { parallelDirectoryPollingEnabled = true; return this; } /** * Adds the given <code>directory</code> to the list of polled directories. * Mandatory to add at least one directory. * <p> * Once the {@link DirectoryPoller} has been built, it can be used to add * additional polled directories, or remove polled directories. * * @param directory - the directory to poll. * @throws NullPointerException - if the given argument is null. * @return {@link DirectoryPollerBuilder} */ public DirectoryPollerBuilder addPolledDirectory(PolledDirectory directory) { if (directory == null) { throw new NullPointerException(NULL_ARGUMENT_ERROR_MESSAGE); } directories.add(directory); return this; } /** * Set the interval between each poll cycle. Optional parameter. * Default value is 1000 milliseconds. * * @param interval - the interval between two poll-cycles. * @param timeUnit - the unit of the interval. Example: TimeUnit.MINUTES * @return {@link DirectoryPollerBuilder} * @throws IllegalArgumentException if <code>interval</code> is negative. */ public DirectoryPollerBuilder setPollingInterval(long interval, TimeUnit timeUnit) { if (interval < 0) { throw new IllegalArgumentException("Argument 'interval' is negative: " + interval); } pollingIntervalInMillis = timeUnit.toMillis(interval); return this; } /** * Set a {@link FileFilter} to be used. Only {@link FileElement}'s * Satisfying the filter will be considered. * <p> * Optional setting. By default all {@link FileElement}'s are * satisfying the filter. * * @param filter FileFilter * @return {@link DirectoryPollerBuilder} * @throws NullPointerException if <code>filter</code> is null. */ public DirectoryPollerBuilder setDefaultFileFilter(FileFilter filter) { if (filter == null) { throw new NullPointerException(NULL_ARGUMENT_ERROR_MESSAGE); } this.filter = filter; return this; } /** * Changes the name of the associated polling thread to be equal * to the given <code>name</code>. * <p> * Optional setting. By default each thread is named "DirectoryPoller-{X}", * where {X} is a sequence number. I.e: "DirectoryPoller-1", "DirectoryPoller-2" etc. etc. * * @param name of thread. * @return {@link DirectoryPollerBuilder} * @throws NullPointerException if the given argument is null. */ public DirectoryPollerBuilder setThreadName(String name) { if (name == null) { String message = "Null argument"; throw new NullPointerException(message); } threadName = name; return this; } /** * Adds the given <code>listener</code> to the list of {@link Rdp4jListener}'s * that receives notifications. * <p> * Once the {@link DirectoryPoller} has been built, it can be used to * add additional listeners, or remove listeners. * * @param listener Implementation of any of the sub-interfaces of {@link Rdp4jListener} * -interface. * @return {@link DirectoryPollerBuilder} * @throws NullPointerException if the given argument is null. */ public DirectoryPollerBuilder addListener(Rdp4jListener listener) { if (listener == null) { throw new NullPointerException(NULL_ARGUMENT_ERROR_MESSAGE); } listeners.add(listener); return this; } /** * Builds a new {@link DirectoryPoller} instance and starts the poll-cycle * mechanism. * <p> * This method will block until all {@link BeforeStartEvent} events has been * fired (and processed by all listeners.) * * @return {@link DirectoryPoller}. */ public DirectoryPoller start() { return future().get(); } /** * Asynchronously starts the poll-cycle mechanism. * <p> * To get a hold of the {@link DirectoryPoller} instance, call the get method on the returned * {@link DirectoryPollerFuture} instance. * * @return {@link DirectoryPollerFuture}. */ public DirectoryPollerFuture startAsync() { return future(); } private DirectoryPollerFuture future() { final DirectoryPoller dp = new DirectoryPoller(this); Future<DirectoryPoller> f = Util.invokeTask("DP-BeforeStart", new Callable<DirectoryPoller>() { @Override public DirectoryPoller call() { dp.notifier.beforeStart(new BeforeStartEvent()); dp.start(); return dp; } }); return new DirectoryPollerFuture(f); } }