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 020package org.crsh.lang.groovy.command; 021 022import groovy.lang.Closure; 023import groovy.lang.GroovyObject; 024import groovy.lang.GroovyRuntimeException; 025import groovy.lang.MetaClass; 026import groovy.lang.MissingMethodException; 027import groovy.lang.MissingPropertyException; 028import org.codehaus.groovy.runtime.InvokerHelper; 029import org.codehaus.groovy.runtime.InvokerInvocationException; 030import org.crsh.cli.impl.descriptor.IntrospectionException; 031import org.crsh.command.BaseCommand; 032import org.crsh.shell.impl.command.spi.CommandCreationException; 033import org.crsh.command.InvocationContext; 034import org.crsh.command.ScriptException; 035import org.crsh.shell.impl.command.spi.ShellCommand; 036import org.crsh.lang.groovy.closure.PipeLineClosure; 037import org.crsh.lang.groovy.closure.PipeLineInvoker; 038import org.crsh.shell.impl.command.CRaSH; 039 040import java.io.IOException; 041import java.lang.reflect.UndeclaredThrowableException; 042 043public abstract class GroovyCommand extends BaseCommand implements GroovyObject { 044 045 // never persist the MetaClass 046 private transient MetaClass metaClass; 047 048 protected GroovyCommand() throws IntrospectionException { 049 this.metaClass = InvokerHelper.getMetaClass(this.getClass()); 050 } 051 052 @Override 053 public UndeclaredThrowableException toScript(Throwable cause) { 054 if (cause instanceof groovy.util.ScriptException) { 055 cause = unwrap((groovy.util.ScriptException)cause); 056 } 057 return super.toScript(cause); 058 } 059 060 public static ScriptException unwrap(groovy.util.ScriptException cause) { 061 // Special handling for groovy.util.ScriptException 062 // which may be thrown by scripts because it is imported by default 063 // by groovy imports 064 String msg = cause.getMessage(); 065 ScriptException translated; 066 if (msg != null) { 067 translated = new ScriptException(msg); 068 } else { 069 translated = new ScriptException(); 070 } 071 translated.setStackTrace(cause.getStackTrace()); 072 return translated; 073 } 074 075 public static ScriptException unwrap(Throwable cause) { 076 if (cause instanceof ScriptException) { 077 return (ScriptException)cause; 078 } if (cause instanceof groovy.util.ScriptException) { 079 return unwrap((groovy.util.ScriptException)cause); 080 } else { 081 return new ScriptException(cause); 082 } 083 } 084 085 public final Object invokeMethod(String name, Object args) { 086 try { 087 return getMetaClass().invokeMethod(this, name, args); 088 } 089 catch (MissingMethodException missing) { 090 if (context instanceof InvocationContext) { 091 CRaSH crash = (CRaSH)context.getSession().get("crash"); 092 if (crash != null) { 093 ShellCommand<?> cmd; 094 try { 095 cmd = crash.getCommand(name); 096 } 097 catch (CommandCreationException ce) { 098 throw new InvokerInvocationException(ce); 099 } 100 if (cmd != null) { 101 InvocationContext<Object> ic = (InvocationContext<Object>)peekContext(); 102 PipeLineClosure closure = new PipeLineClosure(ic, name, cmd); 103 PipeLineInvoker evaluation = closure.bind(args); 104 try { 105 evaluation.invoke(ic); 106 return null; 107 } 108 catch (IOException e) { 109 throw new GroovyRuntimeException(e); 110 } 111 catch (UndeclaredThrowableException e) { 112 throw new GroovyRuntimeException(e.getCause()); 113 } 114 } 115 } 116 } 117 118 // 119 Object o = context.getSession().get(name); 120 if (o instanceof Closure) { 121 Closure closure = (Closure)o; 122 if (args instanceof Object[]) { 123 Object[] array = (Object[])args; 124 if (array.length == 0) { 125 return closure.call(); 126 } else { 127 return closure.call(array); 128 } 129 } else { 130 return closure.call(args); 131 } 132 } else { 133 throw missing; 134 } 135 } 136 } 137 138 public final Object getProperty(String property) { 139 if (context instanceof InvocationContext<?>) { 140 CRaSH crash = (CRaSH)context.getSession().get("crash"); 141 if (crash != null) { 142 try { 143 ShellCommand<?> cmd = crash.getCommand(property); 144 if (cmd != null) { 145 InvocationContext<Object> ic = (InvocationContext<Object>)peekContext(); 146 return new PipeLineClosure(ic, property, cmd); 147 } 148 } catch (CommandCreationException e) { 149 throw new InvokerInvocationException(e); 150 } 151 } 152 } 153 154 // 155 try { 156 return getMetaClass().getProperty(this, property); 157 } 158 catch (MissingPropertyException e) { 159 return context.getSession().get(property); 160 } 161 } 162 163 public final void setProperty(String property, Object newValue) { 164 try { 165 getMetaClass().setProperty(this, property, newValue); 166 } 167 catch (MissingPropertyException e) { 168 context.getSession().put(property, newValue); 169 } 170 } 171 172 public MetaClass getMetaClass() { 173 if (metaClass == null) { 174 metaClass = InvokerHelper.getMetaClass(getClass()); 175 } 176 return metaClass; 177 } 178 179 public void setMetaClass(MetaClass metaClass) { 180 this.metaClass = metaClass; 181 } 182}