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.groovy;
021    
022    import groovy.lang.GroovyObject;
023    import groovy.lang.MetaClass;
024    import groovy.lang.MissingMethodException;
025    import groovy.lang.MissingPropertyException;
026    import org.codehaus.groovy.runtime.InvokerHelper;
027    import org.crsh.command.BaseCommand;
028    import org.crsh.lang.impl.groovy.Helper;
029    import org.crsh.command.InvocationContext;
030    import org.crsh.command.ScriptException;
031    import org.crsh.lang.impl.groovy.closure.PipeLineClosure;
032    
033    /**
034     * The base command for Groovy class based commands.
035     */
036    public abstract class GroovyCommand extends BaseCommand implements GroovyObject {
037    
038      // never persist the MetaClass
039      private transient MetaClass metaClass;
040    
041      protected GroovyCommand() {
042        this.metaClass = InvokerHelper.getMetaClass(this.getClass());
043      }
044    
045      public static ScriptException unwrap(groovy.util.ScriptException cause) {
046        // Special handling for groovy.util.ScriptException
047        // which may be thrown by scripts because it is imported by default
048        // by groovy imports
049        String msg = cause.getMessage();
050        ScriptException translated;
051        if (msg != null) {
052          translated = new ScriptException(msg);
053        } else {
054          translated = new ScriptException();
055        }
056        translated.setStackTrace(cause.getStackTrace());
057        return translated;
058      }
059    
060      public static Exception unwrap(Exception cause) {
061        if (cause instanceof groovy.util.ScriptException) {
062          return unwrap((groovy.util.ScriptException)cause);
063        } else {
064          return cause;
065        }
066      }
067    
068      public final Object invokeMethod(String name, Object args) {
069        try {
070          return getMetaClass().invokeMethod(this, name, args);
071        }
072        catch (MissingMethodException missing) {
073          return Helper.invokeMethod(context, name, args, missing);
074        }
075      }
076    
077      public final Object getProperty(String property) {
078        if (context instanceof InvocationContext<?>) {
079          PipeLineClosure ret = Helper.resolveProperty((InvocationContext)context, property);
080          if (ret != null) {
081            return ret;
082          }
083        }
084        try {
085          return getMetaClass().getProperty(this, property);
086        }
087        catch (MissingPropertyException e) {
088          return context.getSession().get(property);
089        }
090      }
091    
092      public final void setProperty(String property, Object newValue) {
093        try {
094          getMetaClass().setProperty(this, property, newValue);
095        }
096        catch (MissingPropertyException e) {
097          context.getSession().put(property, newValue);
098        }
099      }
100    
101      public MetaClass getMetaClass() {
102        if (metaClass == null) {
103          metaClass = InvokerHelper.getMetaClass(getClass());
104        }
105        return metaClass;
106      }
107    
108      public void setMetaClass(MetaClass metaClass) {
109        this.metaClass = metaClass;
110      }
111    }