001: // Copyright © 2002-2005 Canoo Engineering AG, Switzerland.
002: package com.canoo.webtest.extension.applet.runner;
003:
004: import java.applet.Applet;
005: import java.awt.Frame;
006: import java.io.PrintWriter;
007: import java.lang.reflect.Constructor;
008: import java.lang.reflect.InvocationTargetException;
009: import java.net.URLClassLoader;
010:
011: import org.apache.log4j.Level;
012: import org.apache.log4j.Logger;
013: import org.netbeans.jemmy.JemmyProperties;
014: import org.netbeans.jemmy.Scenario;
015: import org.netbeans.jemmy.TestOut;
016:
017: import com.canoo.webtest.boundary.AppletRunnerBoundary;
018: import com.canoo.webtest.extension.applet.AbstractAppletTag;
019: import com.canoo.webtest.extension.applet.AppletPluginArguments;
020: import com.canoo.webtest.extension.applet.AppletPluginResults;
021: import com.canoo.webtest.extension.applet.runner.http.HttpURLConnection;
022: import com.canoo.webtest.util.FileUtil;
023:
024: /**
025: * Main runner for applet test scenarii.
026: * <p>If the application cannot start the scenario, the application ends with a non-zero exit value.
027: * <p>If the application can start the scenario, the application ends with {@link #EXIT_OK 0} and stores the result
028: * of the scenario in a {@link AppletPluginResults}.
029: * @author Denis N. Antonioli
030: * @author Paul King
031: */
032: public class AppletRunner {
033: private static final Logger LOG = Logger
034: .getLogger(AppletRunner.class);
035: private static final Class[] PARAMETER_TYPES_SCENARIO_CONSTRUCTOR = new Class[] {
036: AppletRunner.class, Frame.class };
037: private static final Class[] PARAMETER_TYPES_APPLET_CONSTRUCTOR = new Class[] {};
038: private static final Object[] PARAMETER_APPLET_CONSTRUCTOR = new Object[] {};
039:
040: public static final int EXIT_OK = 0;
041: public static final int EXIT_ERROR_NO_APPLET_RUNNER = -1;
042: public static final int EXIT_ERROR_INSTANTIATE_APPLET_RUNNER = -2;
043: public static final int EXIT_ERROR_DURING_RUN = -3;
044: public static final int EXIT_ERROR_ARGUMENT_IO = -4;
045: public static final int EXIT_ERROR_ARGUMENT_CLASS = -5;
046:
047: private final AppletPluginArguments fAppletPluginArguments;
048: private final Context fAppletContext;
049:
050: /**
051: * Entry point for the test runner.
052: * <p>The method <em>must</em> end with a {@link System#exit(int)} to also end the awt/swing engine.
053: * If the method just ends, the event queue for the gui keeps the JVM (and the applet!) running.
054: */
055: public static void main(String args[]) {
056: JemmyProperties.setCurrentOutput(new TestOut(System.in,
057: new PrintWriter(new LoggingOutputStream(TestOut.class,
058: LOG, Level.INFO), true), new PrintWriter(
059: new LoggingOutputStream(TestOut.class, LOG,
060: Level.WARN), true)));
061:
062: AppletPluginArguments appletPluginArguments = readPluginArguments(args);
063: HttpURLConnection
064: .setCookies(appletPluginArguments.getCookies());
065:
066: try {
067: new AppletRunner(appletPluginArguments).run();
068: } catch (Exception e) {
069: LOG.error(e.getMessage(), e);
070: System.exit(EXIT_ERROR_DURING_RUN);
071: }
072: System.exit(EXIT_OK);
073: }
074:
075: private static AppletPluginArguments readPluginArguments(
076: String[] args) {
077: return new AppletRunnerHelper(EXIT_ERROR_ARGUMENT_CLASS,
078: EXIT_ERROR_ARGUMENT_IO, new AppletRunnerBoundary())
079: .readPluginArguments(args[0]);
080: }
081:
082: public AppletRunner(AppletPluginArguments appletPluginArguments) {
083: fAppletPluginArguments = appletPluginArguments;
084: fAppletContext = new Context(new AppletPluginResults());
085: }
086:
087: void run() throws Exception {
088: AbstractAppletTag appletTag = fAppletPluginArguments
089: .getAppletTag();
090: AbstractAppletStub appletStub = fAppletContext
091: .newStub(newApplet(appletTag), appletTag,
092: fAppletPluginArguments);
093:
094: final Scenario scenario = newScenario(appletStub.getRootFrame());
095: final ScenarioRunner jemmyRunnable = new ScenarioRunner(
096: scenario);
097:
098: internalRun(appletStub, jemmyRunnable);
099: }
100:
101: void internalRun(AbstractAppletStub appletStub,
102: ScenarioRunner jemmyRunnable) throws InterruptedException {
103: appletStub.init();
104: appletStub.show();
105: appletStub.start();
106:
107: try {
108: jemmyRunnable.startTest();
109: jemmyRunnable.join();
110: fAppletContext.getAppletPluginResults().setReturnValue(
111: (Integer) jemmyRunnable.getResult());
112: if (jemmyRunnable.getException() != null) {
113: fAppletContext.getAppletPluginResults().setException(
114: jemmyRunnable.getException());
115: LOG.error(jemmyRunnable.getException().getMessage(),
116: jemmyRunnable.getException());
117: }
118: AppletRunnerBoundary.storeJemmyExceptionIfNeeded(
119: jemmyRunnable.getJemmyException(), fAppletContext);
120: } catch (InterruptedException e) {
121: LOG.warn("Scenario " + fAppletPluginArguments.getScenario()
122: + " interrupted", e);
123: throw e;
124: } finally {
125: appletStub.stop();
126: appletStub.destroy();
127: writeArguments(fAppletContext.getAppletPluginResults());
128: }
129: }
130:
131: protected void writeArguments(AppletPluginResults apr) {
132: FileUtil.tryWriteObjectToFile(fAppletPluginArguments
133: .getOutputFile(), apr, null);
134: }
135:
136: /**
137: * Loads and instantiates a {@link org.netbeans.jemmy.Scenario}. The method looks on the application's classpath for
138: * the named test scenario. Looks also in the property {@link AppletPluginArguments#getScenarioLocation()
139: * scenarioLocation}, if it is set.
140: *
141: * @param rootFrame The root frame for the execution of jemmy.
142: * @return A newly instantiated test scenario.
143: */
144: AbstractScenario newScenario(final Frame rootFrame)
145: throws Exception {
146: ClassLoader classLoader = new URLClassLoader(
147: fAppletPluginArguments.getScenarioLocation(),
148: getClass().getClassLoader());
149:
150: Object object = createObject(classLoader,
151: fAppletPluginArguments.getScenario(),
152: PARAMETER_TYPES_SCENARIO_CONSTRUCTOR, new Object[] {
153: this , rootFrame });
154: return (AbstractScenario) AppletRunnerBoundary
155: .assertObjectHasCorrectClass(AbstractScenario.class,
156: object, "Parameter scenario does not select a "
157: + AbstractScenario.class.getName()
158: + ": ");
159: }
160:
161: Applet newApplet(final AbstractAppletTag appletTag)
162: throws Exception {
163: URLClassLoader appletLoader = AppletRunnerBoundary
164: .tryCreateUrlClassLoader(appletTag, null);
165: Object object = createObject(appletLoader, appletTag.getCode(),
166: PARAMETER_TYPES_APPLET_CONSTRUCTOR,
167: PARAMETER_APPLET_CONSTRUCTOR);
168: return (Applet) AppletRunnerBoundary
169: .assertObjectHasCorrectClass(Applet.class, object,
170: "The xpath does not select an applet: ");
171: }
172:
173: private static Object createObject(final ClassLoader classLoader,
174: final String className, final Class[] ctorParamType,
175: final Object[] ctorParam) throws ClassNotFoundException,
176: NoSuchMethodException, IllegalAccessException,
177: InvocationTargetException, InstantiationException {
178: Class aClass = Class.forName(className, true, classLoader);
179: Constructor constructor = aClass.getConstructor(ctorParamType);
180: return constructor.newInstance(ctorParam);
181: }
182:
183: public AppletPluginArguments getAppletPluginArguments() {
184: return fAppletPluginArguments;
185: }
186:
187: public Context getAppletContext() {
188: return fAppletContext;
189: }
190: }
|