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