/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.midp.installer; import java.io.IOException; import com.sun.midp.midletsuite.MIDletSuiteLockedException; import com.sun.cldc.isolate.*; import com.sun.midp.i18n.Resource; import com.sun.midp.i18n.ResourceConstants; import com.sun.midp.main.AmsUtil; import com.sun.midp.main.MIDletSuiteUtils; import com.sun.midp.midletsuite.MIDletInfo; import com.sun.midp.midletsuite.MIDletSuiteStorage; import com.sun.midp.midlet.MIDletSuite; import com.sun.midp.configurator.Constants; import com.sun.midp.events.*; /** * Abstract class that implements most of auto testing functionality * for MVM mode. The rest of functionality is implemented by subclasses. * Provides bunch of progress notification callbacks that are needed * for some of the subclasses (ODT auto tester, for example). */ abstract class AutoTesterHelperBaseMVM extends AutoTesterHelperBase implements EventListener { /** ID of the test suite being run */ protected int suiteId = MIDletSuite.UNUSED_SUITE_ID; /** Our event queue. */ protected EventQueue eventQueue; /** True if all events in our queue were processed. */ private boolean eventsInQueueProcessed; /** * Constructor. * * @param theURL URL of the test suite * @param theDomain security domain to assign to unsigned suites * @param theLoopCount how many iterations to run the suite */ AutoTesterHelperBaseMVM(String theURL, String theDomain, int theLoopCount) { super(theURL, theDomain, theLoopCount); eventQueue = EventQueue.getEventQueue(); eventQueue.registerEventListener(EventTypes.AUTOTESTER_EVENT, this); } /** * Preprocess an event that is being posted to the event queue. * This method will get called in the thread that posted the event. * * @param event event being posted * * @param waitingEvent previous event of this type waiting in the * queue to be processed * * @return true to allow the post to continue, false to not post the * event to the queue */ public boolean preprocess(Event event, Event waitingEvent) { return true; } /** * Process an event. * This method will get called in the event queue processing thread. * * @param event event to process */ public void process(Event event) { NativeEvent nativeEvent = (NativeEvent)event; switch (nativeEvent.getType()) { case EventTypes.AUTOTESTER_EVENT: { synchronized (this) { eventsInQueueProcessed = true; notify(); } break; } } } /** * Installs and performs the tests. */ void installAndPerformTests() throws Exception { try { for (; loopCount != 0; ) { // force an overwrite and remove the RMS data suiteId = installer.installJad(url, Constants.INTERNAL_STORAGE_ID, true, true, null); onTestSuiteInstalled(); Isolate[] isolatesBefore = Isolate.getIsolates(); MIDletInfo midletInfo = getFirstMIDletOfSuite(suiteId); Isolate testIsolate = AmsUtil.startMidletInNewIsolate(suiteId, midletInfo.classname, midletInfo.name, null, null, null); testIsolate.waitForExit(); boolean newIsolatesFound; do { newIsolatesFound = false; /* * Send an event to ourselves. * Main idea of it is to process all events that are in the * queue at the moment when the test isolate has exited * (because when testing CHAPI there may be requests to * start new isolates). When this event arrives, all events * that were placed in the queue before it are guaranteed * to be processed. */ synchronized (this) { eventsInQueueProcessed = false; NativeEvent event = new NativeEvent( EventTypes.AUTOTESTER_EVENT); eventQueue.sendNativeEventToIsolate(event, MIDletSuiteUtils.getIsolateId()); // and wait until it arrives do { try { wait(); } catch(InterruptedException ie) { // ignore } } while (!eventsInQueueProcessed); } Isolate[] isolatesAfter = Isolate.getIsolates(); /* * Wait for termination of all isolates contained in * isolatesAfter[], but not in isolatesBefore[]. * This is needed to pass some tests (for example, CHAPI) * that starting several isolates. */ int i, j; for (i = 0; i < isolatesAfter.length; i++) { for (j = 0; j < isolatesBefore.length; j++) { try { if (isolatesBefore[j].equals(isolatesAfter[i])) { break; } } catch (Exception e) { // isolatesAfter[i] might already exit, // no need to wait for it break; } } if (j == isolatesBefore.length) { try { newIsolatesFound = true; isolatesAfter[i].waitForExit(); } catch (Exception e) { // ignore: the isolate might already exit } } } } while (newIsolatesFound); if (loopCount > 0) { loopCount -= 1; } } } finally { // we are done: cleanup if (midletSuiteStorage != null && suiteId != MIDletSuite.UNUSED_SUITE_ID) { try { midletSuiteStorage.remove(suiteId); onTestSuiteRemoved(); } catch (Throwable ex) { // ignore } } } } /** * Gets ID of the current test suite. * * @return ID of the current test suite */ int getTestSuiteId() { return suiteId; } /** * Called after test suite has been installed (updated). */ abstract void onTestSuiteInstalled(); /** * Called after test suite has been removed from storage (uninstalled). */ abstract void onTestSuiteRemoved(); }