Revision: 6332 Author: j...@google.com Date: Thu Oct 8 15:44:08 2009 Log: Fix a problem where JL's batching changes were botched in the process of merging, filter out annoying log spam when JUnit changes to the next module (basically the JSNI call Window.Location.replace never returns and we get a dropped connection).
http://code.google.com/p/google-web-toolkit/source/detail?r=6332 Modified: /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/HostedModeBase.java /changes/jat/abstractui/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserListener.java /changes/jat/abstractui/user/src/com/google/gwt/junit/BatchingStrategy.java /changes/jat/abstractui/user/src/com/google/gwt/junit/JUnitShell.java ======================================= --- /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/HostedModeBase.java Thu Oct 8 14:16:26 2009 +++ /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/HostedModeBase.java Thu Oct 8 15:44:08 2009 @@ -62,6 +62,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.concurrent.Semaphore; /** * The main executable class for the hosted mode shell. This class must not have @@ -316,7 +317,7 @@ return true; } } - + /** * Handles the -noserver command line flag. */ @@ -607,7 +608,7 @@ void setNoServer(boolean isNoServer); } - + /** * Controls what port to use. * @@ -716,7 +717,7 @@ */ private Set<String> alreadySeenModules = new HashSet<String>(); - private final Object blockUntilDone = new Object(); + private final Semaphore blockUntilDone = new Semaphore(0); private BrowserWidgetHostImpl browserHost = new UiBrowserWidgetHostImpl(); @@ -785,9 +786,7 @@ launchStartupUrls(getTopLogger()); } - synchronized (blockUntilDone) { - blockUntilDone.wait(); - } + blockUntilDone.acquire(); } catch (Exception e) { e.printStackTrace(); } finally { @@ -999,9 +998,7 @@ } protected final void setDone() { - synchronized (blockUntilDone) { - blockUntilDone.notifyAll(); - } + blockUntilDone.release(); } protected final void setHeadless(boolean headlessMode) { ======================================= --- /changes/jat/abstractui/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java Wed Oct 7 09:24:31 2009 +++ /changes/jat/abstractui/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java Thu Oct 8 15:44:08 2009 @@ -53,7 +53,7 @@ public TestBrowserChannelServer(TreeLogger logger, InputStream inputStream, OutputStream outputStream, SessionHandler handler) throws IOException { - super(logger, inputStream, outputStream, handler); + super(logger, inputStream, outputStream, handler, true); } @Override ======================================= --- /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java Thu Oct 8 08:49:57 2009 +++ /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java Thu Oct 8 15:44:08 2009 @@ -25,17 +25,30 @@ import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.Socket; +import java.net.SocketException; import java.util.Set; /** * */ public abstract class BrowserChannel { + + /** + * An error indicating that the remote side died and we should unroll the + * call stack as painlessly as possible to allow cleanup. + */ + public static class RemoteDeathError extends Error { + + public RemoteDeathError(Throwable cause) { + super("Remote connection lost", cause); + } + } /** * Class representing a reference to a Java object. @@ -1314,11 +1327,15 @@ public static void send(BrowserChannel channel, boolean isException, Value returnValue) throws IOException { - final DataOutputStream stream = channel.getStreamToOtherSide(); - stream.writeByte(MessageType.RETURN.getId()); - stream.writeBoolean(isException); - channel.writeValue(stream, returnValue); - stream.flush(); + try { + final DataOutputStream stream = channel.getStreamToOtherSide(); + stream.writeByte(MessageType.RETURN.getId()); + stream.writeBoolean(isException); + channel.writeValue(stream, returnValue); + stream.flush(); + } catch (SocketException e) { + throw new RemoteDeathError(e); + } } public static void send(BrowserChannel channel, @@ -1630,28 +1647,35 @@ public void reactToMessages(SessionHandler handler) throws IOException, BrowserChannelException { do { - getStreamToOtherSide().flush(); - MessageType messageType = Message.readMessageType(getStreamFromOtherSide()); - switch (messageType) { - case FREE_VALUE: - final FreeMessage freeMsg = FreeMessage.receive(this); - handler.freeValue(this, freeMsg.getIds()); - break; - case INVOKE: - final InvokeOnServerMessage imsg = InvokeOnServerMessage.receive(this); - ExceptionOrReturnValue result = handler.invoke(this, imsg.getThis(), - imsg.getMethodDispatchId(), imsg.getArgs()); - sendFreedValues(); - ReturnMessage.send(this, result); - break; - case INVOKE_SPECIAL: - handleInvokeSpecial(handler); - break; - case QUIT: - return; - default: - throw new BrowserChannelException("Invalid message type " - + messageType); + try { + getStreamToOtherSide().flush(); + MessageType messageType = Message.readMessageType( + getStreamFromOtherSide()); + switch (messageType) { + case FREE_VALUE: + final FreeMessage freeMsg = FreeMessage.receive(this); + handler.freeValue(this, freeMsg.getIds()); + break; + case INVOKE: + InvokeOnServerMessage imsg = InvokeOnServerMessage.receive(this); + ExceptionOrReturnValue result = handler.invoke(this, imsg.getThis(), + imsg.getMethodDispatchId(), imsg.getArgs()); + sendFreedValues(); + ReturnMessage.send(this, result); + break; + case INVOKE_SPECIAL: + handleInvokeSpecial(handler); + break; + case QUIT: + return; + default: + throw new BrowserChannelException("Invalid message type " + + messageType); + } + } catch (SocketException e) { + throw new RemoteDeathError(e); + } catch (EOFException e) { + throw new RemoteDeathError(e); } } while (true); } @@ -1659,28 +1683,39 @@ public ReturnMessage reactToMessagesWhileWaitingForReturn( SessionHandler handler) throws IOException, BrowserChannelException { do { - getStreamToOtherSide().flush(); - MessageType messageType = Message.readMessageType(getStreamFromOtherSide()); - switch (messageType) { - case FREE_VALUE: - final FreeMessage freeMsg = FreeMessage.receive(this); - handler.freeValue(this, freeMsg.getIds()); - break; - case RETURN: - return ReturnMessage.receive(this); - case INVOKE: - final InvokeOnServerMessage imsg = InvokeOnServerMessage.receive(this); - ExceptionOrReturnValue result = handler.invoke(this, imsg.getThis(), - imsg.getMethodDispatchId(), imsg.getArgs()); - sendFreedValues(); - ReturnMessage.send(this, result); - break; - case INVOKE_SPECIAL: - handleInvokeSpecial(handler); - break; - default: - throw new BrowserChannelException("Invalid message type " - + messageType + " received waiting for return."); + try { + getStreamToOtherSide().flush(); + MessageType messageType = Message.readMessageType( + getStreamFromOtherSide()); + switch (messageType) { + case FREE_VALUE: + final FreeMessage freeMsg = FreeMessage.receive(this); + handler.freeValue(this, freeMsg.getIds()); + break; + case RETURN: + return ReturnMessage.receive(this); + case INVOKE: + InvokeOnServerMessage imsg = InvokeOnServerMessage.receive(this); + ExceptionOrReturnValue result = handler.invoke(this, imsg.getThis(), + imsg.getMethodDispatchId(), imsg.getArgs()); + sendFreedValues(); + ReturnMessage.send(this, result); + break; + case INVOKE_SPECIAL: + handleInvokeSpecial(handler); + break; + case QUIT: + // if we got an unexpected QUIT here, the remote plugin probably + // realized it was dying and had time to close the socket properly. + throw new RemoteDeathError(null); + default: + throw new BrowserChannelException("Invalid message type " + + messageType + " received waiting for return."); + } + } catch (SocketException e) { + throw new RemoteDeathError(e); + } catch (EOFException e) { + throw new RemoteDeathError(e); } } while (true); } ======================================= --- /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java Thu Oct 8 08:49:57 2009 +++ /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java Thu Oct 8 15:44:08 2009 @@ -64,7 +64,9 @@ private static final Object cacheLock = new Object(); - private SessionHandler handler; + private final SessionHandler handler; + + private final boolean ignoreRemoteDeath; private final ServerObjectsTable javaObjectsInBrowser = new ServerObjectsTable(); @@ -77,10 +79,11 @@ private int protocolVersion = -1; public BrowserChannelServer(TreeLogger initialLogger, Socket socket, - SessionHandler handler) throws IOException { + SessionHandler handler, boolean ignoreRemoteDeath) throws IOException { super(socket, new ServerObjectRefFactory()); this.handler = handler; this.logger = initialLogger; + this.ignoreRemoteDeath = ignoreRemoteDeath; Thread thread = new Thread(this); thread.setDaemon(true); thread.setName("Hosted mode worker"); @@ -89,10 +92,12 @@ // @VisibleForTesting BrowserChannelServer(TreeLogger initialLogger, InputStream inputStream, - OutputStream outputStream, SessionHandler handler) throws IOException { + OutputStream outputStream, SessionHandler handler, + boolean ignoreRemoteDeath) throws IOException { super(inputStream, outputStream, new ServerObjectRefFactory()); this.handler = handler; this.logger = initialLogger; + this.ignoreRemoteDeath = ignoreRemoteDeath; Thread thread = new Thread(this); thread.setDaemon(true); thread.setName("Hosted mode worker"); @@ -334,6 +339,10 @@ // send LoadModule response ReturnMessage.send(this, false, new Value()); reactToMessages(handler); + } catch (RemoteDeathError e) { + if (!ignoreRemoteDeath ) { + logger.log(TreeLogger.ERROR, e.getMessage(), e); + } } finally { handler.unloadModule(this, moduleName); } ======================================= --- /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserListener.java Sun Sep 20 12:33:31 2009 +++ /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/shell/BrowserListener.java Thu Oct 8 15:44:08 2009 @@ -36,6 +36,8 @@ private Thread listenThread; + private boolean ignoreRemoteDeath = false; + /** * Listens for new connections from browsers. */ @@ -64,7 +66,7 @@ } BrowserChannelServer server = new BrowserChannelServer(branch, - sock, handler); + sock, handler, ignoreRemoteDeath); /* * This object is special-cased by the SessionHandler, used for * methods needed by the client like hasMethod/hasProperty/etc. @@ -115,4 +117,15 @@ listenThread.start(); } } -} + + /** + * Set any created BrowserChannelServers to ignore remote deaths. + * + * <p>This is most commonly wanted by JUnitShell. + * + * @param ignoreRemoteDeath + */ + public void setIgnoreRemoteDeath(boolean ignoreRemoteDeath) { + this.ignoreRemoteDeath = ignoreRemoteDeath; + } +} ======================================= --- /changes/jat/abstractui/user/src/com/google/gwt/junit/BatchingStrategy.java Fri Oct 2 08:37:20 2009 +++ /changes/jat/abstractui/user/src/com/google/gwt/junit/BatchingStrategy.java Thu Oct 8 15:44:08 2009 @@ -49,11 +49,11 @@ Set<TestInfo> toExecute = GWTTestCase.getTestsForModule(syntheticModuleName).getTests(); Set<TestInfo> toRemove = new HashSet<TestInfo>(); // TODO(jat): merge problem? -// for (TestInfo info : toExecute) { -// if (JUnitShell.mustNotExecuteTest(info.)) { -// toRemove.add(info); -// } -// } + for (TestInfo info : toExecute) { + if (JUnitShell.mustNotExecuteTest(info)) { + toRemove.add(info); + } + } toExecute.removeAll(toRemove); return toExecute; } ======================================= --- /changes/jat/abstractui/user/src/com/google/gwt/junit/JUnitShell.java Thu Oct 8 14:16:26 2009 +++ /changes/jat/abstractui/user/src/com/google/gwt/junit/JUnitShell.java Thu Oct 8 15:44:08 2009 @@ -361,19 +361,34 @@ * @return the list of remote user agents */ public static String[] getRemoteUserAgents() { - return getUnitTestShell().remoteUserAgents; + if (unitTestShell == null) { + return null; + } + return unitTestShell.remoteUserAgents; } /** * Checks if a testCase should not be executed. Currently, a test is either * executed on all clients (mentioned in this test) or on no clients. * - * @param testCase current testCase. + * @param testInfo the test info to check * @return true iff the test should not be executed on any of the specified * clients. */ - public static boolean mustNotExecuteTest(TestCase testCase) { - return getUnitTestShell().mustNotExecuteTest(getBannedPlatforms(testCase)); + public static boolean mustNotExecuteTest(TestInfo testInfo) { + if (unitTestShell == null) { + throw new IllegalStateException( + "mustNotExecuteTest cannot be called before runTest()"); + } + try { + Class<?> testClass = TestCase.class.getClassLoader().loadClass( + testInfo.getTestClass()); + return unitTestShell.mustNotExecuteTest(getBannedPlatforms(testClass, + testInfo.getTestMethod())); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Could not load test class: " + + testInfo.getTestClass()); + } } /** @@ -453,16 +468,19 @@ } /** - * returns the set of banned {...@code Platform} for a test method. + * Returns the set of banned {...@code Platform} for a test method. + * + * @param testClass the testClass + * @param methodName the name of the test method */ - private static Set<Platform> getBannedPlatforms(TestCase testCase) { - Class<?> testClass = testCase.getClass(); + private static Set<Platform> getBannedPlatforms(Class<?> testClass, + String methodName) { Set<Platform> bannedSet = EnumSet.noneOf(Platform.class); if (testClass.isAnnotationPresent(DoNotRunWith.class)) { bannedSet.addAll(Arrays.asList(testClass.getAnnotation(DoNotRunWith.class).value())); } try { - Method testMethod = testClass.getMethod(testCase.getName()); + Method testMethod = testClass.getMethod(methodName); if (testMethod.isAnnotationPresent(DoNotRunWith.class)) { bannedSet.addAll(Arrays.asList(testMethod.getAnnotation( DoNotRunWith.class).value())); @@ -659,6 +677,7 @@ protected void ensureCodeServerListener() { if (developmentMode) { super.ensureCodeServerListener(); + listener.setIgnoreRemoteDeath(true); } } @@ -903,7 +922,8 @@ private void runTestImpl(GWTTestCase testCase, TestResult testResult) throws UnableToCompleteException { - if (mustNotExecuteTest(testCase)) { + if (mustNotExecuteTest(getBannedPlatforms(testCase.getClass(), + testCase.getName()))) { return; } --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---