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 io.stallion.exceptions.CommandException; 021import io.stallion.fileSystem.BaseWatchEventHandler; 022import io.stallion.fileSystem.FileSystemWatcherRunner; 023import io.stallion.plugins.StallionJavaPlugin; 024import io.stallion.services.Log; 025import org.apache.commons.lang3.ArrayUtils; 026import org.apache.commons.lang3.exception.ExceptionUtils; 027 028 029import java.io.Console; 030import java.io.File; 031import java.util.ArrayList; 032import java.util.List; 033import java.util.logging.Level; 034 035/** 036 * Contains main method that gets run when stallion is executed. The entrypoint into the Stallion service. 037 */ 038public class MainRunner 039 040{ 041 /** 042 * Run Stallion 043 * @param args - passed in via the command line 044 * @throws Exception 045 */ 046 public static void main( String[] args ) throws Exception { 047 mainWithPlugins(args); 048 } 049 050 /** 051 * Run main, and manually register plugins, rather than have plugins loaded via the /jars folder. 052 * 053 * This method is used in plugin development, when we do not have a pre-built jar of the plugin available. 054 * 055 * @param args 056 * @param plugins 057 * @throws Exception 058 */ 059 public static void mainWithPlugins(String[] args, StallionJavaPlugin...plugins) throws Exception { 060 try { 061 if (ArrayUtils.contains(args, "-autoReload")) { 062 runWithAutoReload(args, plugins); 063 } else { 064 doMain(args, plugins); 065 } 066 } catch (CommandException ex) { 067 System.err.println("\n\nError! \n\n" + ex.getMessage() + "\n\n"); 068 if (Log.getLogLevel().intValue() <= Level.FINE.intValue()) { 069 Log.exception(ex, "Command exception"); 070 } 071 } 072 } 073 074 /** 075 * Actually boot and run Stallion 076 * 077 * @param args 078 * @param plugins 079 * @throws Exception 080 */ 081 public static void doMain(String[] args, StallionJavaPlugin[] plugins) throws Exception { 082 new Booter().boot(args, plugins); 083 } 084 085 086 087 088 private static boolean isDebugRunner = false; 089 private static boolean doReload = false; 090 private static FileSystemWatcherRunner watcher = null; 091 private static Thread watcherThread = null; 092 private static StallionServer server = null; 093 094 /** 095 * Runs the main Stallion service in auto-reload mode, which means that if a configuration file, 096 * or a server-side javascript file, or a plugin file is touched, the entire application context 097 * will reload and all server-side javascript will be re-processed. Use this when developing 098 * to avoid having to manually restart every time you change a file. 099 * 100 * 101 * @param args 102 * @param plugins 103 * @throws Exception 104 */ 105 public static void runWithAutoReload( String[] args, StallionJavaPlugin[] plugins ) throws Exception { 106 isDebugRunner = true; 107 108 Console console = System.console(); 109 while (true) { 110 Log.info("(re)start in debug reloading mode."); 111 try { 112 reboot(args, plugins); 113 if (doReload) { 114 doReload = false; 115 continue; 116 } 117 System.out.println("Interrupted. Type q to quit, any other key to reboot."); 118 String input = console.readLine(); 119 if (input.startsWith("q")) { 120 break; 121 } 122 } catch (Exception e) { 123 ExceptionUtils.printRootCauseStackTrace(e); 124 System.out.println("Other exception. Type q to quit, any other key to reboot."); 125 String input = console.readLine(); 126 if (input.startsWith("q")) { 127 break; 128 } 129 } 130 } 131 Log.info("Shutting down javascript and conf file watcher."); 132 if (watcher != null) { 133 watcher.setShouldRun(false); 134 } 135 watcherThread.interrupt(); 136 watcherThread.join(); 137 System.out.println("Exiting."); 138 System.exit(0); 139 } 140 141 static void setupWatchersIfDebugMode(String targetPath) { 142 if (isIsDebugRunner()) { 143 setupWatchers(targetPath); 144 } else { 145 return; 146 } 147 } 148 149 static void setupWatchers(String targetPath) { 150 List<File> directories = new ArrayList<>(); 151 directories.add(new File(targetPath + "/js")); 152 directories.add(new File(targetPath + "/conf")); 153 if (new File(targetPath + "/plugins").isDirectory()) { 154 for(File file: new File(targetPath + "/plugins").listFiles()) { 155 if (file.isDirectory()) { 156 directories.add(file); 157 } 158 } 159 } 160 watcher = new FileSystemWatcherRunner(); 161 162 163 for (File dir: directories) { 164 Log.info("Watch folder {0}", dir.toString()); 165 if (!dir.isDirectory()) { 166 continue; 167 } 168 BaseWatchEventHandler handler = new DebugFileChangeHandler() 169 .setWatchTree(true) 170 .setWatchedFolder(dir.getAbsolutePath()); 171 if (dir.getAbsolutePath().endsWith("/conf")) { 172 handler.setExtension(".toml"); 173 } else { 174 handler.setExtension(".js"); 175 } 176 watcher.registerWatcher(handler); 177 } 178 179 watcherThread = new Thread(watcher); 180 watcherThread.setName("stallion-dev-mode-source-code-watcher"); 181 watcherThread.start(); 182 183 } 184 185 186 /** 187 * Reboot the application context. 188 * 189 * @param args 190 * @param plugins 191 * @throws Exception 192 */ 193 public static void reboot(String[] args, StallionJavaPlugin[] plugins) throws Exception { 194 AppContextLoader.shutdown(); 195 doMain(args, plugins); 196 } 197 198 static boolean isDoReload() { 199 return doReload; 200 } 201 static void setDoReload(boolean doReload) { 202 MainRunner.doReload = doReload; 203 } 204 205 static boolean isIsDebugRunner() { 206 return isDebugRunner; 207 } 208 209 static void setIsDebugRunner(boolean isDebugRunner) { 210 MainRunner.isDebugRunner = isDebugRunner; 211 } 212 213}