PageRenderTime 35ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/shell/core/src/main/java/org/crsh/command/ClassDispatcher.java

https://github.com/nscavell/crash
Java | 214 lines | 156 code | 23 blank | 35 comment | 31 complexity | 29540405af5e52066c50e4b717232837 MD5 | raw file
  1. /*
  2. * Copyright (C) 2012 eXo Platform SAS.
  3. *
  4. * This is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation; either version 2.1 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this software; if not, write to the Free
  16. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  17. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  18. */
  19. package org.crsh.command;
  20. import groovy.lang.Closure;
  21. import groovy.lang.MissingMethodException;
  22. import groovy.lang.MissingPropertyException;
  23. import org.codehaus.groovy.runtime.InvokerInvocationException;
  24. import org.crsh.io.Consumer;
  25. import org.crsh.io.ProducerContext;
  26. import java.io.IOException;
  27. import java.util.ArrayList;
  28. import java.util.Collections;
  29. import java.util.HashMap;
  30. import java.util.List;
  31. import java.util.Map;
  32. final class ClassDispatcher extends CommandClosure {
  33. /** . */
  34. final Object owner;
  35. /** . */
  36. final ShellCommand command;
  37. ClassDispatcher(ShellCommand command, Object owner) {
  38. super(new Object());
  39. //
  40. this.command = command;
  41. this.owner = owner;
  42. }
  43. @Override
  44. public Object getProperty(String property) {
  45. try {
  46. return super.getProperty(property);
  47. }
  48. catch (MissingPropertyException e) {
  49. return new MethodDispatcher(this, property);
  50. }
  51. }
  52. @Override
  53. public Object invokeMethod(String name, Object args) {
  54. try {
  55. return super.invokeMethod(name, args);
  56. }
  57. catch (MissingMethodException e) {
  58. return dispatch(name, unwrapArgs(args));
  59. }
  60. }
  61. /**
  62. * Closure invocation.
  63. *
  64. * @param arguments the closure arguments
  65. */
  66. public Object call(Object[] arguments) {
  67. return dispatch("", arguments);
  68. }
  69. Object dispatch(String methodName, Object[] arguments) {
  70. PipeCommandProxy pipe = resolvePipe(methodName, arguments);
  71. //
  72. try {
  73. pipe.fire();
  74. pipe.close();
  75. return null;
  76. }
  77. catch (ScriptException e) {
  78. Throwable cause = e.getCause();
  79. if (cause != null) {
  80. throw new InvokerInvocationException(cause);
  81. } else {
  82. throw e;
  83. }
  84. }
  85. }
  86. private PipeCommandProxy<?, Object> resolvePipe(String name, Object[] args) {
  87. final Closure closure;
  88. int to = args.length;
  89. if (to > 0 && args[to - 1] instanceof Closure) {
  90. closure = (Closure)args[--to];
  91. } else {
  92. closure = null;
  93. }
  94. //
  95. Map<String, Object> invokerOptions = this.options != null ? this.options : Collections.<String, Object>emptyMap();
  96. List<Object> invokerArgs = this.args != null ? this.args : Collections.emptyList();
  97. //
  98. if (to > 0) {
  99. Object first = args[0];
  100. int from;
  101. if (first instanceof Map<?, ?>) {
  102. from = 1;
  103. Map<?, ?> options = (Map<?, ?>)first;
  104. if (options.size() > 0) {
  105. invokerOptions = new HashMap<String, Object>(invokerOptions);
  106. for (Map.Entry<?, ?> option : options.entrySet()) {
  107. String optionName = option.getKey().toString();
  108. Object optionValue = option.getValue();
  109. invokerOptions.put(optionName, optionValue);
  110. }
  111. }
  112. } else {
  113. from = 0;
  114. }
  115. if (from < to) {
  116. invokerArgs = new ArrayList<Object>(invokerArgs);
  117. while (from < to) {
  118. Object o = args[from++];
  119. if (o != null) {
  120. invokerArgs.add(o);
  121. }
  122. }
  123. }
  124. }
  125. //
  126. CommandInvoker<Void, Void> invoker = (CommandInvoker<Void, Void>)command.resolveInvoker(name, invokerOptions, invokerArgs);
  127. //
  128. InvocationContext context;
  129. if (owner instanceof CRaSHCommand) {
  130. context = ((CRaSHCommand)owner).peekContext();
  131. } else if (owner instanceof GroovyScriptCommand) {
  132. context = (InvocationContext)((GroovyScriptCommand)owner).peekContext();
  133. } else {
  134. throw new UnsupportedOperationException("todo");
  135. }
  136. //
  137. Consumer producer;
  138. if (closure != null) {
  139. CommandInvoker producerPipe;
  140. if (closure instanceof MethodDispatcher) {
  141. MethodDispatcher commandClosure = (MethodDispatcher)closure;
  142. producerPipe = commandClosure.dispatcher.resolvePipe(commandClosure.name, new Object[0]);
  143. } else if (closure instanceof ClassDispatcher) {
  144. ClassDispatcher dispatcherClosure = (ClassDispatcher)closure;
  145. producerPipe = dispatcherClosure.resolvePipe(name, new Object[0]);
  146. } else {
  147. // That's the type we cast to
  148. Class[] pt = closure.getParameterTypes();
  149. final Class type;
  150. if (pt.length > 0) {
  151. type = pt[0];
  152. } else {
  153. type = Void.class;
  154. }
  155. //
  156. producerPipe = new CommandInvoker() {
  157. public Class getProducedType() {
  158. return Void.class;
  159. }
  160. public Class getConsumedType() {
  161. return type;
  162. }
  163. public void setSession(CommandContext session) {
  164. }
  165. public void setPiped(boolean piped) {
  166. }
  167. public void open(ProducerContext context) {
  168. }
  169. public void close() {
  170. }
  171. public void provide(Object element) throws IOException {
  172. if (type.isInstance(element)) {
  173. closure.call(element);
  174. }
  175. }
  176. public void flush() throws IOException {
  177. }
  178. };
  179. }
  180. producerPipe.setPiped(true);
  181. producer = producerPipe;
  182. } else {
  183. producer = context;
  184. }
  185. //
  186. InnerInvocationContext inner = new InnerInvocationContext(context, producer);
  187. PipeCommandProxy pipe = new PipeCommandProxy(inner, invoker, producer);
  188. pipe.setSession(context);
  189. return pipe;
  190. }
  191. }