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 }