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 fStatus = 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 Processor getTaskProcessor() {
079                return processor;
080        }
081
082        public Node getTaskNode() {
083                return fTaskNode;
084        }
085
086        public void setProcessor(Processor processor) {
087                this.processor = processor;
088        }
089
090        public void 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                getTaskProcessor().make(file);
096        }
097
098        public void runTest(Node testNode[]) throws Exception {
099                setTaskNode(testNode[0]);
100                processor = new BaseProcessor(fConfigNode, fSystemVariables, this, manager.getStartDir(), getLogger(),
101                                getTaskProcessor());
102                processor.runNodes(testNode);
103                endTask(false);
104        }
105
106        public void setTaskNode(Node object) {
107                fTaskNode = object;
108        }
109
110        public void criticalError(CommandException aThrowable, Processor processor) {
111                this.endTask(true);
112                fStatus = STATUS_FAILED;
113                StringBuilder taskTrace = new StringBuilder(aThrowable.getTaskTrace() + "\n\n");
114                Throwable rootCause = ExceptionUtils.getRootCause(aThrowable);
115                processor.getLogger().error(taskTrace.toString(), (Throwable) ObjectUtils.defaultIfNull(rootCause, aThrowable));
116        }
117
118        public void checkFailure(CommandException e, Processor processor) {
119                fStatus = STATUS_FAILED;
120                processor.getLogger().error("Check Failure. Message: " + e.getMessage() + "\n" + e.getTaskTrace());
121                this.endTask(true);
122                getLogger().debug(e);
123        }
124
125        public void startTask(String aNameTask) {
126                setTestName(aNameTask);
127        }
128
129        public void setTestName(String aNameTask) {
130                fNameTask = aNameTask;
131        }
132
133        public void setProgress(String aCurrentTaskName, long aMaxTags, long aCurrTags, boolean aErrorState) {
134        }
135
136        public AEManager getManager() {
137                return manager;
138        }
139
140        public void endTask(boolean aErrorState) {
141                manager.removeRunner(this);
142        }
143
144        public void changeVariable(String aAttribut, Object aValue) {
145        }
146
147        public void startCommand(int i) {
148        }
149
150        public void startChildProcess(TaskProcessorThread aMaxTestRunnable) {
151        }
152
153        public void stopChildProcess(TaskProcessorThread aMaxTestRunnable) {
154        }
155
156        public Node getConfigNode() {
157                return fConfigNode;
158        }
159
160        public void stopTest() {
161                if (processor != null) {
162                        processor.stop();
163                }
164        }
165
166        public String getTitle() {
167                return fNameTask;
168        }
169
170        public String inputFile(File aDefaultFile, Processor taskProcessor) {
171                return aDefaultFile.getAbsolutePath();
172        }
173
174        public void aboutTest(String theTaskName, Node aCurrentAction) {
175
176        }
177
178        public void setRunMode(String aMode) {
179                fRunMode = aMode;
180        }
181
182        public String getRunMode() {
183                return fRunMode;
184        }
185
186        public void exceptionIgnored(Throwable e) {
187                List<Node> callTaskTrace = getTaskProcessor().getLocalTaskTrace();
188                ByteArrayOutputStream stack = new ByteArrayOutputStream();
189                e.printStackTrace(new PrintStream(stack));
190                getLogger().debug("Exception ignored. Recipe: " + StringUtils.join(callTaskTrace, " - ") + "\nException: "
191                                + stack.toString());
192        }
193
194        public ILogger getLogger() {
195                return log;
196        }
197
198        public int getStatus() {
199                return fStatus;
200        }
201
202        public ServerSocket createPort(int thePort, String aDescription) throws IOException {
203                ServerSocket serverSocket = null;
204
205                if (thePort < 0) {
206                        SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
207                        serverSocket = factory.createServerSocket(-thePort);
208                } else {
209                        serverSocket = new ServerSocket(thePort);
210                }
211
212                return serverSocket;
213        }
214
215        public void closePort(int thePort) {
216        }
217
218        public void errorInformation(Processor processor, Throwable e, Node command) throws CommandException {
219                if (e instanceof CommandException) {
220                        throw (CommandException) e;
221                } else {
222                        throw new CommandException(e, processor, command);
223                }
224        }
225
226        public void outToFrame(Processor processor, Properties aProperties, Object aTheValue) {
227        }
228
229        public void runCommandFrame(Properties params) throws Throwable {
230        }
231
232        public ILogger createLog(String aName, boolean mainLog) {
233                return log;
234        }
235
236        public void pause() {
237        }
238
239        public void resume() {
240        }
241
242        @Override
243        public boolean isNotifyMe() {
244                return false;
245        }
246
247        public Map<String, Object> getSystemVariables() {
248                return fSystemVariables;
249        }
250
251        public void setLog(ILogger log) {
252                this.log = log;
253        }
254
255        public static void main(String... args) throws IOException {
256
257                Options options = new Options();
258                Option helpOption = new Option("h", "help", false, "Displays help information for usage.");
259                Option versionOption = new Option("v", "version", false,
260                                "Use this option to check which version of Anteater you are running, ensuring compatibility with your recipes and plugins.");
261                Option commandPortOption = new Option("c", "commandPort", true,
262                                "Specifies the port for command communication.");
263                Option configNameOption = new Option("n", "configName", true, "Specifies the configuration name to use.");
264                Option commandServerPortOption = new Option("s", "serverPort", true,
265                                "Specifies the port for the command server.");
266                Option consoleOption = new Option("con", "console", false, "Force application to run in console mode");
267
268                options.addOption(helpOption);
269                options.addOption(versionOption);
270                options.addOption(commandPortOption);
271                options.addOption(configNameOption);
272                options.addOption(commandServerPortOption);
273                options.addOption(consoleOption);
274
275                CommandLineParser parser = new DefaultParser();
276                HelpFormatter formatter = new HelpFormatter();
277
278                try {
279                        CommandLine cmd = parser.parse(options, args);
280
281                        if (cmd.hasOption(versionOption)) {
282                                System.out.println("Anteater Version: " + AEUtils.getPrjProperty("application.version"));
283                                return;
284                        }
285
286                        if (cmd.hasOption(helpOption)) {
287                                help(options, formatter);
288                                return;
289                        }
290                        
291                        if (!cmd.hasOption(consoleOption) && System.console() == null) {
292                                JOptionPane.showMessageDialog(null,
293                                                "ae.jar is a command line tool and should be run in a terminal or command prompt.");
294                                System.exit(1);
295                        }
296
297                        if (cmd.hasOption(commandPortOption)) {
298                                int port = Integer.parseInt(cmd.getOptionValue(commandPortOption));
299                                String[] commands = cmd.getArgs();
300                                CommandServer.sendCommand(port, commands);
301                                System.exit(0);
302                        }
303
304                        if (cmd.hasOption(configNameOption)) {
305                                String configName = cmd.getOptionValue(configNameOption);
306                                System.setProperty(ConfigConstants.CONFIG_NAME_SYS_PRPERTY_NAME, configName);
307                        }
308
309                        AEWorkspace workspace = new AEWorkspace();
310                        try {
311                                if (cmd.hasOption(commandServerPortOption)) {
312                                        int port = Integer.parseInt(cmd.getOptionValue(commandServerPortOption));
313                                        CommandServer.openCommandPort(workspace, port);
314                                }
315
316                                String[] recipes = cmd.getArgs();
317                                System.setProperty(ConfigConstants.RECIPES_PARAM_NAME, StringUtils.join(recipes, ","));
318
319                                System.out.println(WELCOME_MESSAGE);
320                                workspace.loadConfiguration(true);
321
322                                System.out.println("Configuration: [" + workspace.getConfigurationName() + "]");
323                                workspace.runSetupNodes();
324
325                                if (recipes.length == 0) {
326                                        String[] testsList = workspace.getTestsList();
327                                        Processor processor = new BaseProcessor(workspace.getSystemVariables(), workspace.getConfigNode(),
328                                                        workspace.getStartDir());
329                                        recipes = workspace.inputMultiChoice("Recipe", testsList, null, processor);
330                                }
331
332                                if (recipes != null) {
333                                        for (String name : recipes) {
334                                                System.out.println("Recipe: [" + name + "]");
335                                                RecipeRunner runTask = workspace.runTask(name, false);
336
337                                                if (runTask == null) {
338                                                        System.out.println("Recipe: [" + name + "] not found.");
339
340                                                        Enumeration<Object> keys = workspace.getTestsDescList().keys();
341                                                        System.out.println("Recipe list:");
342                                                        while (keys.hasMoreElements()) {
343                                                                Object taskName = (Object) keys.nextElement();
344                                                                System.out.println("\t" + taskName);
345                                                        }
346                                                }
347
348                                                if (runTask.getStatus() == STATUS_FAILED) {
349                                                        System.exit(STATUS_FAILED);
350                                                }
351                                        }
352                                }
353
354                        } catch (
355
356                        Exception e) {
357                                e.printStackTrace();
358                                System.exit(STATUS_FAILED);
359                        }
360
361                        workspace.close();
362                } catch (
363
364                ParseException e) {
365                        System.err.println("Error parsing arguments: " + e.getMessage());
366                        help(options, formatter);
367                }
368        }
369
370        private static void help(Options options, HelpFormatter formatter) {
371                formatter.printHelp("java -jar ae.jar <recipe_name> ...", options);
372        }
373
374}