001package com.ganteater.ae; 002 003import java.io.ByteArrayOutputStream; 004import java.io.File; 005import java.io.IOException; 006import java.io.PrintStream; 007import java.net.ServerSocket; 008import java.util.Enumeration; 009import java.util.List; 010import java.util.Map; 011import java.util.Properties; 012 013import javax.net.ssl.SSLServerSocketFactory; 014import javax.swing.JOptionPane; 015 016import org.apache.commons.cli.CommandLine; 017import org.apache.commons.cli.CommandLineParser; 018import org.apache.commons.cli.DefaultParser; 019import org.apache.commons.cli.HelpFormatter; 020import org.apache.commons.cli.Option; 021import org.apache.commons.cli.Options; 022import org.apache.commons.cli.ParseException; 023import org.apache.commons.lang.ObjectUtils; 024import org.apache.commons.lang.exception.ExceptionUtils; 025import org.apache.commons.lang3.StringUtils; 026 027import com.ganteater.ae.processor.BaseProcessor; 028import com.ganteater.ae.processor.Processor; 029import com.ganteater.ae.processor.TaskProcessorThread; 030import com.ganteater.ae.util.AEUtils; 031import com.ganteater.ae.util.xml.easyparser.Node; 032 033/** 034 * @author victort 035 * @version 1.0, 29-Jul-2005 036 */ 037public class RecipeRunner implements RecipeListener { 038 039 private static final String WELCOME_MESSAGE = "Giant anteater looking for recipes ..."; 040 041 public static int STATUS_SUCCESS = 0; 042 043 public static int STATUS_FAILED = 1; 044 045 public static String RUN_MODE_APPLICATION = "Application"; 046 047 public static String RUN_MODE_WEB = "Web"; 048 049 protected Node fConfigNode; 050 051 private Map<String, Object> fSystemVariables; 052 053 private Processor processor = null; 054 055 private String fNameTask; 056 057 private String fRunMode = RUN_MODE_APPLICATION; 058 059 private int status = STATUS_SUCCESS; 060 061 protected AEManager manager; 062 063 private Node fTaskNode; 064 065 private ILogger log; 066 067 public RecipeRunner(AEManager manager) { 068 this(manager, manager.getConfigNode(), manager.getSystemVariables()); 069 } 070 071 public RecipeRunner(AEManager manager, Node aConfigNode, Map<String, Object> aSystemVariables) { 072 fConfigNode = aConfigNode; 073 this.manager = manager; 074 fSystemVariables = aSystemVariables; 075 this.manager.addRunner(this); 076 } 077 078 public Node getTaskNode() { 079 return fTaskNode; 080 } 081 082 public void setProcessor(Processor processor) { 083 this.processor = processor; 084 } 085 086 public Processor getProcessor() { 087 return processor; 088 } 089 090 public Processor makeRecipe(String file) throws CommandException { 091 Processor newProcessor = new BaseProcessor(fSystemVariables, fConfigNode, manager.getStartDir()); 092 newProcessor.setTestListener(this); 093 newProcessor.setLogger(log); 094 setProcessor(newProcessor); 095 getProcessor().make(file); 096 return newProcessor; 097 } 098 099 public void runTest(Node testNode[]) throws Exception { 100 setTaskNode(testNode[0]); 101 processor = new BaseProcessor(fConfigNode, fSystemVariables, this, manager.getStartDir(), getLogger(), 102 getProcessor()); 103 processor.runNodes(testNode); 104 endTask(false); 105 } 106 107 public void setTaskNode(Node object) { 108 fTaskNode = object; 109 } 110 111 public void criticalError(CommandException aThrowable, Processor processor) { 112 this.endTask(true); 113 setStatus(STATUS_FAILED); 114 StringBuilder taskTrace = new StringBuilder(aThrowable.getTaskTrace() + "\n\n"); 115 Throwable rootCause = ExceptionUtils.getRootCause(aThrowable); 116 processor.getLogger().error(taskTrace.toString(), (Throwable) ObjectUtils.defaultIfNull(rootCause, aThrowable)); 117 } 118 119 public void checkFailure(CommandException e, Processor processor) { 120 setStatus(STATUS_FAILED); 121 processor.getLogger().error("Check Failure. Message: " + e.getMessage() + "\n" + e.getTaskTrace()); 122 this.endTask(true); 123 getLogger().debug(e); 124 } 125 126 public void startTask(String aNameTask) { 127 setTestName(aNameTask); 128 } 129 130 public void setTestName(String aNameTask) { 131 fNameTask = aNameTask; 132 } 133 134 public void setProgress(String aCurrentTaskName, long aMaxTags, long aCurrTags, boolean aErrorState) { 135 } 136 137 public AEManager getManager() { 138 return manager; 139 } 140 141 public void endTask(boolean aErrorState) { 142 manager.removeRunner(this); 143 } 144 145 public void changeVariable(String aAttribut, Object aValue) { 146 } 147 148 public void startCommand(int i) { 149 } 150 151 public void startChildProcess(TaskProcessorThread aMaxTestRunnable) { 152 } 153 154 public void stopChildProcess(TaskProcessorThread aMaxTestRunnable) { 155 } 156 157 public Node getConfigNode() { 158 return fConfigNode; 159 } 160 161 public void stopTest() { 162 if (processor != null) { 163 processor.stop(); 164 } 165 } 166 167 public String getTitle() { 168 return fNameTask; 169 } 170 171 public String inputFile(File aDefaultFile, Processor taskProcessor) { 172 return aDefaultFile.getAbsolutePath(); 173 } 174 175 public void aboutTest(String theTaskName, Node aCurrentAction) { 176 177 } 178 179 public void setRunMode(String aMode) { 180 fRunMode = aMode; 181 } 182 183 public String getRunMode() { 184 return fRunMode; 185 } 186 187 public void exceptionIgnored(Throwable e) { 188 List<Node> callTaskTrace = getProcessor().getLocalTaskTrace(); 189 ByteArrayOutputStream stack = new ByteArrayOutputStream(); 190 e.printStackTrace(new PrintStream(stack)); 191 getLogger().debug("Exception ignored. Recipe: " + StringUtils.join(callTaskTrace, " - ")); 192 } 193 194 public ILogger getLogger() { 195 return log; 196 } 197 198 public void setStatus(int status) { 199 this.status = status; 200 } 201 202 public int getStatus() { 203 return status; 204 } 205 206 public ServerSocket createPort(int thePort, String aDescription) throws IOException { 207 ServerSocket serverSocket = null; 208 209 if (thePort < 0) { 210 SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 211 serverSocket = factory.createServerSocket(-thePort); 212 } else { 213 serverSocket = new ServerSocket(thePort); 214 } 215 216 return serverSocket; 217 } 218 219 public void closePort(int thePort) { 220 } 221 222 public void errorInformation(Processor processor, Throwable e, Node command) throws CommandException { 223 setStatus(STATUS_FAILED); 224 if (e instanceof CommandException) { 225 throw (CommandException) e; 226 } else { 227 throw new CommandException(e, processor, command); 228 } 229 } 230 231 public void outToView(Processor processor, Properties aProperties, Object aTheValue) { 232 } 233 234 public void runCommandView(Properties params) throws Throwable { 235 } 236 237 public ILogger createLog(String aName, boolean mainLog) { 238 return log; 239 } 240 241 public void pause() { 242 } 243 244 public void resume() { 245 } 246 247 @Override 248 public boolean isNotifyMe() { 249 return false; 250 } 251 252 public Map<String, Object> getSystemVariables() { 253 return fSystemVariables; 254 } 255 256 public void setLog(ILogger log) { 257 this.log = log; 258 } 259 260 public static void main(String... args) throws IOException { 261 262 Options options = new Options(); 263 Option helpOption = new Option("h", "help", false, "Displays help information for usage."); 264 Option versionOption = new Option("v", "version", false, 265 "Use this option to check which version of Anteater you are running, ensuring compatibility with your recipes and plugins."); 266 Option commandPortOption = new Option("c", "commandPort", true, 267 "Specifies the port for command communication."); 268 Option configNameOption = new Option("n", "configName", true, "Specifies the configuration name to use."); 269 Option commandServerPortOption = new Option("s", "serverPort", true, 270 "Specifies the port for the command server."); 271 Option consoleOption = new Option("con", "console", false, "Force application to run in console mode"); 272 273 options.addOption(helpOption); 274 options.addOption(versionOption); 275 options.addOption(commandPortOption); 276 options.addOption(configNameOption); 277 options.addOption(commandServerPortOption); 278 options.addOption(consoleOption); 279 280 CommandLineParser parser = new DefaultParser(); 281 HelpFormatter formatter = new HelpFormatter(); 282 283 try { 284 CommandLine cmd = parser.parse(options, args); 285 286 if (cmd.hasOption(versionOption)) { 287 System.out.println("Anteater Version: " + AEUtils.getPrjProperty("application.version")); 288 return; 289 } 290 291 if (cmd.hasOption(helpOption)) { 292 help(options, formatter); 293 return; 294 } 295 296 if (!cmd.hasOption(consoleOption) && System.console() == null) { 297 JOptionPane.showMessageDialog(null, 298 "ae.jar is a command line tool and should be run in a terminal or command prompt."); 299 System.exit(1); 300 } 301 302 if (cmd.hasOption(commandPortOption)) { 303 int port = Integer.parseInt(cmd.getOptionValue(commandPortOption)); 304 String[] commands = cmd.getArgs(); 305 CommandServer.sendCommand(port, commands); 306 System.exit(0); 307 } 308 309 if (cmd.hasOption(configNameOption)) { 310 String configName = cmd.getOptionValue(configNameOption); 311 System.setProperty(ConfigConstants.CONFIG_NAME_SYS_PRPERTY_NAME, configName); 312 } 313 314 AEWorkspace workspace = new AEWorkspace(); 315 try { 316 if (cmd.hasOption(commandServerPortOption)) { 317 int port = Integer.parseInt(cmd.getOptionValue(commandServerPortOption)); 318 CommandServer.openCommandPort(workspace, port); 319 } 320 321 String[] recipes = cmd.getArgs(); 322 System.setProperty(ConfigConstants.RECIPES_PARAM_NAME, StringUtils.join(recipes, ",")); 323 324 System.out.println(WELCOME_MESSAGE); 325 workspace.loadConfiguration(true); 326 327 System.out.println("Configuration: [" + workspace.getConfigurationName() + "]"); 328 workspace.runSetupNodes(); 329 330 if (recipes.length == 0) { 331 String[] testsList = workspace.getTestsList(); 332 Processor processor = new BaseProcessor(workspace.getSystemVariables(), workspace.getConfigNode(), 333 workspace.getStartDir()); 334 recipes = workspace.inputMultiChoice("Recipe", testsList, null, processor); 335 } 336 337 if (recipes != null) { 338 for (String name : recipes) { 339 System.out.println("Recipe: [" + name + "]"); 340 RecipeRunner runTask = workspace.runTask(name, false); 341 342 if (runTask == null) { 343 System.out.println("Recipe: [" + name + "] not found."); 344 345 Enumeration<Object> keys = workspace.getTestsDescList().keys(); 346 System.out.println("Recipe list:"); 347 while (keys.hasMoreElements()) { 348 Object taskName = (Object) keys.nextElement(); 349 System.out.println("\t" + taskName); 350 } 351 } 352 353 if (runTask.getStatus() == STATUS_FAILED) { 354 System.exit(STATUS_FAILED); 355 } 356 } 357 } 358 359 } catch ( 360 361 Exception e) { 362 e.printStackTrace(); 363 System.exit(STATUS_FAILED); 364 } 365 366 workspace.close(); 367 } catch (ParseException e) { 368 System.err.println("Error parsing arguments: " + e.getMessage()); 369 help(options, formatter); 370 } 371 } 372 373 private static void help(Options options, HelpFormatter formatter) { 374 formatter.printHelp("java -jar ae.jar <recipe_name> ...", options); 375 } 376 377}