001    package org.hackystat.sensor.xmldata.option;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import org.hackystat.sensor.xmldata.XmlDataController;
007    
008    /**
009     * The class that handles the options created by the XmlDataController. This
010     * class stores, validates, and executes the options.
011     * @author aito
012     * 
013     */
014    public class OptionHandler {
015      /** The list of options managed by this class. */
016      private List<Option> options = new ArrayList<Option>();
017      /** The controller which loads this handler. */
018      private XmlDataController controller = null;
019    
020      /**
021       * Constructs this handler with the specified controller.
022       * @param controller the specified controller.
023       */
024      public OptionHandler(XmlDataController controller) {
025        this.controller = controller;
026      }
027    
028      /**
029       * Adds the specified option to this class. Note that no error checking is
030       * performed by this method. Options may be tested by invoking isOptionsValid.
031       * @param option the specified option to add.
032       */
033      public void addOption(Option option) {
034        this.options.add(option);
035      }
036    
037      /** Clears all of the options managed by this class. */
038      public void clearOptions() {
039        this.options.clear();
040      }
041    
042      /**
043       * Returns true if all of the options stored in this class are valid and
044       * contain no duplicate options. If an option is invalid, an error message is
045       * fired by the invalid option.
046       * @return true if the option is valid, false if not.
047       */
048      public boolean isOptionsValid() {
049        // First, iterate through each option and validate their parameters.
050        List<String> optionNames = new ArrayList<String>();
051        for (Option option : this.options) {
052          if (option == null || !option.isValid()) {
053            return false;
054          }
055          optionNames.add(option.getName());
056        }
057    
058        // Second, iterate through all names to see if each option is unique.
059        for (String optionName : optionNames) {
060          boolean hasName = false;
061          for (Option option : this.options) {
062            if (option.getName().equals(optionName)) {
063              if (hasName) {
064                return false;
065              }
066              hasName = true;
067            }
068          }
069        }
070        return true;
071      }
072    
073      /**
074       * Returns true if this class contains all of the required options.
075       * @return true if all required options exist.
076       */
077      public boolean hasRequiredOptions() {
078        String[] requiredOptionNames = new String[] { FileOption.OPTION_NAME,
079            ArgListOption.OPTION_NAME, MigrationOption.OPTION_NAME };
080    
081        // Test if more than one required option was used.
082        boolean hasRequiredOption = false;
083        for (String optionName : requiredOptionNames) {
084          if (this.hasOptionWithName(optionName)) {
085            if (hasRequiredOption) {
086              String msg = "Only one option, -file, -argList, or -migration, "
087                  + "can be used at the same time.";
088              this.controller.fireMessage(msg);
089              return false;
090            }
091            hasRequiredOption = true;
092          }
093        }
094        
095        // If only one option was used, return true.
096        if (hasRequiredOption) {
097          return true;
098        }
099        String msg = "The -file <files...> or the -argList <argList.txt> " + "option is required.";
100        this.controller.fireMessage(msg);
101        return false;
102      }
103    
104      /**
105       * Returns true if this class contains the option with the specified name.
106       * @param name the name to search for.
107       * @return true if the name was found, false if not.
108       */
109      private boolean hasOptionWithName(String name) {
110        for (Option option : this.options) {
111          if (option.getName().equals(name)) {
112            return true;
113          }
114        }
115        return false;
116      }
117    
118      /**
119       * A helper method that returns true if the specified string is an option.
120       * @param argument the string to test.
121       * @return true if the string is an option, false if not.
122       */
123      public boolean isOption(String argument) {
124        if (argument != null && argument.length() > 0) {
125          String firstChar = argument.substring(0, 1);
126          if ("-".equals(firstChar)) {
127            return true;
128          }
129        }
130        return false;
131      }
132    
133      /** Processes all of the options wrapped in this object. */
134      public void processOptions() {
135        List<Option> options = new ArrayList<Option>(this.options);
136        for (Option option : options) {
137          if (option != null) {
138            option.process();
139          }
140        }
141      }
142    
143      /**
144       * Executes all of the stored options that have operations to execute on their
145       * wrapped parameters.
146       */
147      public void execute() {
148        List<Option> options = new ArrayList<Option>(this.options);
149        for (Option option : options) {
150          option.execute();
151        }
152      }
153    }