001 /*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019
020 package org.crsh.lang.groovy.command;
021
022 import groovy.lang.Closure;
023 import groovy.lang.MissingMethodException;
024 import groovy.lang.Tuple;
025 import org.codehaus.groovy.runtime.MetaClassHelper;
026
027 import java.util.ArrayList;
028 import java.util.Arrays;
029 import java.util.HashMap;
030 import java.util.Map;
031
032 public class CommandClosure extends Closure {
033
034 /** . */
035 protected HashMap<String, Object> options;
036
037 /** . */
038 protected ArrayList<Object> args;
039
040 public CommandClosure(Object owner) {
041 super(owner);
042
043 //
044 this.options = null;
045 this.args = null;
046 }
047
048 static Object[] unwrapArgs(Object arguments) {
049 if (arguments == null) {
050 return MetaClassHelper.EMPTY_ARRAY;
051 } else if (arguments instanceof Tuple) {
052 Tuple tuple = (Tuple) arguments;
053 return tuple.toArray();
054 } else if (arguments instanceof Object[]) {
055 return (Object[])arguments;
056 } else {
057 return new Object[]{arguments};
058 }
059 }
060
061 @Override
062 public Object invokeMethod(String name, Object args) {
063 try {
064 return super.invokeMethod(name, args);
065 }
066 catch (MissingMethodException e) {
067 if ("with".equals(name)) {
068 Object[] array = unwrapArgs(args);
069 if (array.length == 0) {
070 return this;
071 } else if (array[0] instanceof Map) {
072 Map options = (Map)array[0];
073 if( array.length > 1) {
074 return options(options, Arrays.copyOfRange(array, 1, array.length));
075 } else {
076 return options(options, null);
077 }
078 } else {
079 return options(null, array);
080 }
081 } else {
082 throw e;
083 }
084 }
085 }
086
087 private CommandClosure options(Map<?, ?> options, Object[] arguments) {
088 CommandClosure ret;
089 if (this instanceof MethodDispatcher) {
090 ret = new MethodDispatcher(((MethodDispatcher)this).dispatcher, ((MethodDispatcher)this).name);
091 } else {
092 ret = new ClassDispatcher(((ClassDispatcher)this).command, ((ClassDispatcher)this).owner);
093 }
094
095 // We merge options
096 if (options != null && options.size() > 0) {
097 if (this.options == null) {
098 ret.options = new HashMap<String, Object>();
099 } else {
100 ret.options = new HashMap<String, Object>(this.options);
101 }
102 for (Map.Entry<?, ?> arg : options.entrySet()) {
103 ret.options.put(arg.getKey().toString(), arg.getValue());
104 }
105 }
106
107 // We replace arguments
108 if (arguments != null) {
109 ret.args = new ArrayList<Object>(Arrays.asList(arguments));
110 }
111
112 //
113 return ret;
114 }
115 }