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 }