/* * Copyright (C) 2012 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.crsh.lang.impl.script; import org.crsh.cli.descriptor.CommandDescriptor; import org.crsh.cli.descriptor.Description; import org.crsh.cli.impl.SyntaxException; import org.crsh.cli.impl.descriptor.IntrospectionException; import org.crsh.cli.impl.invocation.InvocationException; import org.crsh.cli.impl.invocation.InvocationMatch; import org.crsh.cli.spi.Completer; import org.crsh.command.CommandContext; import org.crsh.command.RuntimeContext; import org.crsh.lang.spi.CommandResolution; import org.crsh.lang.spi.Compiler; import org.crsh.lang.spi.ReplResponse; import org.crsh.shell.ErrorKind; import org.crsh.shell.impl.command.ShellSession; import org.crsh.shell.impl.command.spi.Command; import org.crsh.shell.impl.command.spi.CommandException; import org.crsh.shell.impl.command.spi.CommandInvoker; import org.crsh.shell.impl.command.spi.CommandMatch; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.Collections; import java.util.Map; import java.util.Set; /** * @author Julien Viet */ public class ScriptCompiler implements Compiler { /** . */ private static final Set<String> EXT = Collections.singleton("script"); /** . */ static final ScriptCompiler instance = new ScriptCompiler(); public static ScriptCompiler getInstance() { return instance; } @Override public Set<String> getExtensions() { return EXT; } @Override public CommandResolution compileCommand(final String name, final byte[] source) throws CommandException, NullPointerException { return new CommandResolution() { @Override public String getDescription() { return ""; } @Override public Command<?> getCommand() throws CommandException { // final CommandDescriptor<Object> descriptor; try { descriptor = new CommandDescriptor<Object>(name, new Description()) { @Override public CommandDescriptor<Object> getOwner() { return null; } @Override public Map<String, ? extends CommandDescriptor<Object>> getSubordinates() { return Collections.emptyMap(); } @Override public org.crsh.cli.impl.invocation.CommandInvoker<Object, ?> getInvoker(InvocationMatch<Object> match) { return new org.crsh.cli.impl.invocation.CommandInvoker<Object, Object>(match) { @Override public Class<Object> getReturnType() { return Object.class; } @Override public Type getGenericReturnType() { return Object.class; } @Override public Object invoke(Object command) throws InvocationException, SyntaxException { throw new UnsupportedOperationException("Not used"); } }; } }; } catch (IntrospectionException e) { throw new CommandException(ErrorKind.SYNTAX, "Script " + name + " failed unexpectedly", e); } return new Command<Object>() { @Override public CommandDescriptor<Object> getDescriptor() { return descriptor; } @Override protected Completer getCompleter(RuntimeContext context) { return null; } @Override protected CommandMatch<?, ?> resolve(InvocationMatch<Object> match) { return new CommandMatch<Void, Object>() { @Override public CommandInvoker<Void, Object> getInvoker() { return new CommandInvoker<Void, Object>() { /** . */ private CommandContext<?> consumer; @Override public void provide(Void element) throws IOException { } @Override public Class<Void> getConsumedType() { return Void.class; } @Override public void flush() throws IOException { consumer.flush(); } @Override public Class<Object> getProducedType() { return Object.class; } @Override public void open(CommandContext<? super Object> consumer) { this.consumer = consumer; } @Override public void close() throws IOException, CommandException { // Execute sequentially the script BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(source))); // A bit nasty but well it's ok ShellSession session = (ShellSession)consumer.getSession(); while (true) { String request = reader.readLine(); if (request == null) { break; } request = request.trim(); if (request.length() == 0) { break; } ReplResponse response = ScriptRepl.getInstance().eval(session, request); if (response instanceof ReplResponse.Response) { ReplResponse.Response shellResponse = (ReplResponse.Response)response; Exception ex = new Exception("Was not expecting response " + shellResponse.response); throw new CommandException(ErrorKind.EVALUATION, "Failure when evaluating '" + request + "' in script " + name, ex); } else if (response instanceof ReplResponse.Invoke) { ReplResponse.Invoke invokeResponse = (ReplResponse.Invoke)response; CommandInvoker invoker = invokeResponse.invoker; invoker.invoke(consumer); } } // try { consumer.close(); } catch (Exception e) { // ? } // this.consumer = null; } }; } @Override public Class<Object> getProducedType() { return Object.class; } @Override public Class<Void> getConsumedType() { return Void.class; } }; } }; } }; } @Override public String doCallBack(ShellSession session, String name, String defaultValue) { return null; } }