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