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.impl.script; 020 021 import org.crsh.cli.descriptor.CommandDescriptor; 022 import org.crsh.cli.descriptor.Description; 023 import org.crsh.cli.impl.SyntaxException; 024 import org.crsh.cli.impl.descriptor.IntrospectionException; 025 import org.crsh.cli.impl.invocation.InvocationException; 026 import org.crsh.cli.impl.invocation.InvocationMatch; 027 import org.crsh.cli.spi.Completer; 028 import org.crsh.command.CommandContext; 029 import org.crsh.command.RuntimeContext; 030 import org.crsh.lang.spi.CommandResolution; 031 import org.crsh.lang.spi.Compiler; 032 import org.crsh.lang.spi.ReplResponse; 033 import org.crsh.shell.ErrorKind; 034 import org.crsh.shell.impl.command.ShellSession; 035 import org.crsh.shell.impl.command.spi.Command; 036 import org.crsh.shell.impl.command.spi.CommandException; 037 import org.crsh.shell.impl.command.spi.CommandInvoker; 038 import org.crsh.shell.impl.command.spi.CommandMatch; 039 040 import java.io.BufferedReader; 041 import java.io.ByteArrayInputStream; 042 import java.io.IOException; 043 import java.io.InputStreamReader; 044 import java.lang.reflect.Type; 045 import java.util.Collections; 046 import java.util.Map; 047 import java.util.Set; 048 049 /** 050 * @author Julien Viet 051 */ 052 public class ScriptCompiler implements Compiler { 053 054 /** . */ 055 private static final Set<String> EXT = Collections.singleton("script"); 056 057 /** . */ 058 static final ScriptCompiler instance = new ScriptCompiler(); 059 060 public static ScriptCompiler getInstance() { 061 return instance; 062 } 063 064 @Override 065 public Set<String> getExtensions() { 066 return EXT; 067 } 068 069 @Override 070 public CommandResolution compileCommand(final String name, final byte[] source) throws CommandException, NullPointerException { 071 072 return new CommandResolution() { 073 @Override 074 public String getDescription() { 075 return ""; 076 } 077 @Override 078 public Command<?> getCommand() throws CommandException { 079 080 // 081 final CommandDescriptor<Object> descriptor; 082 try { 083 descriptor = new CommandDescriptor<Object>(name, new Description()) { 084 @Override 085 public CommandDescriptor<Object> getOwner() { 086 return null; 087 } 088 089 @Override 090 public Map<String, ? extends CommandDescriptor<Object>> getSubordinates() { 091 return Collections.emptyMap(); 092 } 093 094 @Override 095 public org.crsh.cli.impl.invocation.CommandInvoker<Object, ?> getInvoker(InvocationMatch<Object> match) { 096 return new org.crsh.cli.impl.invocation.CommandInvoker<Object, Object>(match) { 097 @Override 098 public Class<Object> getReturnType() { 099 return Object.class; 100 } 101 102 @Override 103 public Type getGenericReturnType() { 104 return Object.class; 105 } 106 107 @Override 108 public Object invoke(Object command) throws InvocationException, SyntaxException { 109 throw new UnsupportedOperationException("Not used"); 110 } 111 }; 112 } 113 }; 114 } 115 catch (IntrospectionException e) { 116 throw new CommandException(ErrorKind.SYNTAX, "Script " + name + " failed unexpectedly", e); 117 } 118 119 return new Command<Object>() { 120 @Override 121 public CommandDescriptor<Object> getDescriptor() { 122 return descriptor; 123 } 124 @Override 125 protected Completer getCompleter(RuntimeContext context) { 126 return null; 127 } 128 @Override 129 protected CommandMatch<?, ?> resolve(InvocationMatch<Object> match) { 130 return new CommandMatch<Void, Object>() { 131 @Override 132 public CommandInvoker<Void, Object> getInvoker() { 133 return new CommandInvoker<Void, Object>() { 134 135 /** . */ 136 private CommandContext<?> consumer; 137 138 @Override 139 public void provide(Void element) throws IOException { 140 } 141 142 @Override 143 public Class<Void> getConsumedType() { 144 return Void.class; 145 } 146 147 @Override 148 public void flush() throws IOException { 149 consumer.flush(); 150 } 151 152 @Override 153 public Class<Object> getProducedType() { 154 return Object.class; 155 } 156 157 @Override 158 public void open(CommandContext<? super Object> consumer) { 159 this.consumer = consumer; 160 } 161 162 @Override 163 public void close() throws IOException, CommandException { 164 165 // Execute sequentially the script 166 BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(source))); 167 168 // A bit nasty but well it's ok 169 ShellSession session = (ShellSession)consumer.getSession(); 170 171 while (true) { 172 String request = reader.readLine(); 173 if (request == null) { 174 break; 175 } 176 request = request.trim(); 177 if (request.length() == 0) { 178 break; 179 } 180 ReplResponse response = ScriptRepl.getInstance().eval(session, request); 181 if (response instanceof ReplResponse.Response) { 182 ReplResponse.Response shellResponse = (ReplResponse.Response)response; 183 Exception ex = new Exception("Was not expecting response " + shellResponse.response); 184 throw new CommandException(ErrorKind.EVALUATION, "Failure when evaluating '" + request + "' in script " + name, ex); 185 } else if (response instanceof ReplResponse.Invoke) { 186 ReplResponse.Invoke invokeResponse = (ReplResponse.Invoke)response; 187 CommandInvoker invoker = invokeResponse.invoker; 188 invoker.invoke(consumer); 189 } 190 } 191 192 // 193 try { 194 consumer.close(); 195 } 196 catch (Exception e) { 197 // ? 198 } 199 200 // 201 this.consumer = null; 202 } 203 }; 204 } 205 @Override 206 public Class<Object> getProducedType() { 207 return Object.class; 208 } 209 @Override 210 public Class<Void> getConsumedType() { 211 return Void.class; 212 } 213 }; 214 } 215 }; 216 } 217 }; 218 } 219 220 @Override 221 public String doCallBack(ShellSession session, String name, String defaultValue) { 222 return null; 223 } 224 }