From 3acf86e8b5bee025e5e5141a99ead744d9916611 Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Tue, 29 May 2007 06:36:30 +0000
Subject: [PATCH] add: args4j library for parsing the command line remove:
 commons-cli library for parsing the command line change: switch datamover and
 lims over to use arg4j instead of commons-cli

SVN: 213
---
 datamover/.classpath                          |  26 +-
 .../java/ch/systemsx/cisd/datamover/Main.java |   6 -
 .../systemsx/cisd/datamover/Parameters.java   | 382 ++++--------------
 .../cisd/datamover/ParametersTest.java        | 140 +++----
 4 files changed, 151 insertions(+), 403 deletions(-)

diff --git a/datamover/.classpath b/datamover/.classpath
index 1639fb579a6..cd454f22531 100644
--- a/datamover/.classpath
+++ b/datamover/.classpath
@@ -1,13 +1,13 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="sourceTest/java"/>
-	<classpathentry kind="src" path="source/java"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="lib" path="/libraries/activation/activation.jar"/>
-	<classpathentry kind="lib" path="/libraries/commons-cli/commons-cli.jar" sourcepath="/libraries/commons-cli/src.zip"/>
-	<classpathentry kind="lib" path="/libraries/log4j/log4j.jar" sourcepath="/libraries/log4j/src.zip"/>
-	<classpathentry kind="lib" path="/libraries/mail/mail.jar"/>
-	<classpathentry kind="lib" path="/libraries/testng/testng-jdk15.jar" sourcepath="/libraries/testng/src.zip"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/common"/>
-	<classpathentry kind="output" path="targets/classes"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="sourceTest/java"/>
+	<classpathentry kind="src" path="source/java"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="lib" path="/libraries/activation/activation.jar"/>
+	<classpathentry kind="lib" path="/libraries/log4j/log4j.jar" sourcepath="/libraries/log4j/src.zip"/>
+	<classpathentry kind="lib" path="/libraries/mail/mail.jar"/>
+	<classpathentry kind="lib" path="/libraries/testng/testng-jdk15.jar" sourcepath="/libraries/testng/src.zip"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/common"/>
+	<classpathentry kind="lib" path="/libraries/args4j/args4j.jar" sourcepath="/libraries/args4j/args4j-src.jar"/>
+	<classpathentry kind="output" path="targets/classes"/>
+</classpath>
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/Main.java b/datamover/source/java/ch/systemsx/cisd/datamover/Main.java
index 39541c5cf58..520398fa88c 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/Main.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/Main.java
@@ -222,12 +222,6 @@ public class Main
     {
         initLog();
         final Parameters parameters = new Parameters(args);
-        if (parameters.hasAllMandatoryOptions() == false)
-        {
-            parameters.printVersionAndOptions();
-            System.err.println("\nThere are mandatory options missing from the command line.");
-            System.exit(1);
-        }
         printInitialLogMessage(parameters);
         startupServer(parameters);
         operationLog.info("Data mover ready and waiting for data.");
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java b/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
index 9820b5eac1c..cb1e7fcce87 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
@@ -17,17 +17,17 @@
 package ch.systemsx.cisd.datamover;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.regex.Pattern;
 
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.GnuParser;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
 import org.apache.log4j.Logger;
-
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.ExampleMode;
+import org.kohsuke.args4j.Option;
+import org.kohsuke.args4j.spi.LongOptionHandler;
+import org.kohsuke.args4j.spi.Setter;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.utilities.BuildAndEnvironmentInfo;
@@ -44,145 +44,63 @@ public class Parameters implements ITimingParameters
 
     private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY, Parameters.class);
 
-    /**
-     * The number of milliseconds in a minute.
-     */
-    public static final long MINUTE_MILLIS = 60 * 1000;
-
-    private static final Option RSYNC_EXECUTABLE_OPT =
-            new Option("e", "rsync-executable", true, "The rsync executable to use for copy operations.");
-
-    private static final Option SSH_EXECUTABLE_OPT =
-        new Option("s", "ssh-executable", true, "The ssh executable to use for creating tunnels.");
-
-    private static final Option LOCAL_DATA_DIR_OPT =
-            new Option("d", "local-datadir", true, "The local directory where the data producer writes to (mandatory).");
-
-    private static final Option LOCAL_TEMP_DIR_OPT =
-            new Option("t", "local-tempdir", true,
-                    "The local directory to store the paths to be transfered temporarily (mandatory).");
-
-    private static final Option REMOTE_DIR_OPT =
-            new Option("r", "remotedir", true, "The remote directory to move the data to (mandatory).");
-
-    private static final Option REMOTE_HOST_OPT =
-            new Option("h", "remotehost", true, "The remote host to move the data to (only with rsync).");
-
-    /**
-     * The default interval to wait beween two checks for activity (in milliseconds).
-     */
-    private static final long CHECK_INTERVAL_MILLIS_DEFAULT = 2 * MINUTE_MILLIS;
-
-    private static final Option CHECK_INTERVAL_OPT =
-            new Option("c", "check-interval", true, String.format(
-                    "The interval to wait between two checks (in seconds) [default: %d].",
-                    CHECK_INTERVAL_MILLIS_DEFAULT / 1000));
-
-    /**
-     * The default period to wait before a file or directory is considered "quiet" (in milliseconds). This setting is
-     * used when deciding whether a file or directory is ready to be moved to the remote side.
-     */
-    private static final long QUIET_PERIOD_MILLIS_DEFAULT = 5 * MINUTE_MILLIS;
-
-    private static final Option QUIET_PERIOD_OPT =
-            new Option("q", "quiet-period", true, String.format(
-                    "The period that needs to pass before a path item is considered quiet (in seconds) [default: %d].",
-                    QUIET_PERIOD_MILLIS_DEFAULT / 1000));
-
-    /**
-     * The default time intervall to wait after a failure has occurred before the operation is retried.
-     */
-    private static final long INTERVAL_TO_WAIT_AFTER_FAILURE_MILLIS = 2 * MINUTE_MILLIS;
-
-    private static final Option INTERVAL_TO_WAIT_AFTER_FAILURE_OPT =
-            new Option(
-                    "f",
-                    "failure-interval",
-                    true,
-                    String
-                            .format(
-                                    "The interval to wait after a failure has occurred before retrying the operation (in seconds) [default: %d].",
-                                    INTERVAL_TO_WAIT_AFTER_FAILURE_MILLIS / 1000));
-
-    /**
-     * The default number of times a failed operation is retried (note that this means that the total number that the
-     * operation is tried is one more).
-     */
-    private static final int MAXIMAL_NUMBER_OF_RETRIES_DEFAULT = 2;
-
-    private static final Option MAXIMAL_NUMBER_OF_RETRIES_OPT =
-            new Option("m", "max-retries", true, String.format(
-                    "The number of retries of a failed operation before the data mover gives up on it. [default: %d].",
-                    MAXIMAL_NUMBER_OF_RETRIES_DEFAULT));
-
-    /**
-     * The default period to wait before a file or directory is considered "inactive" or "stalled" (in milliseconds).
-     * This setting is used when deciding whether a copy operation of a file or directory is "stalled".
-     */
-    private static final long INACTIVITY_PERIOD_MILLIS_DEFAULT = 10 * MINUTE_MILLIS;
-
-    private static final Option INACTIVITY_PERIOD_MILLIS_OPT =
-            new Option(
-                    "i",
-                    "inactivity-period",
-                    true,
-                    String
-                            .format(
-                                    "The period to wait before a file or directory is considered \"inactive\" or \"stalled\" (in seconds) [default: %d].",
-                                    INACTIVITY_PERIOD_MILLIS_DEFAULT / 1000));
-
-    private static final Option CLEANSING_REGEX_OPT =
-            new Option("x", "cleansing-regex", true,
-                    "The regular expression to use for cleansing before moving to remote.");
-
-    private static final Option HELP_OPT = new Option("H", "help", false, "Prints out a description of the options.");
-
-    private static final Option VERSION_OPT = new Option("V", "version", false, "Prints out the version information.");
-
-    private static final Option TEST_NOTIFY_OPT =
-            new Option("N", "test-notify", false, "Tests the notify log (i.e. that mail is sent out).");
-
     /**
      * The name of the <code>rsync</code> executable to use for copy operations.
      */
+    @Option(longName = "rsync-executable", metaVar = "EXEC", usage = "The rsync executable to use for "
+            + "copy operations.")
     private String rsyncExecutable = null;
 
     /**
      * The name of the <code>ssh</code> executable to use for creating tunnels.
      */
+    @Option(longName = "ssh-executable", metaVar = "EXEC", usage = "The ssh executable to use for "
+            + "creating tunnels.")
     private String sshExecutable = null;
-    
+
     /**
      * The interval to wait beween to checks for activity (in milliseconds).
      */
-    private long checkIntervalMillis = CHECK_INTERVAL_MILLIS_DEFAULT;
+    @Option(name = "c", longName = "check-interval", usage = "The interval to wait between two checks (in seconds) "
+            + "[default: 120]", handler = MillisecondConversionOptionHandler.class)
+    private long checkIntervalMillis = 120 * 1000;
 
     /**
      * The period to wait before a file or directory is considered "inactive" or "stalled" (in milliseconds). This
      * setting is used when deciding whether a copy operation of a file or directory is "stalled".
      */
-    private long inactivityPeriodMillis = INACTIVITY_PERIOD_MILLIS_DEFAULT;
+    @Option(name = "i", longName = "inactivity-period", usage = "The period to wait before a file or directory is "
+            + "considered \"inactive\" or \"stalled\" (in seconds) [default: 600].", handler = MillisecondConversionOptionHandler.class)
+    private long inactivityPeriodMillis = 600 * 1000;
 
     /**
      * The period to wait before a file or directory is considered "quiet" (in milliseconds). This setting is used when
      * deciding whether a file or directory is ready to be moved to the remote side.
      */
-    private long quietPeriodMillis = QUIET_PERIOD_MILLIS_DEFAULT;
+    @Option(name = "q", longName = "quiet-period", usage = "The period that needs to pass before a path item is "
+            + "considered quiet (in seconds) [default: 300].", handler = MillisecondConversionOptionHandler.class)
+    private long quietPeriodMillis = 300 * 1000;
 
     /**
-     * The time intervall to wait after a failure has occurred before the operation is retried.
+     * The time intervall to wait after a failure has occurred before the operation is retried (in milliseconds).
      */
-    private long intervalToWaitAfterFailureMillis = INTERVAL_TO_WAIT_AFTER_FAILURE_MILLIS;
+    @Option(name = "f", longName = "failure-interval", usage = "The interval to wait after a failure has occurred "
+            + "before retrying the operation (in seconds) [default: 120].", handler = MillisecondConversionOptionHandler.class)
+    private long intervalToWaitAfterFailureMillis = 120 * 1000;
 
     /**
      * The number of times a failed operation is retried (note that this means that the total number that the operation
      * is tried is one more).
      */
-    private int maximalNumberOfRetries = MAXIMAL_NUMBER_OF_RETRIES_DEFAULT;
+    @Option(name = "m", longName = "max-retries", usage = "The number of retries of a failed operation before the "
+            + "datamover gives up on it. [default: 2].")
+    private int maximalNumberOfRetries = 2;
 
     /**
      * The (local) directory to monitor for new files and directories to move to the remote side.
      */
+    @Option(name = "d", longName = "local-datadir", metaVar = "DIR", required = true, usage = "The local directory where "
+            + "the data producer writes to.")
     private File localDataDirectory = null;
 
     /**
@@ -190,236 +108,114 @@ public class Parameters implements ITimingParameters
      * and thus are considered to be ready to be moved to remote. Note that this directory needs to be on the same file
      * system than {@link #localDataDirectory}.
      */
+    @Option(name = "t", longName = "local-tempdir", metaVar = "DIR", required = true, usage = "The local directory to "
+            + "store the paths to be transfered temporarily.")
     private File localTemporaryDirectory = null;
 
     /**
      * The directory on the remote side to move the local files to once they are quiet.
      */
+    @Option(name = "r", longName = "remotedir", metaVar = "DIR", required = true, usage = "The remote directory to "
+            + "move the data to.")
     private File remoteDataDirectory = null;
 
     /**
-     * The remote host to copy the data to (only with rsync, will use ssh tunnel).
+     * The remote host to copy the data to (only with rsync, will use an ssh tunnel).
      */
+    @Option(name = "h", longName = "remotehost", metaVar = "HOST", usage = "The remote host to move the data to (only "
+            + "with rsync).")
     private String remoteHost = null;
 
     /**
      * The regular expression to use for cleansing on the local path before moving it to remote.
      */
+    @Option(longName = "cleansing-regex", usage = "The regular expression to use for cleansing before "
+            + "moving to remote.")
     private Pattern cleansingRegex = null;
 
     /**
-     * <code>true</code> if the command line provided all necessary options.
+     * The command line parser.
      */
-    private boolean hasAllMandatoryOptions;
+    private final CmdLineParser parser = new CmdLineParser(this);
 
-    /**
-     * Class that wraps {@link Options} and keeps an order.
-     */
-    private static class OptionsWrapper
+    @Option(longName = "help", skipForExample = true, usage = "Prints out a description of the options.")
+    void printHelp(boolean exit)
     {
-        private final Options optionMap = new Options();
-
-        private final List<Option> optionList = new ArrayList<Option>();
-
-        private final List<Option> mandatoryOptionList = new ArrayList<Option>();
-
-        void add(Option option, boolean mandatory)
-        {
-            optionMap.addOption(option);
-            optionList.add(option);
-            if (mandatory)
-            {
-                mandatoryOptionList.add(option);
-            }
-        }
-
-        void addEmptyLine()
-        {
-            optionList.add(null);
-        }
-
-        Options getOptionMap()
-        {
-            return optionMap;
-        }
-
-        List<Option> getOptionList()
+        parser.printHelp("datamover", "<required options> [option [...]]", "", ExampleMode.ALL);
+        if (exit)
         {
-            return optionList;
+            System.exit(0);
         }
-
-        List<Option> getMandatoryOptionList()
-        {
-            return mandatoryOptionList;
-        }
-
     }
 
-    public Parameters(String[] args)
+    @Option(longName = "version", skipForExample = true, usage = "Prints out the version information.")
+    void printVersion(boolean exit)
     {
-        final OptionsWrapper options = getOptions();
-        try
+        System.err.println("datamover version " + BuildAndEnvironmentInfo.INSTANCE.getBuildNumber());
+        if (exit)
         {
-            final CommandLine cmdLine = (new GnuParser()).parse(options.getOptionMap(), args);
-            hasAllMandatoryOptions = hasAllMandatoryOptions(cmdLine, options.getMandatoryOptionList());
-            if (cmdLine.hasOption(HELP_OPT.getOpt()))
-            {
-                printVersion();
-                printOptions(options);
-                System.exit(1);
-            }
-            if (cmdLine.hasOption(VERSION_OPT.getOpt()))
-            {
-                printVersion();
-                System.exit(1);
-            }
-            if (cmdLine.hasOption(TEST_NOTIFY_OPT.getOpt()))
-            {
-                notificationLog.error("This is a test notification given due to specifying the --test-notify option.");
-                System.exit(1);
-            }
-            updateParametersFromCommandLine(cmdLine);
-        } catch (ParseException e)
-        {
-            printVersion();
-            System.err.printf("Exception when parsing command line: [%s: %s]\n", e.getClass().getSimpleName(), e
-                    .getMessage());
-            printOptions(options);
-            System.exit(1);
+            System.exit(0);
         }
     }
 
-    private OptionsWrapper getOptions()
+    @Option(longName = "test-notify", skipForExample = true, usage = "Tests the notify log (i.e. that an email is "
+            + "sent out).")
+    void sendTestNotification(boolean exit)
     {
-        final OptionsWrapper options = new OptionsWrapper();
-        options.add(LOCAL_DATA_DIR_OPT, true);
-        options.add(LOCAL_TEMP_DIR_OPT, true);
-        options.add(REMOTE_DIR_OPT, true);
-        options.add(REMOTE_HOST_OPT, false);
-        options.addEmptyLine();
-        options.add(CHECK_INTERVAL_OPT, false);
-        options.add(QUIET_PERIOD_OPT, false);
-        options.add(INACTIVITY_PERIOD_MILLIS_OPT, false);
-        options.add(INTERVAL_TO_WAIT_AFTER_FAILURE_OPT, false);
-        options.add(MAXIMAL_NUMBER_OF_RETRIES_OPT, false);
-        options.addEmptyLine();
-        options.add(RSYNC_EXECUTABLE_OPT, false);
-        options.add(SSH_EXECUTABLE_OPT, false);
-        options.addEmptyLine();
-        options.add(CLEANSING_REGEX_OPT, false);
-        options.addEmptyLine();
-        options.add(HELP_OPT, false);
-        options.add(VERSION_OPT, false);
-        options.add(TEST_NOTIFY_OPT, false);
-
-        return options;
+        notificationLog.error("This is a test notification given due to specifying the --test-notify option.");
+        if (exit)
+        {
+            System.exit(0);
+        }
     }
 
-    private boolean hasAllMandatoryOptions(CommandLine cmdLine, List<Option> mandatoryOptionList)
+    /**
+     * A class which converts <code>long</code> options given in seconds to milli-seconds.
+     */
+    public static class MillisecondConversionOptionHandler extends LongOptionHandler
     {
-        for (Option option : mandatoryOptionList)
+        public MillisecondConversionOptionHandler(Option option, Setter<? super Long> setter)
         {
-            if (cmdLine.hasOption(option.getOpt()) == false)
-            {
-                return false;
-            }
+            super(option, setter);
         }
-        return true;
-    }
 
-    private void printOptions(final OptionsWrapper options)
-    {
-        System.err.println("List of options:");
-        for (Option option : options.getOptionList())
+        @Override
+        public void set(long value) throws CmdLineException
         {
-            if (option == null)
-            {
-                System.err.println();
-            } else
-            {
-                System.err.printf("  -%s [--%s]: %s\n", option.getOpt(), option.getLongOpt(), option.getDescription());
-            }
+            setter.addValue(value * 1000);
         }
-    }
 
-    private void printVersion()
-    {
-        System.err.println("Data mover version " + BuildAndEnvironmentInfo.INSTANCE.getBuildNumber());
     }
 
-    /**
-     * Prints out the options.
-     */
-    public void printVersionAndOptions()
+    Parameters(String[] args)
     {
-        printVersion();
-        printOptions(getOptions());
+        this(args, false, false);
     }
 
-    private void updateParametersFromCommandLine(final CommandLine cmdLine)
+    Parameters(String[] args, boolean unitTest, boolean suppressMissingMandatoryOptions)
     {
-        if (cmdLine.hasOption(RSYNC_EXECUTABLE_OPT.getOpt()))
-        {
-            rsyncExecutable = cmdLine.getOptionValue(RSYNC_EXECUTABLE_OPT.getOpt());
-        }
-        if (cmdLine.hasOption(SSH_EXECUTABLE_OPT.getOpt()))
-        {
-            sshExecutable = cmdLine.getOptionValue(SSH_EXECUTABLE_OPT.getOpt());
-        }
-        if (cmdLine.hasOption(LOCAL_DATA_DIR_OPT.getOpt()))
-        {
-            localDataDirectory = new File(cmdLine.getOptionValue(LOCAL_DATA_DIR_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(LOCAL_TEMP_DIR_OPT.getOpt()))
-        {
-            localTemporaryDirectory = new File(cmdLine.getOptionValue(LOCAL_TEMP_DIR_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(REMOTE_DIR_OPT.getOpt()))
-        {
-            remoteDataDirectory = new File(cmdLine.getOptionValue(REMOTE_DIR_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(REMOTE_HOST_OPT.getOpt()))
-        {
-            remoteHost = cmdLine.getOptionValue(REMOTE_HOST_OPT.getOpt());
-        }
-        if (cmdLine.hasOption(CHECK_INTERVAL_OPT.getOpt()))
-        {
-            checkIntervalMillis = 1000 * Long.parseLong(cmdLine.getOptionValue(CHECK_INTERVAL_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(QUIET_PERIOD_OPT.getOpt()))
-        {
-            quietPeriodMillis = 1000 * Long.parseLong(cmdLine.getOptionValue(QUIET_PERIOD_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(INTERVAL_TO_WAIT_AFTER_FAILURE_OPT.getOpt()))
-        {
-            intervalToWaitAfterFailureMillis =
-                    1000 * Long.parseLong(cmdLine.getOptionValue(INTERVAL_TO_WAIT_AFTER_FAILURE_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(MAXIMAL_NUMBER_OF_RETRIES_OPT.getOpt()))
-        {
-            maximalNumberOfRetries = Integer.parseInt(cmdLine.getOptionValue(MAXIMAL_NUMBER_OF_RETRIES_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(INACTIVITY_PERIOD_MILLIS_OPT.getOpt()))
+        try
         {
-            inactivityPeriodMillis =
-                    1000 * Long.parseLong(cmdLine.getOptionValue(INACTIVITY_PERIOD_MILLIS_OPT.getOpt()));
-        }
-        if (cmdLine.hasOption(CLEANSING_REGEX_OPT.getOpt()))
+            parser.parseArgument(args);
+        } catch (CmdLineException ex)
         {
-            final String cleansingRegexStr = cmdLine.getOptionValue(CLEANSING_REGEX_OPT.getOpt());
-            cleansingRegex = Pattern.compile(cleansingRegexStr);
+            if (unitTest == false)
+            {
+                System.err.println(ex.getMessage());
+                printHelp(false);
+                System.exit(1);
+            } else
+            // Suppress exception due to missing mandatory options.
+            {
+                if (false == suppressMissingMandatoryOptions
+                        || ex.getMessage().indexOf("Required option(s) are missing") == -1)
+                {
+                    throw new UserFailureException("Error parsing command line: " + ex.getMessage(), ex);
+                }
+            }
         }
     }
 
-    /**
-     * @return <code>true</code> if and only if all mandatory options have been provided to this
-     *         <code>Parameter</code> object.
-     */
-    public boolean hasAllMandatoryOptions()
-    {
-        return hasAllMandatoryOptions;
-    }
-
     /**
      * @return The name of the <code>rsync</code> executable to use for copy operations.
      */
diff --git a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/ParametersTest.java b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/ParametersTest.java
index 4b37b7fff25..f313462d7cd 100644
--- a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/ParametersTest.java
+++ b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/ParametersTest.java
@@ -17,207 +17,167 @@
 package ch.systemsx.cisd.datamover;
 
 import java.io.File;
-import java.util.regex.PatternSyntaxException;
-
 import org.testng.annotations.Test;
 
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
 import static org.testng.AssertJUnit.*;
 
 /**
  * Test cases for the {@link Parameters} class.
  * 
- * @author bernd
+ * @author Bernd Rinn
  */
 public class ParametersTest
 {
 
-    @Test()
-    public void testSetRsyncExecutableLong() throws Exception
+    private Parameters parse(String... args)
     {
-        final String RSYNC_EXEC = "/usr/local/bin/rsync";
-        final Parameters parameters = new Parameters(new String[]
-            { "--rsync-executable", RSYNC_EXEC });
-        assertEquals(RSYNC_EXEC, parameters.getRsyncExecutable());
-        assert parameters.hasAllMandatoryOptions() == false;
+        return parse(true, args);
     }
 
-    @Test()
-    public void testSetRsyncExecutableShort() throws Exception
+    private Parameters parse(boolean suppressMissingMandatoryOptions, String... args)
     {
-        final String RSYNC_EXEC = "/usr/local/bin/rsync";
-        final Parameters parameters = new Parameters(new String[]
-            { "-e", RSYNC_EXEC });
-        assertEquals(RSYNC_EXEC, parameters.getRsyncExecutable());
-        assert parameters.hasAllMandatoryOptions() == false;
+        return new Parameters(args, true, suppressMissingMandatoryOptions);
     }
 
-    @Test()
-    public void testSetSshExecutableLong() throws Exception
+    @Test
+    public void testSetRsyncExecutableLong() throws Exception
     {
-        final String SSH_EXEC = "/usr/local/bin/ssh";
-        final Parameters parameters = new Parameters(new String[]
-            { "--ssh-executable", SSH_EXEC });
-        assertEquals(SSH_EXEC, parameters.getSshExecutable());
-        assert parameters.hasAllMandatoryOptions() == false;
+        final String RSYNC_EXEC = "/usr/local/bin/rsync";
+        final Parameters parameters = parse("--rsync-executable", RSYNC_EXEC);
+        assertEquals(RSYNC_EXEC, parameters.getRsyncExecutable());
     }
 
-    @Test()
-    public void testSetSshExecutableShort() throws Exception
+    @Test
+    public void testSetSshExecutableLong() throws Exception
     {
         final String SSH_EXEC = "/usr/local/bin/ssh";
-        final Parameters parameters = new Parameters(new String[]
-            { "-s", SSH_EXEC });
+        final Parameters parameters = parse("--ssh-executable", SSH_EXEC);
         assertEquals(SSH_EXEC, parameters.getSshExecutable());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
-    @Test()
+    @Test
     public void testSetCleansingRegexLong() throws Exception
     {
         final String CLEANSING_REGEX = "[0-9]+";
-        final Parameters parameters = new Parameters(new String[]
-            { "--cleansing-regex", CLEANSING_REGEX });
-        assertEquals(CLEANSING_REGEX, parameters.getCleansingRegex().pattern());
-        assert parameters.hasAllMandatoryOptions() == false;
-    }
-
-    @Test()
-    public void testSetCleansingRegexShort() throws Exception
-    {
-        final String CLEANSING_REGEX = "[0-9]+";
-        final Parameters parameters = new Parameters(new String[]
-            { "-x", CLEANSING_REGEX });
+        final Parameters parameters = parse("--cleansing-regex", CLEANSING_REGEX);
         assertEquals(CLEANSING_REGEX, parameters.getCleansingRegex().pattern());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
-    @Test(expectedExceptions =
-        { PatternSyntaxException.class })
+    @Test(expectedExceptions = UserFailureException.class)
     public void testSetInvalidCleansingRegex() throws Exception
     {
         final String CLEANSING_REGEX = "[0-9}+";
-        new Parameters(new String[]
-            { "--cleansing-regex", CLEANSING_REGEX });
+        parse("--cleansing-regex", CLEANSING_REGEX);
     }
 
     @Test
     public void testSetLocalDataDirLong() throws Exception
     {
         final String LOCAL_DATADIR = ".." + File.separator + "test_it_data";
-        final Parameters parameters = new Parameters(new String[]
-            { "--local-datadir", LOCAL_DATADIR });
+        final Parameters parameters = parse("--local-datadir", LOCAL_DATADIR);
         assertEquals(LOCAL_DATADIR, parameters.getLocalDataDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetLocalDataDirShort() throws Exception
     {
         final String LOCAL_DATADIR = ".." + File.separator + "test_it_data2";
-        final Parameters parameters = new Parameters(new String[]
-            { "-d", LOCAL_DATADIR });
+        final Parameters parameters = parse("-d", LOCAL_DATADIR);
         assertEquals(LOCAL_DATADIR, parameters.getLocalDataDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetLocalTempDirLong() throws Exception
     {
         final String LOCAL_TEMPDIR = "test_it_tmp";
-        final Parameters parameters = new Parameters(new String[]
-            { "--local-tempdir", LOCAL_TEMPDIR });
+        final Parameters parameters = parse("--local-tempdir", LOCAL_TEMPDIR);
         assertEquals(LOCAL_TEMPDIR, parameters.getLocalTemporaryDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetLocalTempDirShort() throws Exception
     {
         final String LOCAL_TEMPDIR = "test_it_tmp3";
-        final Parameters parameters = new Parameters(new String[]
-            { "-t", LOCAL_TEMPDIR });
+        final Parameters parameters = parse("-t", LOCAL_TEMPDIR);
         assertEquals(LOCAL_TEMPDIR, parameters.getLocalTemporaryDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetRemoteDirLong() throws Exception
     {
         final String REMOTE_DATADIR = "test_it_remote";
-        final Parameters parameters = new Parameters(new String[]
-            { "--remotedir", REMOTE_DATADIR });
+        final Parameters parameters = parse("--remotedir", REMOTE_DATADIR);
         assertEquals(REMOTE_DATADIR, parameters.getRemoteDataDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetRemoteDirShort() throws Exception
     {
         final String REMOTE_DATADIR = "test_it_remote4";
-        final Parameters parameters = new Parameters(new String[]
-            { "-r", REMOTE_DATADIR });
+        final Parameters parameters = parse("-r", REMOTE_DATADIR);
         assertEquals(REMOTE_DATADIR, parameters.getRemoteDataDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetRemoteHostLong() throws Exception
     {
         final String REMOTE_HOST = "test_it_remote";
-        final Parameters parameters = new Parameters(new String[]
-            { "--remotehost", REMOTE_HOST });
+        final Parameters parameters = parse("--remotehost", REMOTE_HOST);
         assertEquals(REMOTE_HOST, parameters.getRemoteHost());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetRemoteHostShort() throws Exception
     {
         final String REMOTE_HOST = "test_it_remote4";
-        final Parameters parameters = new Parameters(new String[]
-            { "-h", REMOTE_HOST });
+        final Parameters parameters = parse("-h", REMOTE_HOST);
         assertEquals(REMOTE_HOST, parameters.getRemoteHost());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetCheckIntervalLong() throws Exception
     {
         final int CHECK_INTERVAL = 5;
-        final Parameters parameters = new Parameters(new String[]
-            { "--check-interval", Integer.toString(CHECK_INTERVAL) });
+        final Parameters parameters = parse("--check-interval", Integer.toString(CHECK_INTERVAL));
         assertEquals(1000 * CHECK_INTERVAL, parameters.getCheckIntervalMillis());
-        assert parameters.hasAllMandatoryOptions() == false;
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testSetInvalidCheckInterval() throws Exception
+    {
+        parse("--check-interval", "5x");
     }
 
     @Test
     public void testSetCheckIntervalShort() throws Exception
     {
         final int CHECK_INTERVAL = 11;
-        final Parameters parameters = new Parameters(new String[]
-            { "-c", Integer.toString(CHECK_INTERVAL) });
+        final Parameters parameters = parse("-c", Integer.toString(CHECK_INTERVAL));
         assertEquals(1000 * CHECK_INTERVAL, parameters.getCheckIntervalMillis());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetQuietPeriodLong() throws Exception
     {
         final int QUIET_PERIOD = 6;
-        final Parameters parameters = new Parameters(new String[]
-            { "--quiet-period", Integer.toString(QUIET_PERIOD) });
+        final Parameters parameters = parse("--quiet-period", Integer.toString(QUIET_PERIOD));
         assertEquals(1000 * QUIET_PERIOD, parameters.getQuietPeriodMillis());
-        assert parameters.hasAllMandatoryOptions() == false;
     }
 
     @Test
     public void testSetQuietPeriodShort() throws Exception
     {
         final int QUIET_PERIOD = 17;
-        final Parameters parameters = new Parameters(new String[]
-            { "-q", Integer.toString(QUIET_PERIOD) });
+        final Parameters parameters = parse("-q", Integer.toString(QUIET_PERIOD));
         assertEquals(1000 * QUIET_PERIOD, parameters.getQuietPeriodMillis());
-        assert parameters.hasAllMandatoryOptions() == false;
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testMissingMandatoryOptions() throws Exception
+    {
+        parse(false);
     }
 
     @Test
@@ -226,12 +186,12 @@ public class ParametersTest
         final String LOCAL_DATADIR = ".." + File.separator + "ldata";
         final String LOCAL_TEMPDIR = "l" + File.separator + "tmp";
         final String REMOTE_DATADIR = "rrr";
-        final Parameters parameters = new Parameters(new String[]
-            { "--local-datadir", LOCAL_DATADIR, "--local-tempdir", LOCAL_TEMPDIR, "--remotedir", REMOTE_DATADIR, });
+        final Parameters parameters =
+                parse(false, "--local-datadir", LOCAL_DATADIR, "--local-tempdir", LOCAL_TEMPDIR, "--remotedir",
+                        REMOTE_DATADIR);
         assertEquals(LOCAL_DATADIR, parameters.getLocalDataDirectory().getPath());
         assertEquals(LOCAL_TEMPDIR, parameters.getLocalTemporaryDirectory().getPath());
         assertEquals(REMOTE_DATADIR, parameters.getRemoteDataDirectory().getPath());
-        assert parameters.hasAllMandatoryOptions();
     }
 
     @Test
@@ -244,17 +204,15 @@ public class ParametersTest
         final int CHECK_INTERVAL = 22;
         final int QUIET_PERIOD = 33;
         final Parameters parameters =
-                new Parameters(new String[]
-                    { "--local-datadir", LOCAL_DATADIR, "--local-tempdir", LOCAL_TEMPDIR, "--remotedir",
-                            REMOTE_DATADIR, "--remotehost", REMOTE_HOST, "--check-interval",
-                            Integer.toString(CHECK_INTERVAL), "--quiet-period", Integer.toString(QUIET_PERIOD), });
+                parse(false, "--local-datadir", LOCAL_DATADIR, "--local-tempdir", LOCAL_TEMPDIR, "--remotedir",
+                        REMOTE_DATADIR, "--remotehost", REMOTE_HOST, "--check-interval", Integer
+                                .toString(CHECK_INTERVAL), "--quiet-period", Integer.toString(QUIET_PERIOD));
         assertEquals(LOCAL_DATADIR, parameters.getLocalDataDirectory().getPath());
         assertEquals(LOCAL_TEMPDIR, parameters.getLocalTemporaryDirectory().getPath());
         assertEquals(REMOTE_DATADIR, parameters.getRemoteDataDirectory().getPath());
         assertEquals(REMOTE_HOST, parameters.getRemoteHost());
         assertEquals(1000 * CHECK_INTERVAL, parameters.getCheckIntervalMillis());
         assertEquals(1000 * QUIET_PERIOD, parameters.getQuietPeriodMillis());
-        assert parameters.hasAllMandatoryOptions();
     }
 
 }
-- 
GitLab