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