/* * Copyright 2012 Atteo. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.atteo.moonshine.nashorn_console; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.xml.bind.annotation.XmlRootElement; import org.atteo.moonshine.TopLevelService; import org.atteo.moonshine.services.ServiceInfo; import com.google.inject.Binding; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.PrivateModule; import com.google.inject.spi.DefaultElementVisitor; import com.google.inject.spi.Element; import com.google.inject.spi.PrivateElements; import jline.TerminalFactory; import jline.console.ConsoleReader; /** * Nashorn Console. */ @XmlRootElement(name = "nashorn-console") public class NashornConsole extends TopLevelService { @Override public Module configure() { return new PrivateModule() { @Override protected void configure() { } }; } @Inject private Injector injector; @Inject private List<? extends ServiceInfo> services; public class SimpleInjector { public Object get(String name) { List<Binding<?>> results = new ArrayList<>(); for (Map.Entry<Key<?>, Binding<?>> entry : injector.getParent().getAllBindings().entrySet()) { if (entry.getKey().toString().contains(name)) { results.add(entry.getValue()); } } if (results.isEmpty()) { System.out.println("No matching objects found"); return null; } else if (results.size() > 1) { System.out.println("More than one matching objects found"); return null; } return results.get(0).getProvider().get(); } public Object get(Class<?> klass) { List<Binding<?>> results = new ArrayList<>(); for (Map.Entry<Key<?>, Binding<?>> entry : injector.getParent().getAllBindings().entrySet()) { if (entry.getKey().getTypeLiteral().getType() == klass) { results.add(entry.getValue()); } } if (results.isEmpty()) { System.out.println("No matching objects found"); return null; } else if (results.size() > 1) { System.out.println("More than one matching objects found"); return null; } return results.get(0).getProvider().get(); } private String getBindingsList() { final StringBuilder builder = new StringBuilder(); for (ServiceInfo service : services) { builder.append(service.getName()); builder.append("\n"); for (Element element : service.getElements()) { element.acceptVisitor(new DefaultElementVisitor<Void>() { @Override public <T> Void visit(Binding<T> binding) { builder.append(" "); builder.append(binding.getKey()); builder.append("\n"); return null; } @Override public Void visit(PrivateElements elements) { for (Element element : elements.getElements()) { if (element instanceof Binding<?> && elements.getExposedKeys().contains(((Binding)element).getKey())) { Binding<?> binding = ((Binding)element); builder.append(" "); if (binding.getKey().getAnnotation() != null) { builder.append(binding.getKey().getAnnotation()); builder.append(" "); } builder.append(binding.getKey().getTypeLiteral()); builder.append("\n"); } } return null; } }); } } builder.append("\nUse injector.get(...) to retrieve"); return builder.toString(); } public void list() { System.out.println(getBindingsList()); } @Override public String toString() { return "SimpleInjector (hint: use injector.list())"; } } private class ConsoleThread extends Thread { @Override public void run() { try { System.setProperty("nashorn.args", "-scripting"); ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn"); if (nashorn == null) { throw new RuntimeException("Nashorn Javascript engine not found, this service requires Java 8"); } Bindings bindings = nashorn.createBindings(); bindings.put("injector", new SimpleInjector()); nashorn.setBindings(bindings, ScriptContext.ENGINE_SCOPE); ConsoleReader console = new ConsoleReader(); console.setPrompt("js> "); String line; while (!Thread.currentThread().isInterrupted() && (line = console.readLine()) != null) { try { Object result = nashorn.eval(line); if (result != null) { System.out.println(result); } } catch (ScriptException e) { System.out.println("Error: " + e.getMessage()); } catch (RuntimeException e) { System.out.println("Runtime error: " + e.getMessage()); } } } catch (IOException e) { throw new RuntimeException(e); } finally { try { TerminalFactory.get().restore(); } catch (InterruptedException e) { // First execution of restore() can catch InterruptedException, so let's repeat it try { TerminalFactory.get().restore(); } catch (Exception f) { throw new RuntimeException(f); } } catch (Exception e) { throw new RuntimeException(e); } System.exit(0); } } } private Thread thread = null; @Override public void start() { thread = new ConsoleThread(); thread.start(); } @Override public void stop() { thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }