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.groovy.command;
020
021 import groovy.lang.GroovyRuntimeException;
022 import groovy.lang.MissingMethodException;
023 import groovy.lang.MissingPropertyException;
024 import groovy.lang.Script;
025 import org.codehaus.groovy.runtime.InvokerInvocationException;
026 import org.crsh.shell.impl.command.spi.CommandCreationException;
027 import org.crsh.shell.impl.command.spi.CommandInvoker;
028 import org.crsh.command.InvocationContext;
029 import org.crsh.command.ScriptException;
030 import org.crsh.shell.impl.command.spi.ShellCommand;
031 import org.crsh.lang.groovy.closure.PipeLineClosure;
032 import org.crsh.lang.groovy.closure.PipeLineInvoker;
033 import org.crsh.shell.impl.command.CRaSH;
034 import org.crsh.text.RenderPrintWriter;
035
036 import java.io.IOException;
037 import java.lang.reflect.UndeclaredThrowableException;
038 import java.util.LinkedList;
039
040 public abstract class GroovyScriptCommand extends Script {
041
042 /** . */
043 private LinkedList<InvocationContext<?>> stack;
044
045 /** The current context. */
046 protected InvocationContext context;
047
048 /** The current output. */
049 protected RenderPrintWriter out;
050
051 protected GroovyScriptCommand() {
052 this.stack = null;
053 }
054
055 public final void pushContext(InvocationContext<?> context) throws NullPointerException {
056 if (context == null) {
057 throw new NullPointerException();
058 }
059
060 //
061 if (stack == null) {
062 stack = new LinkedList<InvocationContext<?>>();
063 }
064
065 // Save current context (is null the first time)
066 stack.addLast((InvocationContext)this.context);
067
068 // Set new context
069 this.context = context;
070 this.out = context.getWriter();
071 }
072
073 public final InvocationContext<?> popContext() {
074 if (stack == null || stack.isEmpty()) {
075 throw new IllegalStateException("Cannot pop a context anymore from the stack");
076 }
077 InvocationContext context = this.context;
078 this.context = stack.removeLast();
079 this.out = this.context != null ? this.context.getWriter() : null;
080 return context;
081 }
082
083 public final void execute(String s) throws ScriptException, IOException {
084 InvocationContext<?> context = peekContext();
085 CommandInvoker invoker = context.resolve(s);
086 invoker.invoke(context);
087 }
088
089 public final InvocationContext<?> peekContext() {
090 return (InvocationContext<?>)context;
091 }
092
093 @Override
094 public final Object invokeMethod(String name, Object args) {
095
096 //
097 try {
098 return super.invokeMethod(name, args);
099 }
100 catch (MissingMethodException missing) {
101 if (context instanceof InvocationContext) {
102 CRaSH crash = (CRaSH)context.getSession().get("crash");
103 if (crash != null) {
104 ShellCommand<?> cmd;
105 try {
106 cmd = crash.getCommand(name);
107 }
108 catch (CommandCreationException ce) {
109 throw new InvokerInvocationException(ce);
110 }
111 if (cmd != null) {
112 InvocationContext<Object> ic = (InvocationContext<Object>)peekContext();
113 PipeLineClosure closure = new PipeLineClosure(ic, name, cmd);
114 PipeLineInvoker evaluation = closure.bind(args);
115 try {
116 evaluation.invoke(ic);
117 return null;
118 }
119 catch (IOException e) {
120 throw new GroovyRuntimeException(e);
121 }
122 catch (UndeclaredThrowableException e) {
123 throw new GroovyRuntimeException(e.getCause());
124 }
125 }
126 }
127 }
128
129 //
130 throw missing;
131 }
132 }
133
134 @Override
135 public final Object getProperty(String property) {
136 if ("out".equals(property)) {
137 if (context instanceof InvocationContext<?>) {
138 return ((InvocationContext<?>)context).getWriter();
139 } else {
140 return null;
141 }
142 } else if ("context".equals(property)) {
143 return context;
144 } else {
145 if (context instanceof InvocationContext<?>) {
146 CRaSH crash = (CRaSH)context.getSession().get("crash");
147 if (crash != null) {
148 try {
149 ShellCommand<?> cmd = crash.getCommand(property);
150 if (cmd != null) {
151 InvocationContext<Object> ic = (InvocationContext<Object>)peekContext();
152 return new PipeLineClosure(ic, property, cmd);
153 }
154 } catch (CommandCreationException e) {
155 throw new InvokerInvocationException(e);
156 }
157 }
158 }
159
160 //
161 try {
162 return super.getProperty(property);
163 }
164 catch (MissingPropertyException e) {
165 return null;
166 }
167 }
168 }
169 }