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    package org.crsh.lang.impl.groovy.command;
020    
021    import groovy.lang.MissingMethodException;
022    import groovy.lang.MissingPropertyException;
023    import groovy.lang.Script;
024    import org.crsh.lang.impl.groovy.Helper;
025    import org.crsh.shell.impl.command.spi.CommandException;
026    import org.crsh.shell.impl.command.spi.CommandInvoker;
027    import org.crsh.command.InvocationContext;
028    import org.crsh.lang.impl.groovy.closure.PipeLineClosure;
029    import org.crsh.text.RenderPrintWriter;
030    
031    import java.lang.reflect.UndeclaredThrowableException;
032    import java.util.LinkedList;
033    
034    public abstract class GroovyScriptCommand extends Script {
035    
036      /** . */
037      private LinkedList<InvocationContext<?>> stack;
038    
039      /** The current context. */
040      protected InvocationContext context;
041    
042      /** The current output. */
043      protected RenderPrintWriter out;
044    
045      protected GroovyScriptCommand() {
046        this.stack = null;
047      }
048    
049      public final void pushContext(InvocationContext<?> context) throws NullPointerException {
050        if (context == null) {
051          throw new NullPointerException();
052        }
053    
054        //
055        if (stack == null) {
056          stack = new LinkedList<InvocationContext<?>>();
057        }
058    
059        // Save current context (is null the first time)
060        stack.addLast(this.context);
061    
062        // Set new context
063        this.context = context;
064        this.out = context.getWriter();
065      }
066    
067      public final InvocationContext<?> popContext() {
068        if (stack == null || stack.isEmpty()) {
069          throw new IllegalStateException("Cannot pop a context anymore from the stack");
070        }
071        InvocationContext context = this.context;
072        this.context = stack.removeLast();
073        this.out = this.context != null ? this.context.getWriter() : null;
074        return context;
075      }
076    
077      public final void execute(String s) throws Exception {
078        InvocationContext<?> context = peekContext();
079        try {
080          CommandInvoker invoker = context.resolve(s);
081          invoker.invoke(context);
082        }
083        catch (CommandException e) {
084          Throwable cause = e.getCause();
085          if (cause instanceof Exception) {
086            throw (Exception)cause;
087          } else if (cause instanceof Error) {
088            throw (Error)cause;
089          } else {
090            throw new UndeclaredThrowableException(cause);
091          }
092        }
093      }
094    
095      public final InvocationContext<?> peekContext() {
096        return (InvocationContext<?>)context;
097      }
098    
099      @Override
100      public final Object invokeMethod(String name, Object args) {
101    
102        //
103        try {
104          return super.invokeMethod(name, args);
105        }
106        catch (MissingMethodException missing) {
107          return Helper.invokeMethod(context, name, args, missing);
108        }
109      }
110    
111      @Override
112      public final Object getProperty(String property) {
113        if ("out".equals(property)) {
114          return ((InvocationContext<?>)context).getWriter();
115        } else if ("context".equals(property)) {
116          return context;
117        } else {
118          PipeLineClosure ret = Helper.resolveProperty(context, property);
119          if (ret != null) {
120            return ret;
121          }
122          try {
123            return super.getProperty(property);
124          }
125          catch (MissingPropertyException e) {
126            return null;
127          }
128        }
129      }
130    }