Revision: 8472
Author: [email protected]
Date: Tue Aug  3 17:01:46 2010
Log: Put in a new fix for DevMode logging that uses bytecode rewriting rather than swapping out
the LogManager and should work with App Engine apps

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

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

Added:
/trunk/dev/core/src/com/google/gwt/dev/shell/rewrite/UseMirroredClasses.java
 /trunk/user/src/com/google/gwt/logging/impl/DevModeLoggingFixes.java
Deleted:
 /trunk/dev/core/src/com/google/gwt/dev/shell/DevModeLogManager.java
 /trunk/dev/core/test/com/google/gwt/dev/DevModeBaseTest.java
 /trunk/dev/core/test/com/google/gwt/dev/shell/DevModeLogManagerTest.java
Modified:
 /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java
 /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
 /trunk/dev/core/src/com/google/gwt/dev/shell/GWTBridgeImpl.java
/trunk/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java
 /trunk/dev/core/super/com/google/gwt/core/client/GWTBridge.java
 /trunk/user/src/com/google/gwt/core/client/GWT.java
 /trunk/user/src/com/google/gwt/junit/GWTDummyBridge.java
 /trunk/user/src/com/google/gwt/logging/client/LogConfiguration.java

=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/shell/rewrite/UseMirroredClasses.java Tue Aug 3 17:01:46 2010
@@ -0,0 +1,160 @@
+/*
+ * 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.rewrite;
+
+import com.google.gwt.dev.asm.ClassAdapter;
+import com.google.gwt.dev.asm.ClassVisitor;
+import com.google.gwt.dev.asm.MethodAdapter;
+import com.google.gwt.dev.asm.MethodVisitor;
+import com.google.gwt.dev.asm.Opcodes;
+import com.google.gwt.dev.asm.Type;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A general Class Visitor which will take any of the method calls in it's
+ * list and replace them with static calls to another method (the "mirrored"
+ * method) in another class (the "mirrored" class). This method should
+ * take the original object as it's first argument, followed by the rest of
+ * the arguments to the method. The "mirrored" class will not be rewritten, + * allowing the "mirrored" method to do whatever modifications are necessary + * before calling the original method (if desired). Methods which should be
+ * rewritten are listed in the mirroredMethods map below. Note that our
+ * mirroring process is not robust enough to rewrite methods on subtypes.
+ */
+public class UseMirroredClasses extends ClassAdapter {
+  private static class MethodInterceptor extends MethodAdapter {
+    private static HashMap<String, HashMap<String, String>> mirrorMap;
+    static {
+        // The list of mirrored methods
+        // TODO(unnurg): Find a better way to track methods that will get
+        // rewritten - possibly by using annotations
+        mirrorMap = new HashMap<String, HashMap<String, String>>();
+
+ HashMap<String, String> logRecordMethods = new HashMap<String, String>();
+        logRecordMethods.put(
+            "getLoggerName",
+            "com/google/gwt/logging/impl/DevModeLoggingFixes:getLoggerName");
+        mirrorMap.put("java/util/logging/LogRecord", logRecordMethods);
+
+ HashMap<String, String> logManagerMethods = new HashMap<String, String>();
+        logManagerMethods.put(
+            "getLogger",
+            
"com/google/gwt/logging/impl/DevModeLoggingFixes:logManagerGetLogger");
+        mirrorMap.put("java/util/logging/LogManager", logManagerMethods);
+
+ HashMap<String, String> loggerMethods = new HashMap<String, String>();
+        loggerMethods.put(
+            "getName",
+            "com/google/gwt/logging/impl/DevModeLoggingFixes:getName");
+        loggerMethods.put(
+            "getLogger",
+            "com/google/gwt/logging/impl/DevModeLoggingFixes:loggerGetLogger");
+        mirrorMap.put("java/util/logging/Logger", loggerMethods);
+      }
+
+    private String className;
+
+    protected MethodInterceptor(MethodVisitor mv, String className) {
+      super(mv);
+      this.className = className;
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name,
+        String desc) {
+
+      // Check if this method is in our list
+      Map<String, String> mirroredMethods = mirrorMap.get(owner);
+      if (mirroredMethods == null) {
+        super.visitMethodInsn(opcode, owner, name, desc);
+        return;
+      }
+
+      String mirrorClassMethod = mirroredMethods.get(name);
+      if (mirrorClassMethod == null) {
+        super.visitMethodInsn(opcode, owner, name, desc);
+        return;
+      }
+
+      // Confirm that the replacement method string is correctly formatted
+      // and split it into a class and a method
+      String[] temp = mirrorClassMethod.split(":");
+      if (temp.length < 2) {
+        super.visitMethodInsn(opcode, owner, name, desc);
+        return;
+      }
+
+      String mirrorClass = temp[0];
+      String mirrorMethod = temp[1];
+
+      // Confirm that this is not the mirrored class itself (this would
+      // lead to infinite loops if the mirrored method wants to call
+      // the original method in it's implementation).
+      if (className.equals(mirrorClass.replace("/", "."))) {
+        super.visitMethodInsn(opcode, owner, name, desc);
+        return;
+      }
+
+      if (opcode == Opcodes.INVOKESTATIC) {
+        super.visitMethodInsn(opcode, mirrorClass, mirrorMethod, desc);
+        return;
+      }
+
+      // Get the types of the current method being invoked
+      // using the method descriptor string
+      final Type[] argTypes = Type.getArgumentTypes(desc);
+
+      // The new types for the new method
+      final Type[] newArgTypes = new Type[argTypes.length + 1];
+
+      // Make the first argument be the instance type (i.e. "this")
+      newArgTypes[0] = Type.getType("L" + owner + ";");
+
+      // Copy over all the other args
+      System.arraycopy(argTypes, 0, newArgTypes, 1, argTypes.length);
+
+      // Specify the new descriptor that includes the "this" arg.
+      String newDesc =
+        Type.getMethodDescriptor(Type.getReturnType(desc), newArgTypes);
+
+      // Call the corresponding static method on the mirror class
+      super.visitMethodInsn(
+          Opcodes.INVOKESTATIC, mirrorClass, mirrorMethod, newDesc);
+      return;
+    }
+  }
+
+  private String className;
+
+  public UseMirroredClasses(ClassVisitor cv, String className) {
+    super(cv);
+    this.className = className;
+  }
+
+  @Override
+  public MethodVisitor visitMethod(int access, String name, String desc,
+      String signature, String[] exceptions) {
+    MethodVisitor mv = super.visitMethod(access, name, desc, signature,
+        exceptions);
+    if (mv == null) {
+      return null;
+    }
+    return new MethodInterceptor(mv, className);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/logging/impl/DevModeLoggingFixes.java Tue Aug 3 17:01:46 2010
@@ -0,0 +1,99 @@
+/*
+ * 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.logging.impl;
+
+import com.google.gwt.core.client.GWT;
+
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * This class is used by the byte code rewriting which happens in DevMode only.
+ * We rewrite all calls that create and access loggers by name to include a
+ * magic, thread specific prefix, which creates a separate tree of loggers for
+ * each thread in DevMode. This works around the issue where DevMode root
+ * loggers are shared between threads and between client/server. These functions
+ * will never be used in Production compiles.
+ *
+ * TODO(unnurg): Move this class into gwt-dev
+ *
+ * @see UseMirroredClasses
+ */
+public class DevModeLoggingFixes {
+  private static Logger root = null;
+
+  /**
+ * Replaces all logRecord.getLoggerName() calls, removing a thread specific
+   * prefix which is appended to all logger names in dev mode in order to
+   * maintain a pseudo tree of loggers for each thread.
+   */
+  public static String getLoggerName(LogRecord record) {
+    return removeLoggerPrefix(record.getLoggerName());
+  }
+
+  /**
+   * Replaces all logger.getName() calls, removing a thread specific prefix
+   * which is appended to all logger names in dev mode in order to maintain
+   * a pseudo tree of loggers for each thread.
+   */
+  public static String getName(Logger logger) {
+    return removeLoggerPrefix(logger.getName());
+  }
+
+  /**
+ * Replaces all Logger.getLogger(name) calls, adding a thread specific prefix
+   * which is appended to all logger names in dev mode in order to maintain
+   * a pseudo tree of loggers for each thread.
+   */
+  public static Logger loggerGetLogger(String name) {
+    // If a library adds Loggers, but does not include the LogConfiguration
+ // EntryPoint, then the separate root logger does not get created, and set + // to ignore it's parent. In order to ensure that this happens, we do it
+    // again here.
+    if (root == null) {
+      root = Logger.getLogger(getPrefixName());
+      root.setUseParentHandlers(false);
+    }
+    return Logger.getLogger(addLoggerPrefix(name));
+  }
+
+  /**
+ * Replaces all LogManager.getLogger(name) calls, adding a thread specific
+   * prefix which is appended to all logger names in dev mode in order to
+   * maintain a pseudo tree of loggers for each thread.
+   */
+ public static Logger logManagerGetLogger(LogManager manager, String name) {
+    return manager.getLogger(addLoggerPrefix(name));
+  }
+
+  private static String addLoggerPrefix(String name) {
+    return getLoggerPrefix() + name;
+  }
+
+  private static String getLoggerPrefix() {
+    return getPrefixName() + ".";
+  }
+
+  private static String getPrefixName() {
+    return GWT.getUniqueThreadId();
+  }
+
+  private static String removeLoggerPrefix(String name) {
+    return name.replaceFirst("^" + getLoggerPrefix(), "");
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/DevModeLogManager.java Fri May 28 08:44:36 2010
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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);
-  }
-}
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/DevModeBaseTest.java Fri May 28 08:44:36 2010
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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));
-  }
-
-}
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/shell/DevModeLogManagerTest.java Fri May 28 08:44:36 2010
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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));
-  }
-
-}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java Fri Jun 18 12:28:31 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java Tue Aug 3 17:01:46 2010
@@ -710,19 +710,6 @@
     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;

   protected String bindAddress;
@@ -798,9 +785,6 @@
       // 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.
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Fri May 28 08:44:36 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Tue Aug 3 17:01:46 2010
@@ -35,16 +35,6 @@
  */
 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.
@@ -680,7 +670,7 @@

   private void init(TreeLogger initialLogger) {
     this.logger = initialLogger;
-    Thread thread = new CodeServerThread(this);
+    Thread thread = new Thread(this);
     thread.setDaemon(true);
     thread.setName("Code server (initializing)");
     thread.start();
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/GWTBridgeImpl.java Fri Jun 5 07:19:33 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/GWTBridgeImpl.java Tue Aug 3 17:01:46 2010
@@ -22,6 +22,15 @@
* This class is the hosted-mode peer for {...@link com.google.gwt.core.client.GWT}.
  */
 public class GWTBridgeImpl extends GWTBridge {
+
+  protected static ThreadLocal<String> uniqueID =
+    new ThreadLocal<String>() {
+    private int counter = 0;
+
+    public String initialValue() {
+      return "DevModeThread" + ++counter;
+    }
+  };

   private final ShellJavaScriptHost host;

@@ -43,6 +52,13 @@
       throw new RuntimeException(msg, e);
     }
   }
+
+  @Override
+  public String getThreadUniqueID() {
+ // TODO(unnurg): Remove this function once Dev Mode rewriting classes are
+    // in gwt-dev.
+    return uniqueID.get();
+  }

   @Override
   public String getVersion() {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java Tue Jun 22 10:07:56 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java Tue Aug 3 17:01:46 2010
@@ -227,6 +227,8 @@
     // v = new CheckClassAdapter(v);
     // v = new TraceClassVisitor(v, new PrintWriter(System.out));

+    v = new UseMirroredClasses(v, className);
+
     v = new RewriteSingleJsoImplDispatches(v, typeOracle, jsoData);

     v = new RewriteRefsToJsoClasses(v, jsoIntfDescs, mapper);
=======================================
--- /trunk/dev/core/super/com/google/gwt/core/client/GWTBridge.java Tue Jun 3 13:38:06 2008 +++ /trunk/dev/core/super/com/google/gwt/core/client/GWTBridge.java Tue Aug 3 17:01:46 2010
@@ -23,6 +23,10 @@

   public abstract <T> T create(Class<?> classLiteral);

+  public String getThreadUniqueID() {
+    return "";
+  }
+
   public abstract String getVersion();

   public abstract boolean isClient();
=======================================
--- /trunk/user/src/com/google/gwt/core/client/GWT.java Tue Jul 13 15:21:54 2010 +++ /trunk/user/src/com/google/gwt/core/client/GWT.java Tue Aug 3 17:01:46 2010
@@ -163,6 +163,23 @@
   public static UncaughtExceptionHandler getUncaughtExceptionHandler() {
     return sUncaughtExceptionHandler;
   }
+
+  /**
+ * Returns the empty string when running in web mode, but returns a unique
+   * string for each thread in hosted mode (for example, different windows
+   * accessing the dev mode server will each have a unique id, and hitting
+   * refresh without restarting dev mode will result in a new unique id for
+   * a particular window.
+   *
+   * TODO(unnurg): Remove this function once Dev Mode rewriting classes are
+   * in gwt-dev.
+   */
+  public static String getUniqueThreadId() {
+    if (sGWTBridge != null) {
+      return sGWTBridge.getThreadUniqueID();
+    }
+    return "";
+  }

   public static String getVersion() {
     if (sGWTBridge == null) {
=======================================
--- /trunk/user/src/com/google/gwt/junit/GWTDummyBridge.java Fri Jun 5 07:19:33 2009 +++ /trunk/user/src/com/google/gwt/junit/GWTDummyBridge.java Tue Aug 3 17:01:46 2010
@@ -35,7 +35,7 @@
   public <T> T create(Class<?> classLiteral) {
     return null;
   }
-
+
   /**
    * @return the current version of GWT ({...@link About#getGwtVersionNum()})
    */
=======================================
--- /trunk/user/src/com/google/gwt/logging/client/LogConfiguration.java Tue Jul 20 11:03:23 2010 +++ /trunk/user/src/com/google/gwt/logging/client/LogConfiguration.java Tue Aug 3 17:01:46 2010
@@ -60,6 +60,10 @@

     public void configureClientSideLogging() {
       root = Logger.getLogger("");
+ // In DevMode, this root logger will have a parent and we do not want this
+      // root logger to pass messages to it's parent, so we set
+      // useParentHandlers to false here.
+      root.setUseParentHandlers(false);
       setLevels(root);
       setDefaultHandlers(root);
     }

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

Reply via email to