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.command;
021    
022    import groovy.lang.Closure;
023    import groovy.lang.GroovyObjectSupport;
024    import groovy.lang.MissingMethodException;
025    import groovy.lang.MissingPropertyException;
026    import org.codehaus.groovy.runtime.InvokerInvocationException;
027    import org.crsh.shell.impl.command.CRaSH;
028    import org.crsh.text.RenderPrintWriter;
029    
030    import java.util.LinkedList;
031    
032    public abstract class GroovyCommand extends GroovyObjectSupport {
033    
034      /** . */
035      private LinkedList<InvocationContext<?>> stack;
036    
037      /** The current context. */
038      protected RuntimeContext context;
039    
040      /** The current output. */
041      protected RenderPrintWriter out;
042    
043      protected GroovyCommand() {
044        this.stack = null;
045        this.context = null;
046      }
047    
048      public final void pushContext(InvocationContext<?> context) throws NullPointerException {
049        if (context == null) {
050          throw new NullPointerException();
051        }
052    
053        //
054        if (stack == null) {
055          stack = new LinkedList<InvocationContext<?>>();
056        }
057    
058        // Save current context (is null the first time)
059        stack.addLast((InvocationContext<?>)this.context);
060    
061        // Set new context
062        this.context = context;
063        this.out = context.getWriter();
064      }
065    
066      public final InvocationContext<?> popContext() {
067        if (stack != null && stack.size() > 0) {
068          InvocationContext context = (InvocationContext)this.context;
069          this.context = stack.removeLast();
070          this.out = this.context != null ? ((InvocationContext)this.context).getWriter() : null;
071          return context;
072        } else {
073          return null;
074        }
075      }
076    
077      public final InvocationContext<?> peekContext() {
078        return (InvocationContext<?>)context;
079      }
080    
081      @Override
082      public final Object invokeMethod(String name, Object args) {
083        try {
084          return super.invokeMethod(name, args);
085        }
086        catch (MissingMethodException e) {
087          if (context instanceof InvocationContext) {
088            CRaSH crash = (CRaSH)context.getSession().get("crash");
089            if (crash != null) {
090              ShellCommand cmd;
091              try {
092                cmd = crash.getCommand(name);
093              }
094              catch (NoSuchCommandException ce) {
095                throw new InvokerInvocationException(ce);
096              }
097              if (cmd != null) {
098                // Should we use null instead of "" ?
099                return new ClassDispatcher(cmd, this).dispatch("", CommandClosure.unwrapArgs(args));
100              }
101            }
102          }
103    
104          //
105          Object o = context.getSession().get(name);
106          if (o instanceof Closure) {
107            Closure closure = (Closure)o;
108            if (args instanceof Object[]) {
109              Object[] array = (Object[])args;
110              if (array.length == 0) {
111                return closure.call();
112              } else {
113                return closure.call(array);
114              }
115            } else {
116              return closure.call(args);
117            }
118          } else {
119            throw e;
120          }
121        }
122      }
123    
124      @Override
125      public final Object getProperty(String property) {
126        if (context instanceof InvocationContext<?>) {
127          CRaSH crash = (CRaSH)context.getSession().get("crash");
128          if (crash != null) {
129            try {
130              ShellCommand cmd = crash.getCommand(property);
131              if (cmd != null) {
132                return new ClassDispatcher(cmd, this);
133              }
134            } catch (NoSuchCommandException e) {
135              throw new InvokerInvocationException(e);
136            }
137          }
138        }
139    
140        //
141        try {
142          return super.getProperty(property);
143        }
144        catch (MissingPropertyException e) {
145          return context.getSession().get(property);
146        }
147      }
148    
149      @Override
150      public final void setProperty(String property, Object newValue) {
151        try {
152          super.setProperty(property, newValue);
153        }
154        catch (MissingPropertyException e) {
155          context.getSession().put(property, newValue);
156        }
157      }
158    }