Revision: 8052
Author: [email protected]
Date: Wed May  5 10:04:19 2010
Log: Fix GWT logging in Devmode

Review at http://gwt-code-reviews.appspot.com/437801

Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=8052

Added:
 /branches/2.1/dev/core/src/com/google/gwt/dev/shell/DevModeLogManager.java
 /branches/2.1/dev/core/test/com/google/gwt/dev/DevModeBaseTest.java
/branches/2.1/dev/core/test/com/google/gwt/dev/shell/DevModeLogManagerTest.java
Modified:
 /branches/2.1/dev/core/src/com/google/gwt/dev/DevModeBase.java
/branches/2.1/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java

=======================================
--- /dev/null
+++ /branches/2.1/dev/core/src/com/google/gwt/dev/shell/DevModeLogManager.java Wed May 5 10:04:19 2010
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ *  A log manager which delegates to different instances for client
+ * code so that the client and server code do not share a root logger and try
+ *  to log to each other's handlers.
+ */
+public class DevModeLogManager extends LogManager {
+  static class LogManagerWithExposedConstructor extends LogManager {
+    public LogManagerWithExposedConstructor() {
+      super();
+    }
+  }
+
+  protected ThreadLocal<LogManager> clientLogManager =
+    new ThreadLocal<LogManager>() {
+      public LogManager initialValue() {
+        return new LogManagerWithExposedConstructor();
+      }
+    };
+
+  public DevModeLogManager() {
+    if (System.getProperty("java.util.logging.oldLogManager") != null) {
+      // TODO(unnurg): Instantiate the class stored in oldLogManager and
+      // delegate calls to there.
+      System.err.println(
+          "[WARN] ignoring user-specified value '" +
+          System.getProperty("java.util.logging.oldLogManager") +
+          "' for java.util.logging.manager");
+    }
+  }
+
+  @Override
+  public boolean addLogger(Logger logger) {
+    if (isClientCode()) {
+      return clientLogManager.get().addLogger(logger);
+    }
+    return super.addLogger(logger);
+  }
+
+  @Override
+  public void addPropertyChangeListener(PropertyChangeListener l) {
+    if (isClientCode()) {
+      clientLogManager.get().addPropertyChangeListener(l);
+    }
+    super.addPropertyChangeListener(l);
+  }
+
+  @Override
+  public void checkAccess() {
+    if (isClientCode()) {
+      clientLogManager.get().checkAccess();
+    }
+    super.checkAccess();
+  }
+
+  @Override
+  public Logger getLogger(String name) {
+    if (isClientCode()) {
+      return clientLogManager.get().getLogger(name);
+    }
+    return super.getLogger(name);
+  }
+
+  @Override
+  public Enumeration<String> getLoggerNames() {
+    if (isClientCode()) {
+      return clientLogManager.get().getLoggerNames();
+    }
+    return super.getLoggerNames();
+  }
+
+  @Override
+  public String getProperty(String name) {
+    if (isClientCode()) {
+      return clientLogManager.get().getProperty(name);
+    }
+    return super.getProperty(name);
+  }
+
+  @Override
+  public void readConfiguration() throws IOException, SecurityException {
+    if (isClientCode()) {
+      clientLogManager.get().readConfiguration();
+    }
+    super.readConfiguration();
+  }
+
+  @Override
+  public void readConfiguration(InputStream ins) throws IOException,
+  SecurityException {
+    if (isClientCode()) {
+      clientLogManager.get().readConfiguration(ins);
+    }
+    super.readConfiguration(ins);
+  }
+
+  @Override
+  public void removePropertyChangeListener(PropertyChangeListener l) {
+    if (isClientCode()) {
+      clientLogManager.get().removePropertyChangeListener(l);
+    }
+    super.removePropertyChangeListener(l);
+  }
+
+  @Override
+  public void reset() {
+    if (isClientCode()) {
+      clientLogManager.get().reset();
+    }
+    super.reset();
+  }
+
+  protected boolean isClientCode() {
+    return (Thread.currentThread() instanceof
+        BrowserChannelServer.CodeServerThread);
+  }
+}
=======================================
--- /dev/null
+++ /branches/2.1/dev/core/test/com/google/gwt/dev/DevModeBaseTest.java Wed May 5 10:04:19 2010
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev;
+
+import junit.framework.TestCase;
+
+public class DevModeBaseTest extends TestCase {
+  static final String MANAGER_PROPERTY = "java.util.logging.manager";
+ static final String NEW_MANAGER = "com.google.gwt.dev.shell.DevModeLogManager"; + static final String OLD_MANAGER_PROPERTY = "java.util.logging.oldLogManager";
+  static final String USERS_MANAGER = "UsersLogManager";
+
+  public void testSetLogManager() {
+    assertEquals(null, System.getProperty(MANAGER_PROPERTY));
+    assertEquals(null, System.getProperty(OLD_MANAGER_PROPERTY));
+
+    DevModeBase.setLogManager();
+    assertEquals(NEW_MANAGER, System.getProperty(MANAGER_PROPERTY));
+    assertEquals(null, System.getProperty(OLD_MANAGER_PROPERTY));
+
+    System.setProperty(MANAGER_PROPERTY, USERS_MANAGER);
+    DevModeBase.setLogManager();
+    assertEquals(NEW_MANAGER, System.getProperty(MANAGER_PROPERTY));
+    assertEquals(USERS_MANAGER, System.getProperty(OLD_MANAGER_PROPERTY));
+  }
+
+}
=======================================
--- /dev/null
+++ /branches/2.1/dev/core/test/com/google/gwt/dev/shell/DevModeLogManagerTest.java Wed May 5 10:04:19 2010
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import junit.framework.TestCase;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+public class DevModeLogManagerTest extends TestCase {
+  private static String LOGGER_1_NAME = "Logger1";
+  private static String LOGGER_2_NAME = "Logger2";
+
+  /**
+ * Mocks out the detection of client code since I don't know how to change + * Thread.currentThread to be an instance of CodeServerThread in a unit test.
+   */
+  protected static class DevModeManagerMock extends DevModeLogManager {
+    private boolean isClientCode = false;
+
+    public void setIsClientCode(boolean value) {
+      isClientCode = value;
+    }
+
+    @Override
+    protected boolean isClientCode() {
+      return isClientCode;
+    }
+  }
+
+  public void testDelegation() {
+    Logger logger1 = Logger.getLogger(LOGGER_1_NAME);
+    Logger logger2 = Logger.getLogger(LOGGER_2_NAME);
+    DevModeManagerMock devManager = new DevModeManagerMock();
+    LogManager delegate = devManager.clientLogManager.get();
+    assertNull(devManager.getLogger(LOGGER_1_NAME));
+    assertNull(devManager.getLogger(LOGGER_2_NAME));
+    assertNull(delegate.getLogger(LOGGER_1_NAME));
+    assertNull(delegate.getLogger(LOGGER_2_NAME));
+
+    // devManager delegates to the delegate
+    devManager.setIsClientCode(false);
+    devManager.addLogger(logger1);
+    assertNotNull(devManager.getLogger(LOGGER_1_NAME));
+    assertNull(delegate.getLogger(LOGGER_1_NAME));
+
+    // devManager delegates to super
+    devManager.setIsClientCode(true);
+    devManager.addLogger(logger2);
+    assertNotNull(devManager.getLogger(LOGGER_2_NAME));
+    assertNotNull(delegate.getLogger(LOGGER_2_NAME));
+  }
+
+}
=======================================
--- /branches/2.1/dev/core/src/com/google/gwt/dev/DevModeBase.java Fri Apr 23 06:39:33 2010 +++ /branches/2.1/dev/core/src/com/google/gwt/dev/DevModeBase.java Wed May 5 10:04:19 2010
@@ -62,7 +62,7 @@
* The main executable class for the hosted mode shell. This class must not have
  * any GUI dependencies.
  */
-public abstract class DevModeBase implements DoneCallback {
+abstract class DevModeBase implements DoneCallback {

   /**
    * Implementation of BrowserWidgetHost that supports the abstract UI
@@ -165,9 +165,6 @@
    * Handles the -blacklist command line argument.
    */
   protected static class ArgHandlerBlacklist extends ArgHandlerString {
-    public ArgHandlerBlacklist() {
-    }
-
     @Override
     public String getPurpose() {
return "Prevents the user browsing URLs that match the specified regexes (comma or space separated)";
@@ -346,9 +343,6 @@
     }
   }

-  /**
-   * Handles the -remoteUI command line flag.
-   */
   protected static class ArgHandlerRemoteUI extends ArgHandlerString {

     private final HostedModeBaseOptions options;
@@ -413,9 +407,6 @@
    * Handles the -whitelist command line flag.
    */
   protected static class ArgHandlerWhitelist extends ArgHandlerString {
-    public ArgHandlerWhitelist() {
-    }
-
     @Override
     public String getPurpose() {
return "Allows the user to browse URLs that match the specified regexes (comma or space separated)";
@@ -437,9 +428,6 @@
     }
   }

-  /**
-   * Base options for dev mode.
-   */
protected interface HostedModeBaseOptions extends JJSOptions, OptionLogDir,
       OptionLogLevel, OptionGenDir, OptionNoServer, OptionPort,
       OptionCodeServerPort, OptionStartupURLs, OptionRemoteUI,
@@ -560,9 +548,6 @@
     }
   }

-  /**
-   * Controls what local address to bind to.
-   */
   protected interface OptionBindAddress {
     String getBindAddress();

@@ -573,9 +558,6 @@
     void setConnectAddress(String connectAddress);
   }

-  /**
-   * Controls what port the code server listens on.
-   */
   protected interface OptionCodeServerPort {
     int getCodeServerPort();

@@ -644,10 +626,7 @@
     List<String> getStartupURLs();
   }

-  /**
-   * The base dev mode argument processor.
-   */
-  protected abstract static class ArgProcessor extends ArgProcessorBase {
+  abstract static class ArgProcessor extends ArgProcessorBase {
public ArgProcessor(HostedModeBaseOptions options, boolean forceServer) {
       if (!forceServer) {
         registerHandler(new ArgHandlerNoServerFlag(options));
@@ -709,6 +688,19 @@
     }
     return buf.toString();
   }
+
+  /**
+   * Set up the system to use a DevModeLogManager, which will delegate to
+   * different LogManager instances for client and server code.
+   */
+  protected static void setLogManager() {
+    String oldLogManager = System.getProperty("java.util.logging.manager");
+    if (oldLogManager != null) {
+      System.setProperty("java.util.logging.oldLogManager", oldLogManager);
+    }
+    System.setProperty("java.util.logging.manager",
+        "com.google.gwt.dev.shell.DevModeLogManager");
+  }

   protected TreeLogger.Type baseLogLevelForUI = null;

@@ -785,6 +777,9 @@
       // Eager AWT init for OS X to ensure safe coexistence with SWT.
       BootStrapPlatform.initGui();

+      // Ensure that client and server logging does not share a root logger
+      setLogManager();
+
       boolean success = startUp();

// The web server is running now, so launch browsers for startup urls.
@@ -1133,7 +1128,7 @@
         newlyGeneratedArtifacts);
     produceOutput(linkLogger, linkerContext, artifacts, module, true);
   }
-
+
   /**
* Set the set of startup URLs. This is done before launching to allow the UI * to better present the options to the user, but note that the UI should not
=======================================
--- /branches/2.1/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Fri Feb 19 06:35:15 2010 +++ /branches/2.1/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Wed May 5 10:04:19 2010
@@ -35,6 +35,16 @@
  */
 public class BrowserChannelServer extends BrowserChannel
     implements Runnable {
+
+  /**
+   * Does not extend the Thread functionality in any way. We use instanceof
+   * checks elsewhere in the code to check for this particular thread.
+   */
+  public static class CodeServerThread extends Thread {
+    private CodeServerThread(BrowserChannelServer browserChannelServer) {
+      super(browserChannelServer);
+    }
+  }

   /**
    * Hook interface for responding to messages from the client.
@@ -670,7 +680,7 @@

   private void init(TreeLogger initialLogger) {
     this.logger = initialLogger;
-    Thread thread = new Thread(this);
+    Thread thread = new CodeServerThread(this);
     thread.setDaemon(true);
     thread.setName("Code server (initializing)");
     thread.start();

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to