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 InvocationContext 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.isEmpty()) {
068 throw new IllegalStateException("Cannot pop a context anymore from the stack");
069 }
070 InvocationContext context = (InvocationContext)this.context;
071 this.context = stack.removeLast();
072 this.out = this.context != null ? ((InvocationContext)this.context).getWriter() : null;
073 return context;
074 }
075
076 public final InvocationContext<?> peekContext() {
077 return (InvocationContext<?>)context;
078 }
079
080 @Override
081 public final Object invokeMethod(String name, Object args) {
082 try {
083 return super.invokeMethod(name, args);
084 }
085 catch (MissingMethodException e) {
086 if (context instanceof InvocationContext) {
087 CRaSH crash = (CRaSH)context.getSession().get("crash");
088 if (crash != null) {
089 ShellCommand cmd;
090 try {
091 cmd = crash.getCommand(name);
092 }
093 catch (NoSuchCommandException ce) {
094 throw new InvokerInvocationException(ce);
095 }
096 if (cmd != null) {
097 // Should we use null instead of "" ?
098 return new ClassDispatcher(cmd, this).dispatch("", CommandClosure.unwrapArgs(args));
099 }
100 }
101 }
102
103 //
104 Object o = context.getSession().get(name);
105 if (o instanceof Closure) {
106 Closure closure = (Closure)o;
107 if (args instanceof Object[]) {
108 Object[] array = (Object[])args;
109 if (array.length == 0) {
110 return closure.call();
111 } else {
112 return closure.call(array);
113 }
114 } else {
115 return closure.call(args);
116 }
117 } else {
118 throw e;
119 }
120 }
121 }
122
123 @Override
124 public final Object getProperty(String property) {
125 if (context instanceof InvocationContext<?>) {
126 CRaSH crash = (CRaSH)context.getSession().get("crash");
127 if (crash != null) {
128 try {
129 ShellCommand cmd = crash.getCommand(property);
130 if (cmd != null) {
131 return new ClassDispatcher(cmd, this);
132 }
133 } catch (NoSuchCommandException e) {
134 throw new InvokerInvocationException(e);
135 }
136 }
137 }
138
139 //
140 try {
141 return super.getProperty(property);
142 }
143 catch (MissingPropertyException e) {
144 return context.getSession().get(property);
145 }
146 }
147
148 @Override
149 public final void setProperty(String property, Object newValue) {
150 try {
151 super.setProperty(property, newValue);
152 }
153 catch (MissingPropertyException e) {
154 context.getSession().put(property, newValue);
155 }
156 }
157 }