001 /*
002 * Copyright (C) 2010 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.shell.impl;
021
022 import org.crsh.command.CommandInvoker;
023 import org.crsh.command.ShellCommand;
024 import org.crsh.shell.ShellResponse;
025 import org.crsh.shell.ShellProcessContext;
026
027 import java.util.ArrayList;
028 import java.util.regex.Pattern;
029
030 /**
031 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
032 * @version $Revision$
033 */
034 abstract class AST {
035
036 abstract Term lastTerm();
037
038 static class Expr extends AST {
039
040 /** . */
041 final Term term;
042
043 /** . */
044 final Expr next;
045
046 Expr(Term term) {
047 this.term = term;
048 this.next = null;
049 }
050
051 Expr(Term term, Expr next) {
052 this.term = term;
053 this.next = next;
054 }
055
056 final CRaSHProcess create(CRaSHSession crash, String request) throws CreateCommandException {
057 term.create(crash);
058 if (next != null) {
059 next.create(crash);
060 }
061 return new CRaSHProcess(crash, request) {
062 @Override
063 ShellResponse doInvoke(ShellProcessContext context) throws InterruptedException {
064 return Expr.this.execute(crash, context, null);
065 }
066 };
067 }
068
069 private void create(CRaSHSession crash) throws CreateCommandException {
070 term.create(crash);
071 if (next != null) {
072 next.create(crash);
073 }
074 }
075
076 protected ShellResponse execute(CRaSHSession crash, ShellProcessContext context, ArrayList consumed) throws InterruptedException {
077
078 // What will be produced by this expression
079 ArrayList produced = new ArrayList();
080
081 //
082 StringBuilder out = new StringBuilder();
083
084 // Iterate over all terms
085 for (Term current = term;current != null;current = current.next) {
086
087 // Build command context
088 InvocationContextImpl ctx;
089 if (current.invoker.getConsumedType() == Void.class) {
090 ctx = new InvocationContextImpl(context, null, crash.attributes);
091 } else {
092 // For now we assume we have compatible consumed/produced types
093 ctx = new InvocationContextImpl(context, consumed, crash.attributes);
094 }
095
096 //
097 try {
098 current.invoker.invoke(ctx);
099 } catch (InterruptedException e) {
100 throw e;
101 } catch (Throwable t) {
102 return ShellResponse.internalError(t);
103 }
104
105 // Append anything that was in the buffer
106 if (ctx.getBuffer() != null) {
107 out.append(ctx.getBuffer().toString());
108 }
109
110 // Append produced if possible
111 if (current.invoker.getProducedType() == Void.class) {
112 // Do nothing
113 } else {
114 produced.addAll(ctx.getProducedItems());
115 }
116 }
117
118 //
119 if (next != null) {
120 return next.execute(crash, context, produced);
121 } else {
122 ShellResponse response;
123 if (out.length() > 0) {
124 response = ShellResponse.display(produced, out.toString());
125 } else {
126 response = ShellResponse.ok(produced);
127 }
128 return response;
129 }
130 }
131
132 @Override
133 Term lastTerm() {
134 if (next != null) {
135 return next.lastTerm();
136 }
137 if (term != null) {
138 return term.lastTerm();
139 }
140 return null;
141 }
142 }
143
144 static class Term extends AST {
145
146 /** . */
147 final String line;
148
149 /** . */
150 final Term next;
151
152 /** . */
153 final String name;
154
155 /** . */
156 final String rest;
157
158 /** . */
159 private ShellCommand command;
160
161 /** . */
162 private CommandInvoker invoker;
163
164 Term(String line) {
165 this(line, null);
166 }
167
168 Term(String line, Term next) {
169
170 Pattern p = Pattern.compile("^\\s*(\\S+)");
171 java.util.regex.Matcher m = p.matcher(line);
172 String name = null;
173 String rest = null;
174 if (m.find()) {
175 name = m.group(1);
176 rest = line.substring(m.end());
177 }
178
179 //
180 this.name = name;
181 this.rest = rest;
182 this.line = line;
183 this.next = next;
184 }
185
186 private void create(CRaSHSession crash) throws CreateCommandException {
187 CommandInvoker invoker = null;
188 if (name != null) {
189 command = crash.getCommand(name);
190 if (command != null) {
191 invoker = command.createInvoker(rest);
192 }
193 }
194
195 //
196 if (invoker == null) {
197 throw new CreateCommandException(ShellResponse.unknownCommand(name));
198 } else {
199 this.invoker = invoker;
200 }
201
202 //
203 if (next != null) {
204 next.create(crash);
205 }
206 }
207
208 String getLine() {
209 return line;
210 }
211
212 @Override
213 Term lastTerm() {
214 if (next != null) {
215 return next.lastTerm();
216 } else {
217 return this;
218 }
219 }
220 }
221 }