Revision: 8565
Author: [email protected]
Date: Wed Aug 18 11:12:36 2010
Log: Add DevMode support for the xsiframe linker

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

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

Added:
/trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted_xsiframe.html
Modified:
 /trunk/dev/core/src/com/google/gwt/core/ext/Linker.java
/trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
 /trunk/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
 /trunk/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js
 /trunk/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
 /trunk/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
 /trunk/user/src/com/google/gwt/junit/JUnitShell.java
/trunk/user/test/com/google/gwt/core/ext/test/CrossSiteIframeLinkerTest.java

=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted_xsiframe.html Wed Aug 18 11:12:36 2010
@@ -0,0 +1,350 @@
+<html>
+<head><script>
+var $wnd = parent;
+var $doc = $wnd.document;
+var $moduleName, $moduleBase, $entry
+,$stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null
+,$sessionId = $wnd.__gwtStatsSessionId ? $wnd.__gwtStatsSessionId : null;
+// Lightweight metrics
+if ($stats) {
+  var moduleFuncName = location.search.substr(1);
+  var moduleFunc = $wnd[moduleFuncName];
+  var moduleName = moduleFunc ? moduleFunc.moduleName : "unknown";
+ $stats({moduleName:moduleName,sessionId:$sessionId,subSystem:'startup',evtGroup:'moduleStartup',millis:(new Date()).getTime(),type:'moduleEvalStart'});
+}
+var $hostedHtmlVersion="2.1";
+
+var gwtOnLoad;
+var $hosted = "localhost:9997";
+
+function loadIframe(url) {
+  var topDoc = window.top.document;
+
+  // create an iframe
+  var iframeDiv = topDoc.createElement("div");
+ iframeDiv.innerHTML = "<iframe scrolling=no frameborder=0 src='" + url + "'>";
+  var iframe = iframeDiv.firstChild;
+
+  // mess with the iframe style a little
+  var iframeStyle = iframe.style;
+  iframeStyle.position = "absolute";
+  iframeStyle.borderWidth = "0";
+  iframeStyle.left = "0";
+  iframeStyle.top = "0";
+  iframeStyle.width = "100%";
+  iframeStyle.backgroundColor = "#ffffff";
+  iframeStyle.zIndex = "1";
+  iframeStyle.height = "100%";
+
+  // update the top window's document's body's style
+  var hostBodyStyle = window.top.document.body.style;
+  hostBodyStyle.margin = "0";
+  hostBodyStyle.height = iframeStyle.height;
+  hostBodyStyle.overflow = "hidden";
+
+  // insert the iframe
+  topDoc.body.insertBefore(iframe, topDoc.body.firstChild);
+}
+
+var ua = navigator.userAgent.toLowerCase();
+if (ua.indexOf("gecko") != -1) {
+  // install eval wrapper on FF to avoid EvalError problem
+  var __eval = window.eval;
+  window.eval = function(s) {
+    return __eval(s);
+  }
+}
+if (ua.indexOf("chrome") != -1) {
+  // work around __gwt_ObjectId appearing in JS objects
+  var hop = Object.prototype.hasOwnProperty;
+  Object.prototype.hasOwnProperty = function(prop) {
+    return prop != "__gwt_ObjectId" && hop.call(this, prop);
+  };
+  // do the same in our parent as well -- see issue 4486
+ // NOTE: this will have to be changed when we support non-iframe-based DevMode
+  var hop2 = parent.Object.prototype.hasOwnProperty;
+  parent.Object.prototype.hasOwnProperty = function(prop) {
+    return prop != "__gwt_ObjectId" && hop2.call(this, prop);
+  };
+}
+
+// wrapper to call JS methods, which we need both to be able to supply a
+// different this for method lookup and to get the exception back
+function __gwt_jsInvoke(thisObj, methodName) {
+  try {
+    var args = Array.prototype.slice.call(arguments, 2);
+    return [0, window[methodName].apply(thisObj, args)];
+  } catch (e) {
+    return [1, e];
+  }
+}
+
+var __gwt_javaInvokes = [];
+function __gwt_makeJavaInvoke(argCount) {
+  return __gwt_javaInvokes[argCount] || __gwt_doMakeJavaInvoke(argCount);
+}
+
+function __gwt_doMakeJavaInvoke(argCount) {
+  // IE6 won't eval() anonymous functions except as r-values
+  var argList = "";
+  for (var i = 0; i < argCount; i++) {
+    argList += ",p" + i;
+  }
+  var argListNoComma = argList.substring(1);
+
+  return eval(
+    "__gwt_javaInvokes[" + argCount + "] =\n" +
+    "  function(thisObj, dispId" + argList + ") {\n" +
+    "    var result = __static(dispId, thisObj" + argList + ");\n" +
+    "    if (result[0]) {\n" +
+    "      throw result[1];\n" +
+    "    } else {\n" +
+    "      return result[1];\n" +
+    "    }\n" +
+    "  }\n"
+  );
+}
+
+/*
+ * This is used to create tear-offs of Java methods. Each function corresponds + * to exactly one dispId, and also embeds the argument count. We get the "this"
+ * value from the context in which the function is being executed.
+ * Function-object identity is preserved by caching in a sparse array.
+ */
+var __gwt_tearOffs = [];
+var __gwt_tearOffGenerators = [];
+function __gwt_makeTearOff(proxy, dispId, argCount) {
+  return __gwt_tearOffs[dispId] || __gwt_doMakeTearOff(dispId, argCount);
+}
+
+function __gwt_doMakeTearOff(dispId, argCount) {
+  return __gwt_tearOffs[dispId] =
+ (__gwt_tearOffGenerators[argCount] || __gwt_doMakeTearOffGenerator(argCount))(dispId);
+}
+
+function __gwt_doMakeTearOffGenerator(argCount) {
+  // IE6 won't eval() anonymous functions except as r-values
+  var argList = "";
+  for (var i = 0; i < argCount; i++) {
+    argList += ",p" + i;
+  }
+  var argListNoComma = argList.substring(1);
+
+  return eval(
+    "__gwt_tearOffGenerators[" + argCount + "] =\n" +
+    "  function(dispId) {\n" +
+    "    return function(" + argListNoComma + ") {\n" +
+    "      var result = __static(dispId, this" + argList + ");\n" +
+    "      if (result[0]) {\n" +
+    "        throw result[1];\n" +
+    "      } else {\n" +
+    "        return result[1];\n" +
+    "      }\n" +
+    "    }\n" +
+    "  }\n"
+  );
+}
+
+function __gwt_makeResult(isException, result) {
+  return [isException, result];
+}
+
+function __gwt_disconnected() {
+  // Prevent double-invocation.
+  window.__gwt_disconnected = new Function();
+  // Do it in a timeout so we can be sure we have a clean stack.
+  window.setTimeout(__gwt_disconnected_impl, 1);
+}
+
+function __gwt_disconnected_impl() {
+  __gwt_displayGlassMessage('GWT Code Server Disconnected',
+ 'Most likely, you closed GWT Development Mode. Or, you might have lost ' + + 'network connectivity. To fix this, try restarting GWT Development Mode and ' + + '<a style="color: #FFFFFF; font-weight: bold;" href="javascript:location.reload()">'
+      + 'REFRESH</a> this page.');
+}
+
+// Note this method is also used by ModuleSpace.java
+function __gwt_displayGlassMessage(summary, details) {
+  var topWin = window.top;
+  var topDoc = topWin.document;
+  var outer = topDoc.createElement("div");
+  // Do not insert whitespace or outer.firstChild will get a text node.
+  outer.innerHTML =
+ '<div style="position:absolute;z-index:2147483646;left:0px;top:0px;right:0px;bottom:0px;filter:alpha(opacity=75);opacity:0.75;background-color:#000000;"></div>' + + '<div style="position:absolute;z-index:2147483647;left:50px;top:50px;width:600px;color:#FFFFFF;font-family:verdana;">' + + '<div style="font-size:30px;font-weight:bold;">' + summary + '</div>' +
+      '<p style="font-size:15px;">' + details + '</p>' +
+    '</div>'
+  ;
+  topDoc.body.appendChild(outer);
+  var glass = outer.firstChild;
+  var glassStyle = glass.style;
+
+  // Scroll to the top and remove scrollbars.
+  topWin.scrollTo(0, 0);
+  if (topDoc.compatMode == "BackCompat") {
+    topDoc.body.style["overflow"] = "hidden";
+  } else {
+    topDoc.documentElement.style["overflow"] = "hidden";
+  }
+
+  // Steal focus.
+  glass.focus();
+
+ if ((navigator.userAgent.indexOf("MSIE") >= 0) && (topDoc.compatMode == "BackCompat")) {
+    // IE quirks mode doesn't support right/bottom, but does support this.
+    glassStyle.width = "125%";
+    glassStyle.height = "100%";
+  } else if (navigator.userAgent.indexOf("MSIE 6") >= 0) {
+    // IE6 doesn't have a real standards mode, so we have to use hacks.
+    glassStyle.width = "125%"; // Get past scroll bar area.
+ // Nasty CSS; onresize would be better but the outer window won't let us add a listener IE. + glassStyle.setExpression("height", "document.documentElement.clientHeight");
+  }
+
+  $doc.title = summary + " [" + $doc.title + "]";
+}
+
+function findPluginObject() {
+  try {
+    return document.getElementById('pluginObject');
+  } catch (e) {
+    return null;
+  }
+}
+
+function findPluginEmbed() {
+  try {
+    return document.getElementById('pluginEmbed')
+  } catch (e) {
+    return null;
+  }
+}
+
+function findPluginXPCOM() {
+  try {
+    return __gwt_HostedModePlugin;
+  } catch (e) {
+    return null;
+  }
+}
+
+gwtOnLoad = function(errFn, modName, modBase){
+  $moduleName = modName;
+  $moduleBase = modBase;
+
+  // Note that the order is important
+  var pluginFinders = [
+    findPluginXPCOM,
+    findPluginObject,
+    findPluginEmbed,
+  ];
+  var topWin = window.top;
+  var url = topWin.location.href;
+  if (!topWin.__gwt_SessionID) {
+    var ASCII_EXCLAMATION = 33;
+    var ASCII_TILDE = 126;
+    var chars = [];
+    for (var i = 0; i < 16; ++i) {
+      chars.push(Math.floor(ASCII_EXCLAMATION
+          + Math.random() * (ASCII_TILDE - ASCII_EXCLAMATION + 1)));
+    }
+    topWin.__gwt_SessionID = String.fromCharCode.apply(null, chars);
+  }
+  var plugin = null;
+  for (var i = 0; i < pluginFinders.length; ++i) {
+    try {
+      var maybePlugin = pluginFinders[i]();
+      if (maybePlugin != null && maybePlugin.init(window)) {
+        plugin = maybePlugin;
+        break;
+      }
+    } catch (e) {
+    }
+  }
+  if (!plugin) {
+    // try searching for a v1 plugin for backwards compatibility
+    var found = false;
+    for (var i = 0; i < pluginFinders.length; ++i) {
+      try {
+        plugin = pluginFinders[i]();
+ if (plugin != null && plugin.connect($hosted, $moduleName, window)) {
+          return;
+        }
+      } catch (e) {
+      }
+    }
+    loadIframe("http://gwt.google.com/missing-plugin";);
+  } else {
+    if (plugin.connect(url, topWin.__gwt_SessionID, $hosted, $moduleName,
+        $hostedHtmlVersion)) {
+      window.onUnload = function() {
+        try {
+ // wrap in try/catch since plugins are not required to supply this
+          plugin.disconnect();
+        } catch (e) {
+        }
+      };
+    } else {
+      if (errFn) {
+        errFn(modName);
+      } else {
+ alert("Plugin failed to connect to hosted mode server at " + $hosted); + loadIframe("http://code.google.com/p/google-web-toolkit/wiki/TroubleshootingOOPHM";);
+      }
+    }
+  }
+}
+
+window.onunload = function() {
+};
+
+// Lightweight metrics
+window.fireOnModuleLoadStart = function(className) {
+ $stats && $stats({moduleName:$moduleName, sessionId:$sessionId, subSystem:'startup', evtGroup:'moduleStartup', millis:(new Date()).getTime(), type:'onModuleLoadStart', className:className});
+};
+
+window.__gwt_module_id = 0;
+</script></head>
+<body>
+<font face='arial' size='-1'>This html file is for hosted mode support.</font>
+<script><!--
+// Lightweight metrics
+$stats && $stats({moduleName:$moduleName, sessionId:$sessionId, subSystem:'startup', evtGroup:'moduleStartup', millis:(new Date()).getTime(), type:'moduleEvalEnd'});
+
+// OOPHM currently only supports IFrameLinker
+var query = parent.location.search;
+if (!findPluginXPCOM()) {
+ document.write('<embed id="pluginEmbed" type="application/x-gwt-hosted-mode" width="10" height="10">');
+  document.write('</embed>');
+ document.write('<object id="pluginObject" CLASSID="CLSID:1D6156B6-002B-49E7-B5CA-C138FB843B4E">');
+  document.write('</object>');
+}
+
+// look for the old query parameter if we don't find the new one
+var idx = query.indexOf("gwt.codesvr=");
+if (idx >= 0) {
+  idx += 12;  // "gwt.codesvr=".length() == 12
+} else {
+  idx = query.indexOf("gwt.hosted=");
+  if (idx >= 0) {
+    idx += 11;  // "gwt.hosted=".length() == 11
+  }
+}
+if (idx >= 0) {
+  var amp = query.indexOf("&", idx);
+  if (amp >= 0) {
+    $hosted = query.substring(idx, amp);
+  } else {
+    $hosted = query.substring(idx);
+  }
+
+  // According to RFC 3986, some of this component's characters (e.g., ':')
+  // are reserved and *may* be escaped.
+  $hosted = decodeURIComponent($hosted);
+}
+
+query = window.location.search.substring(1);
+if (query && $wnd[query]) setTimeout(function() { $wnd[query].onScriptInstalled(gwtOnLoad) }, 1);
+--></script></body></html>
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/Linker.java Fri Jul 9 08:37:26 2010 +++ /trunk/dev/core/src/com/google/gwt/core/ext/Linker.java Wed Aug 18 11:12:36 2010
@@ -76,7 +76,7 @@

     return false;
   }
-
+
   /**
* This method is invoked for linkers not annotated with {...@link Shardable}. It
    * sees all artifacts across the whole compile and can modify them
@@ -150,4 +150,12 @@
       ArtifactSet newArtifacts) throws UnableToCompleteException {
     return newArtifacts;
   }
-}
+
+  /**
+   * Does this linker support DevMode?
+   */
+  public boolean supportsDevMode() {
+    // By default, linkers do not support Dev Mode
+    return false;
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java Tue Jun 22 06:26:45 2010 +++ /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java Wed Aug 18 11:12:36 2010
@@ -35,8 +35,10 @@

 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -175,10 +177,16 @@

       ArtifactSet toReturn = new ArtifactSet(artifacts);
       toReturn.add(emitSelectionScript(logger, context, artifacts));
+      maybeAddHostedModeFile(logger, toReturn);
       return toReturn;
     }
   }

+  @Override
+  public boolean supportsDevMode() {
+    return (getHostedFilename() != "");
+  }
+
   protected Collection<Artifact<?>> doEmitCompilation(TreeLogger logger,
       LinkerContext context, CompilationResult result)
       throws UnableToCompleteException {
@@ -322,6 +330,7 @@
     replaceAll(selectionScript, "__MODULE_FUNC__",
         context.getModuleFunctionName());
replaceAll(selectionScript, "__MODULE_NAME__", context.getModuleName()); + replaceAll(selectionScript, "__HOSTED_FILENAME__", getHostedFilename());

     int startPos;

@@ -428,7 +437,7 @@

     return selectionScript.toString();
   }
-
+
   /**
    * Generate a Snippet of JavaScript to inject an external stylesheet.
    *
@@ -460,6 +469,10 @@
   protected abstract String getCompilationExtension(TreeLogger logger,
       LinkerContext context) throws UnableToCompleteException;

+  protected String getHostedFilename() {
+    return "";
+  }
+
   /**
* Compute the beginning of a JavaScript file that will hold the main module
    * implementation.
@@ -487,6 +500,50 @@

   protected abstract String getSelectionScriptTemplate(TreeLogger logger,
       LinkerContext context) throws UnableToCompleteException;
+
+  /**
+   * Add the hosted file to the artifact set.
+   */
+ protected void maybeAddHostedModeFile(TreeLogger logger, ArtifactSet artifacts)
+      throws UnableToCompleteException {
+    String hostedFilename = getHostedFilename();
+    if ("".equals(hostedFilename)) {
+      return;
+    }
+    try {
+ URL resource = SelectionScriptLinker.class.getResource(hostedFilename);
+      if (resource == null) {
+        logger.log(TreeLogger.ERROR,
+            "Unable to find support resource: " + hostedFilename);
+        throw new UnableToCompleteException();
+      }
+
+      final URLConnection connection = resource.openConnection();
+      // TODO: extract URLArtifact class?
+      EmittedArtifact hostedFile = new EmittedArtifact(
+          SelectionScriptLinker.class, hostedFilename) {
+        @Override
+        public InputStream getContents(TreeLogger logger)
+            throws UnableToCompleteException {
+          try {
+            return connection.getInputStream();
+          } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to copy support resource", e);
+            throw new UnableToCompleteException();
+          }
+        }
+
+        @Override
+        public long getLastModified() {
+          return connection.getLastModified();
+        }
+      };
+      artifacts.add(hostedFile);
+    } catch (IOException e) {
+      logger.log(TreeLogger.ERROR, "Unable to copy support resource", e);
+      throw new UnableToCompleteException();
+    }
+  }

   /**
    * Find all instances of {...@link SelectionInformation} and add them to the
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java Tue Aug 10 07:06:57 2010 +++ /trunk/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java Wed Aug 18 11:12:36 2010
@@ -84,6 +84,11 @@
     return ".cache.js";
   }

+  @Override
+  protected String getHostedFilename() {
+    return "hosted_xsiframe.html";
+  }
+
   @Override
protected String getModulePrefix(TreeLogger logger, LinkerContext context,
       String strongName) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js Tue Aug 10 07:06:57 2010 +++ /trunk/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js Wed Aug 18 11:12:36 2010
@@ -29,9 +29,6 @@
   // The downloaded script code, once it arrives
   ,compiledScript

-  // Whether the main script has been injected yet
-  ,scriptInjected
-
   // The iframe holding the app's code
   ,scriptFrame

@@ -83,8 +80,7 @@
     try {
       var query = $wnd.location.search;
       return (query.indexOf('gwt.codesvr=') != -1
-          || query.indexOf('gwt.hosted=') != -1
-          || ($wnd.external && $wnd.external.gwtOnLoad)) &&
+          || query.indexOf('gwt.hosted=') != -1) &&
           (query.indexOf('gwt.hybrid') == -1);
     } catch (e) {
       // Defensive: some versions of IE7 reportedly can throw an exception
@@ -94,14 +90,13 @@
     return result;
   }

-  // Called when the body has been finished and when the script
-  // to install is available. These can happen in either order.
-  // When both have happened, create the code-holding iframe.
-  //
+  // This function is called on two events: the body has finished
+  // loading, and the script to install is available. For hosted
+  // mode, install the hosted file as soon as the body is done.
+  // For prod mode, additionally wait until the script to install
+  // has been loaded, and then install the code.
   function maybeCreateFrame() {
-    if (bodyDone && compiledScript && !scriptInjected) {
-       scriptInjected = true;
-
+    if (bodyDone && !scriptFrame && (isHostedMode() || compiledScript)) {
        // Create the script frame, making sure it's invisible, but not
        // "display:none", which keeps some browsers from running code in it.
        scriptFrame = $doc.createElement('iframe');
@@ -114,7 +109,15 @@
         // For some reason, adding this setTimeout makes code installation
         // more reliable.
         setTimeout(function() {
-          installCode(compiledScript);
+            if (isHostedMode()) {
+ // TODO(unnurg) changing the src introduces cross-site problems
+              // Neeed to add a hosted-xsiframe.js and install a script tag
+              // pointing at it
+              scriptFrame.contentWindow.location.replace(
+                         base + "__HOSTED_FILENAME__?__MODULE_FUNC__");
+            } else {
+              installCode(compiledScript);
+            }
         })
     }
   }
@@ -222,6 +225,9 @@
   __MODULE_FUNC__.onScriptInstalled = function(gwtOnLoadFunc) {
     // remove the callback to prevent it being called twice
     __MODULE_FUNC__.onScriptInstalled = null;
+    if (isHostedMode()) {
+      scriptFrame.contentWindow.__gwt_getProperty = computePropValue;
+    }
gwtOnLoadFunc(onLoadErrorFunc, '__MODULE_NAME__', base, softPermutationId);
     // Record when the module EntryPoints return.
     $stats && $stats({
@@ -240,12 +246,6 @@

   // --------------- STRAIGHT-LINE CODE ---------------

-  if (isHostedMode()) {
-    alert("Cross-site hosted mode not yet implemented. See issue " +
-      "http://code.google.com/p/google-web-toolkit/issues/detail?id=2079";);
-    return;
-  }
-
   // do it early for compile/browse rebasing
   processMetas();
   computeScriptBase();
@@ -262,20 +262,22 @@
   });

   var strongName;
-  try {
+  if (!isHostedMode()) {
+    try {
 // __PERMUTATIONS_BEGIN__
-    // Permutation logic
+      // Permutation logic
 // __PERMUTATIONS_END__
-    var idx = strongName.indexOf(':');
-    if (idx != -1) {
-      softPermutationId = +(strongName.substring(idx + 1));
-      strongName = strongName.substring(0, idx);
-    }
-  } catch (e) {
-    // intentionally silent on property failure
-    return;
-  }
-
+      var idx = strongName.indexOf(':');
+      if (idx != -1) {
+        softPermutationId = +(strongName.substring(idx + 1));
+        strongName = strongName.substring(0, idx);
+      }
+    } catch (e) {
+      // intentionally silent on property failure
+      return;
+    }
+  }
+
   var onBodyDoneTimerId;
   function onBodyDone() {
     if (!bodyDone) {
@@ -329,7 +331,6 @@
 // __MODULE_SCRIPTS_BEGIN__
   // Script resources are injected here
 // __MODULE_SCRIPTS_END__
-
// This is a bit ugly, but serves a purpose. We need to ensure that the stats // script runs before the compiled script. If they are both doc.write()n in
   // sequence, that should be the effect. Except on IE it turns out that a
@@ -338,7 +339,10 @@
   // some apps. The final solution was simply to inject the compiled script
// from *within* the stats script, guaranteeing order at the expense of near
   // total inscrutability :(
- var compiledScriptTag = '"<script src=\\"' + base + strongName + '.cache.js\\"></scr" + "ipt>"';
+  var compiledScriptWrite = '';
+  if (!isHostedMode()) {
+ compiledScriptWrite = 'document.write("<script src=\\"' + base + strongName + '.cache.js\\"></scr" + "ipt>");';
+  }

   $doc.write('<scr' + 'ipt><!-' + '-\n'
     + 'window.__gwtStatsEvent && window.__gwtStatsEvent({'
@@ -349,7 +353,7 @@
+ 'moduleName:"__MODULE_NAME__", sessionId:window.__gwtStatsSessionId, subSystem:"startup",'
     + 'evtGroup: "moduleStartup", millis:(new Date()).getTime(),'
     + 'type: "moduleRequested"});'
-    + 'document.write(' + compiledScriptTag + ');'
+    + compiledScriptWrite
     + '\n-' + '-></scr' + 'ipt>');
 }

=======================================
--- /trunk/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java Wed Mar 31 06:57:50 2010 +++ /trunk/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java Wed Aug 18 11:12:36 2010
@@ -18,24 +18,17 @@
 import com.google.gwt.core.ext.LinkerContext;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.linker.ArtifactSet;
 import com.google.gwt.core.ext.linker.CompilationResult;
 import com.google.gwt.core.ext.linker.ConfigurationProperty;
-import com.google.gwt.core.ext.linker.EmittedArtifact;
 import com.google.gwt.core.ext.linker.LinkerOrder;
 import com.google.gwt.core.ext.linker.Shardable;
 import com.google.gwt.core.ext.linker.StatementRanges;
 import com.google.gwt.core.ext.linker.LinkerOrder.Order;
-import com.google.gwt.core.ext.linker.impl.HostedModeLinker;
 import com.google.gwt.core.ext.linker.impl.SelectionScriptLinker;
 import com.google.gwt.dev.About;
 import com.google.gwt.dev.util.DefaultTextOutput;
 import com.google.gwt.dev.util.Util;

-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
 import java.util.SortedSet;

 /**
@@ -116,54 +109,6 @@
   public String getDescription() {
     return "Standard";
   }
-
-  @Override
-  public ArtifactSet link(TreeLogger logger, LinkerContext context,
- ArtifactSet artifacts, boolean onePerm) throws UnableToCompleteException {
-    ArtifactSet toReturn = super.link(logger, context, artifacts, onePerm);
-
-    if (onePerm) {
-      return toReturn;
-    }
-
-    try {
-      // Add hosted mode iframe contents
-      // TODO move this into own impl package if HostedModeLinker goes away
-      URL resource = HostedModeLinker.class.getResource("hosted.html");
-      if (resource == null) {
-        logger.log(TreeLogger.ERROR,
-            "Unable to find support resource 'hosted.html'");
-        throw new UnableToCompleteException();
-      }
-
-      final URLConnection connection = resource.openConnection();
-      // TODO: extract URLArtifact class?
-      EmittedArtifact hostedHtml = new EmittedArtifact(IFrameLinker.class,
-          "hosted.html") {
-        @Override
-        public InputStream getContents(TreeLogger logger)
-            throws UnableToCompleteException {
-          try {
-            return connection.getInputStream();
-          } catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Unable to copy support resource", e);
-            throw new UnableToCompleteException();
-          }
-        }
-
-        @Override
-        public long getLastModified() {
-          return connection.getLastModified();
-        }
-      };
-      toReturn.add(hostedHtml);
-    } catch (IOException e) {
-      logger.log(TreeLogger.ERROR, "Unable to copy support resource", e);
-      throw new UnableToCompleteException();
-    }
-
-    return toReturn;
-  }

   /*
* This implementation divides the code of the initial fragment into multiple
@@ -184,7 +129,7 @@
     b.append(getModuleSuffix(logger, context));
     return Util.getBytes(b.toString());
   }
-
+
   @Override
   protected String getCompilationExtension(TreeLogger logger,
       LinkerContext context) {
@@ -214,6 +159,11 @@

     return subdir;
   }
+
+  @Override
+  protected String getHostedFilename() {
+    return "hosted.html";
+  }

   @Override
protected String getModulePrefix(TreeLogger logger, LinkerContext context,
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js Thu Mar 25 12:00:47 2010 +++ /trunk/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js Wed Aug 18 11:12:36 2010
@@ -249,7 +249,7 @@
       $wnd.location.reload();
       return;
     }
-    initialHtml = "hosted.html?__MODULE_FUNC__";
+    initialHtml = "__HOSTED_FILENAME__?__MODULE_FUNC__";
     strongName = "";
   }

=======================================
--- /trunk/user/src/com/google/gwt/junit/JUnitShell.java Thu Aug 12 07:56:03 2010 +++ /trunk/user/src/com/google/gwt/junit/JUnitShell.java Wed Aug 18 11:12:36 2010
@@ -1092,10 +1092,16 @@
       }
     }
     if (developmentMode) {
-      // BACKWARDS COMPATIBILITY: most linkers currently fail in dev mode.
-      if (module.getLinker("std") != null) {
- // TODO: unfortunately, this could be race condition between dev/prod
-        module.addLinker("std");
+      // BACKWARDS COMPATIBILITY: many linkers currently fail in dev mode.
+      try {
+ if (!module.getActivePrimaryLinker().newInstance().supportsDevMode()) {
+          if (module.getLinker("std") != null) {
+ // TODO: unfortunately, this could be race condition between dev/prod
+            module.addLinker("std");
+          }
+        }
+      } catch (Exception e) {
+ getTopLogger().log(TreeLogger.WARN, "Failed to instantiate linker: " + e);
       }
       super.link(getTopLogger(), module);
     } else {
=======================================
--- /trunk/user/test/com/google/gwt/core/ext/test/CrossSiteIframeLinkerTest.java Tue Aug 10 07:06:57 2010 +++ /trunk/user/test/com/google/gwt/core/ext/test/CrossSiteIframeLinkerTest.java Wed Aug 18 11:12:36 2010
@@ -16,13 +16,10 @@

 package com.google.gwt.core.ext.test;

-import com.google.gwt.junit.DoNotRunWith;
-import com.google.gwt.junit.Platform;

 /**
  * Integration test of the cross-site iframe linker.
  */
-...@donotrunwith(Platform.Devel)
 public class CrossSiteIframeLinkerTest extends LinkerTest {
   @Override
   public String getModuleName() {

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

Reply via email to