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.groovy;
021
022import groovy.lang.GroovyObject;
023import groovy.lang.MetaClass;
024import groovy.lang.MissingMethodException;
025import groovy.lang.MissingPropertyException;
026import org.codehaus.groovy.runtime.InvokerHelper;
027import org.crsh.command.BaseCommand;
028import org.crsh.lang.impl.groovy.Helper;
029import org.crsh.command.InvocationContext;
030import org.crsh.command.ScriptException;
031import org.crsh.lang.impl.groovy.closure.PipeLineClosure;
032
033/**
034 * The base command for Groovy class based commands.
035 */
036public 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}