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}