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(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 = this.context;
069 this.context = stack.removeLast();
070 this.out = this.context != null ? 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 }