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 }