001    package org.crsh.command;
002    
003    import groovy.lang.Closure;
004    import groovy.lang.MissingMethodException;
005    import groovy.lang.MissingPropertyException;
006    import groovy.lang.Tuple;
007    import org.codehaus.groovy.runtime.InvokerInvocationException;
008    import org.codehaus.groovy.runtime.MetaClassHelper;
009    import org.crsh.cmdline.Delimiter;
010    
011    import java.io.IOException;
012    import java.util.Map;
013    
014    /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
015    final class CommandDispatcher extends Closure {
016    
017      /** . */
018      final InvocationContext ic;
019    
020      /** . */
021      final ShellCommand command;
022    
023      CommandDispatcher(ShellCommand command, InvocationContext ic) {
024        super(new Object());
025    
026        //
027        this.command = command;
028        this.ic = ic;
029      }
030    
031      @Override
032      public Object getProperty(String property) {
033        try {
034          return super.getProperty(property);
035        }
036        catch (MissingPropertyException e) {
037          return new CommandClosure(this, property);
038        }
039      }
040    
041      @Override
042      public Object invokeMethod(String name, Object args) {
043        try {
044          return super.invokeMethod(name, args);
045        }
046        catch (MissingMethodException e) {
047          return dispatch(name, args);
048        }
049      }
050    
051      /**
052       * Closure invocation.
053       *
054       * @param arguments the closure arguments
055       */
056      public Object call(Object[] arguments) {
057        return dispatch("", arguments);
058      }
059    
060      Object dispatch(String methodName, Object arguments) {
061        if (arguments == null) {
062          return dispatch(methodName, MetaClassHelper.EMPTY_ARRAY);
063        } else if (arguments instanceof Tuple) {
064          Tuple tuple = (Tuple) arguments;
065          return dispatch(methodName, tuple.toArray());
066        } else if (arguments instanceof Object[]) {
067          return dispatch(methodName, (Object[])arguments);
068        } else {
069          return dispatch(methodName, new Object[]{arguments});
070        }
071      }
072    
073      Object dispatch(String name, Object[] args) {
074        StringBuilder line = new StringBuilder();
075        if (name.length() > 0) {
076          line.append(name).append(" ");
077        }
078    
079        //
080        Closure closure;
081        int to = args.length;
082        if (to > 0 && args[to - 1] instanceof Closure) {
083          closure = (Closure)args[--to];
084        } else {
085          closure = null;
086        }
087    
088        //
089        if (to > 0) {
090          Object first = args[0];
091          int from;
092          try {
093            if (first instanceof Map<?, ?>) {
094              from = 1;
095              Map<?, ?> options = (Map<?, ?>)first;
096              for (Map.Entry<?, ?> option : options.entrySet()) {
097                String optionName = option.getKey().toString();
098                Object optionValue = option.getValue();
099    
100                boolean printName;
101                boolean printValue;
102                if (optionValue instanceof Boolean) {
103                  printName = Boolean.TRUE.equals(optionValue);
104                  printValue = false;
105                } else {
106                  printName = true;
107                  printValue = true;
108                }
109    
110                //
111                if (printName) {
112                  line.append(" ");
113                  line.append(optionName.length() == 1 ? "-" : "--");
114                  line.append(optionName);
115                  if (printValue) {
116                    line.append(" ");
117                    line.append("\"");
118                    Delimiter.DOUBLE_QUOTE.escape(optionValue.toString(), line);
119                    line.append("\"");
120                  }
121                }
122              }
123            } else {
124              from = 0;
125            }
126            while (from < to) {
127              Object o = args[from++];
128              line.append(" ");
129              line.append("\"");
130              Delimiter.DOUBLE_QUOTE.escape(o.toString(), line);
131              line.append("\"");
132            }
133          }
134          catch (IOException e) {
135            throw new AssertionError(e);
136          }
137        }
138    
139        //
140        try {
141          CommandInvoker<Void, Void> invoker = (CommandInvoker<Void, Void>)command.createInvoker(line.toString());
142          Class producedType = invoker.getProducedType();
143          InnerInvocationContext inc = new InnerInvocationContext(ic, producedType, closure != null);
144          invoker.invoke(inc);
145    
146          //
147          if (closure != null) {
148            for (Object o : inc.products) {
149              closure.call(o);
150            }
151          }
152    
153          //
154          return null;
155        }
156        catch (ScriptException e) {
157          Throwable cause = e.getCause();
158          if (cause != null) {
159            throw new InvokerInvocationException(cause);
160          } else {
161            throw e;
162          }
163        }
164      }
165    }