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.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.List; 031 import java.util.Map; 032 033 public class CommandClosure extends Closure { 034 035 /** . */ 036 protected HashMap<String, Object> options; 037 038 /** . */ 039 protected ArrayList<Object> args; 040 041 public CommandClosure(Object owner) { 042 super(owner); 043 044 // 045 this.options = null; 046 this.args = null; 047 } 048 049 static Object[] unwrapArgs(Object arguments) { 050 if (arguments == null) { 051 return MetaClassHelper.EMPTY_ARRAY; 052 } else if (arguments instanceof Tuple) { 053 Tuple tuple = (Tuple) arguments; 054 return tuple.toArray(); 055 } else if (arguments instanceof Object[]) { 056 return (Object[])arguments; 057 } else { 058 return new Object[]{arguments}; 059 } 060 } 061 062 @Override 063 public Object invokeMethod(String name, Object args) { 064 try { 065 return super.invokeMethod(name, args); 066 } 067 catch (MissingMethodException e) { 068 if ("with".equals(name)) { 069 Object[] array = unwrapArgs(args); 070 if (array.length == 0) { 071 return this; 072 } else if (array[0] instanceof Map) { 073 Map options = (Map)array[0]; 074 if( array.length > 1) { 075 return options(options, Arrays.copyOfRange(array, 1, array.length)); 076 } else { 077 return options(options, null); 078 } 079 } else { 080 return options(null, array); 081 } 082 } else { 083 throw e; 084 } 085 } 086 } 087 088 private CommandClosure options(Map<?, ?> options, Object[] arguments) { 089 CommandClosure ret; 090 if (this instanceof MethodDispatcher) { 091 ret = new MethodDispatcher(((MethodDispatcher)this).dispatcher, ((MethodDispatcher)this).name); 092 } else { 093 ret = new ClassDispatcher(((ClassDispatcher)this).command, ((ClassDispatcher)this).owner); 094 } 095 096 // We merge options 097 if (options != null && options.size() > 0) { 098 if (this.options == null) { 099 ret.options = new HashMap<String, Object>(); 100 } else { 101 ret.options = new HashMap<String, Object>(this.options); 102 } 103 for (Map.Entry<?, ?> arg : options.entrySet()) { 104 ret.options.put(arg.getKey().toString(), arg.getValue()); 105 } 106 } 107 108 // We replace arguments 109 if (arguments != null) { 110 ret.args = new ArrayList<Object>(Arrays.asList(arguments)); 111 } 112 113 // 114 return ret; 115 } 116 }