001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.tools; 019 020import io.stallion.boot.AppContextLoader; 021import io.stallion.boot.StallionRunAction; 022import io.stallion.exceptions.CommandException; 023import io.stallion.plugins.StallionJavaPlugin; 024import io.stallion.plugins.PluginRegistry; 025import io.stallion.plugins.javascript.*; 026import io.stallion.utils.json.JSON; 027import org.apache.commons.io.IOUtils; 028import org.apache.commons.lang3.exception.ExceptionUtils; 029 030 031import javax.script.ScriptEngine; 032import javax.script.ScriptEngineManager; 033import java.io.File; 034import java.net.URL; 035import java.util.List; 036import java.util.Scanner; 037 038import static io.stallion.utils.Literals.*; 039import static io.stallion.Context.*; 040 041 042public class ScriptExecBase implements StallionRunAction<ScriptOptions> { 043 044 045 046 @Override 047 public ScriptOptions newCommandOptions() { 048 return new ScriptOptions(); 049 } 050 051 @Override 052 public String getActionName() { 053 return "exec-script"; 054 } 055 056 @Override 057 public String getHelp() { 058 return "Executes a jython or javascript script."; 059 } 060 061 @Override 062 public void loadApp(ScriptOptions options) { 063 064 AppContextLoader.loadCompletelyForScript(options); 065 } 066 067 @Override 068 public void execute(ScriptOptions options) throws Exception { 069 if (options.getArguments().size() < 2) { 070 throw new CommandException("You must pass in the script that you want to execute as a positional argument"); 071 } 072 String scriptArg = options.getArguments().get(1); 073 074 String plugin = ""; 075 String path = scriptArg; 076 String[] parts = scriptArg.split(":"); 077 String scriptPath = ""; 078 if (parts.length > 1) { 079 plugin = parts[0]; 080 path = parts[1]; 081 } 082 083 URL url = null; 084 String folder = null; 085 if (!empty(plugin)) { 086 if ("stallion".equals(plugin)) { 087 url = getClass().getResource(path); 088 } 089 if (url == null && PluginRegistry.instance() != null) { 090 StallionJavaPlugin booter = PluginRegistry.instance().getJavaPluginByName().getOrDefault(plugin, null); 091 if (booter != null) { 092 url = booter.getClass().getResource(path); 093 } 094 } 095 if (url == null) { 096 if (plugin.equals("js")) { 097 String fullPath = settings().getTargetFolder() + "/js" + path; 098 File file = new File(fullPath); 099 if (file.isFile()) { 100 url = new URL("file:" + fullPath); 101 scriptPath = file.getParent(); 102 folder = settings().getTargetFolder() + "/js"; 103 } 104 105 } else { 106 107 String fullPath = settings().getTargetFolder() + "/plugins/" + plugin + path; 108 File file = new File(fullPath); 109 if (file.isFile()) { 110 url = new URL("file:" + fullPath); 111 scriptPath = file.getParent(); 112 folder = settings().getTargetFolder() + "/plugins/" + plugin; 113 } 114 } 115 } 116 } else { 117 url = new URL("file:" + settings().getTargetFolder() + "/js/" + path); 118 folder = settings().getTargetFolder() + "/js/"; 119 } 120 if (url == null) { 121 throw new CommandException("Could not find matching script for '" + scriptArg + "' in any folder or jar resource."); 122 } 123 if (empty(folder)) { 124 folder = new File(url.toString()).getParent(); 125 } 126 String source = IOUtils.toString(url, UTF8); 127 List<String> args = list(path); 128 if (options.getArguments().size() > 2) { 129 args.addAll(options.getArguments().subList(2, options.getArguments().size())); 130 } 131 if (path.endsWith(".js")) { 132 executeJavascript(source, url, scriptPath, folder, args, plugin); 133 } else { 134 throw new CommandException("Unknown extension for path. Supported extensions are .py for jython and .js for javascript. Path was: " + path); 135 } 136 } 137 138 public void executeJavascript(String source, URL url, String scriptPath, String folder, List<String> args, String plugin) throws Exception { 139 ScriptEngine scriptEngine = null; 140 if (plugin.equals("js") || plugin.equals("stallion")) { 141 JsPluginEngine pluginEngine = PluginRegistry.instance().getEngine("main.js"); 142 if (pluginEngine != null) { 143 scriptEngine = pluginEngine.getScriptEngine(); 144 } 145 } else if (!empty(plugin)) { 146 JsPluginEngine pluginEngine = PluginRegistry.instance().getEngine(plugin); 147 if (pluginEngine != null) { 148 scriptEngine = pluginEngine.getScriptEngine(); 149 } 150 } 151 if (scriptEngine == null) { 152 ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); 153 scriptEngine = scriptEngineManager.getEngineByName("nashorn"); 154 scriptEngine.eval(IOUtils.toString(getClass().getResource("/jslib/jvm-npm.js"), UTF8)); 155 scriptEngine.eval(IOUtils.toString(getClass().getResource("/jslib/stallion_shared.js"), UTF8)); 156 String nodePath = folder + "/node_modules"; 157 scriptEngine.eval("require.NODE_PATH = \"" + nodePath + "\""); 158 scriptEngine.put("myContext", new SandboxedContext(plugin, Sandbox.allPermissions(), new JsPluginSettings())); 159 } 160 if (true || newCommandOptions().isDevMode()) { 161 Scanner in = new Scanner(System.in); 162 while (true) { 163 source = IOUtils.toString(url, UTF8); 164 try { 165 scriptEngine.eval("load(" + JSON.stringify(map(val("script", source), val("name", url.toString()))) + ");"); 166 //scriptEngine.eval(IOUtils.) 167 } catch(Exception e) { 168 ExceptionUtils.printRootCauseStackTrace(e); 169 } finally { 170 171 } 172 System.out.println("Hit enter to re-run the script. Type quit and hit enter to stop."); 173 String line = in.nextLine().trim(); 174 if (empty(line)) { 175 continue; 176 } else { 177 break; 178 } 179 } 180 } else { 181 scriptEngine.eval(source); 182 } 183 184 } 185 186 187}