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