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.boot; 019 020import com.mashape.unirest.http.Unirest; 021import io.stallion.dataAccess.db.SqlCheckNeedsMigrationAction; 022import io.stallion.dataAccess.db.SqlGenerationAction; 023import io.stallion.dataAccess.db.SqlMigrationAction; 024import io.stallion.exceptions.CommandException; 025import io.stallion.exceptions.UsageException; 026import io.stallion.plugins.PluginRegistry; 027import io.stallion.plugins.StallionJavaPlugin; 028import io.stallion.plugins.PluginTestsRunAction; 029import io.stallion.secrets.SecretsAction; 030import io.stallion.secrets.SecretsDecryptAction; 031import io.stallion.services.Log; 032import io.stallion.tools.ExportToHtml; 033import io.stallion.tools.ScriptExecBase; 034import io.stallion.users.UserAdder; 035import io.stallion.utils.Literals; 036import org.apache.commons.lang3.StringUtils; 037import org.kohsuke.args4j.CmdLineException; 038import org.kohsuke.args4j.CmdLineParser; 039 040import java.io.File; 041import java.io.IOException; 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.List; 045import java.util.logging.Level; 046 047import static io.stallion.utils.Literals.*; 048 049/** 050 * Does the main work of booting up Stallion, and executing one of the boot actions. 051 */ 052public class Booter { 053 054 private static final List<StallionRunAction> builtinActions = Literals.list( 055 new StallionServer(), 056 new UserAdder(), 057 new PluginTestsRunAction(), 058 new ScriptExecBase(), 059 new NewProjectBuilder(), 060 new NewDraftPageAction(), 061 //new NewJavaPluginRunAction(), 062 new ExportToHtml(), 063 new SecretsAction(), 064 new SqlMigrationAction(), 065 new SqlCheckNeedsMigrationAction(), 066 new SqlGenerationAction(), 067 new InteractiveJavascriptRunAction(), 068 new ForceTaskAction(), 069 new SecretsDecryptAction() 070 ); 071 072 public void boot(String[] args) throws Exception { 073 boot(args, new StallionJavaPlugin[]{}); 074 } 075 076 public void boot(String[] args, StallionJavaPlugin[] plugins) throws Exception { 077 078 // Load the plugin jars, to get additional actions 079 String targetPath = new File(".").getAbsolutePath(); 080 for(String arg: args) { 081 if (arg.startsWith("-targetPath=")) { 082 targetPath = StringUtils.split(arg, "=", 2)[1]; 083 } 084 } 085 if (!new File(targetPath).isDirectory() || empty(targetPath) || targetPath.equals("/") || targetPath.equals("/.")) { 086 throw new CommandException("You ran stallion with the target path " + targetPath + " but that is not a valid folder."); 087 } 088 089 PluginRegistry.loadWithJavaPlugins(targetPath, plugins); 090 List<StallionRunAction> actions = new ArrayList(builtinActions); 091 actions.addAll(PluginRegistry.instance().getAllPluginDefinedStallionRunActions()); 092 093 // Load the action executor 094 StallionRunAction action = null; 095 for(StallionRunAction anAction: actions) { 096 if (empty(anAction.getActionName())) { 097 throw new UsageException("The action class " + anAction.getClass().getName() + " has an empty action name"); 098 } 099 if (args.length > 0 && anAction.getActionName().equals(args[0])) { 100 action = anAction; 101 } 102 } 103 if (action == null) { 104 String msg = "\n\nError! You must pass in a valid action as the first command line argument. For example:\n\n" + 105 ">stallion serve -port=8090 -targetPath=~/my-stallion-site\n"; 106 if (args.length > 0) { 107 msg += "\n\nYou passed in '" + args[0] + "', which is not a valid action.\n"; 108 } 109 msg += "\nAllowed actions are:\n\n"; 110 for (StallionRunAction anAction: actions) { 111 //Log.warn("Action: {0} {1} {2}", action, action.getActionName(), action.getHelp()); 112 msg += anAction.getActionName() + " - " + anAction.getHelp() + "\n"; 113 } 114 msg += "\n\nYou can get help about an action by running: >stallion <action> help\n\n"; 115 System.err.println(msg); 116 System.exit(1); 117 } 118 119 120 121 // Load the command line options 122 CommandOptionsBase options = action.newCommandOptions(); 123 124 CmdLineParser parser = new CmdLineParser(options); 125 126 if (args.length > 1 && "help".equals(args[1])) { 127 System.out.println(action.getActionName() + " - " + action.getHelp() + "\n\n"); 128 System.out.println("\n\nOptions for command " + action.getActionName() + "\n\n"); 129 parser.printUsage(System.out); 130 System.exit(0); 131 } 132 133 try { 134 parser.parseArgument(args); 135 } catch( CmdLineException e ) { 136 System.err.println("\n\nError!\n\n" + e.getMessage()); 137 System.err.println("\n\nAllowed options: \n"); 138 parser.printUsage(System.err); 139 System.err.println("\n"); 140 System.exit(1); 141 } 142 143 options.setExtraPlugins(Arrays.asList(plugins)); 144 145 if (!empty(options.getLogLevel())) { 146 try { 147 Log.setLogLevel(Level.parse(options.getLogLevel())); 148 } catch (IllegalArgumentException e) { 149 System.err.println("\nError! Invalid log level: " + options.getLogLevel() + "\n\n" + CommandOptionsBase.ALLOWED_LEVELS); 150 System.exit(1); 151 } 152 } 153 if (empty(options.getTargetPath())) { 154 options.setTargetPath(new File(".").getAbsolutePath()); 155 } 156 157 // Shutdown hooks 158 Thread shutDownHookThread = new Thread() { 159 public void run() { 160 try { 161 Unirest.shutdown(); 162 } catch (IOException e) { 163 e.printStackTrace(); 164 } 165 } 166 }; 167 shutDownHookThread.setName("stallion-shutdown-hook"); 168 Runtime.getRuntime().addShutdownHook(shutDownHookThread); 169 170 171 // Execute the action 172 action.loadApp(options); 173 action.execute(options); 174 175 176 177 if (!AppContextLoader.isNull()) { 178 AppContextLoader.shutdown(); 179 } 180 181 } 182}