Author: [email protected]
Date: Wed May 27 06:48:54 2009
New Revision: 5475

Added:
     
trunk/user/src/com/google/gwt/resources/rebind/context/MhtmlClientBundleGenerator.java
     
trunk/user/src/com/google/gwt/resources/rebind/context/MhtmlResourceContext.java
Modified:
    trunk/user/src/com/google/gwt/resources/Resources.gwt.xml
    trunk/user/src/com/google/gwt/resources/client/CssResource.java
     
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
     
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractResourceContext.java
     
trunk/user/src/com/google/gwt/resources/rebind/context/InlineResourceContext.java
     
trunk/user/src/com/google/gwt/resources/rebind/context/StaticResourceContext.java

Log:
Add MHTML / RFC 2557 support to ClientBundle for ie6 user.agent.
Enable data: urls for ie8 user.agent.
Update documentation location in CssResource JavaDoc.

Patch by: bobv
Review by: rjrjr


Modified: trunk/user/src/com/google/gwt/resources/Resources.gwt.xml
==============================================================================
--- trunk/user/src/com/google/gwt/resources/Resources.gwt.xml   (original)
+++ trunk/user/src/com/google/gwt/resources/Resources.gwt.xml   Wed May 27  
06:48:54 2009
@@ -23,7 +23,7 @@
    <define-property name="ClientBundle.enableInlining" values="true,false"  
/>
    <set-property name="ClientBundle.enableInlining" value="true" />

-  <!-- Specify the default behavior -->
+  <!-- Specify the default behavior which should work on all browsers -->
    <generate-with
       
class="com.google.gwt.resources.rebind.context.StaticClientBundleGenerator">

@@ -34,6 +34,24 @@

    <!-- Last-matches wins, so this will selectively override the previous  
rule -->
    <generate-with
+     
class="com.google.gwt.resources.rebind.context.MhtmlClientBundleGenerator">
+
+    <!-- We have a number of conditions that must be satisfied -->
+    <all>
+      <!-- Is inlining enabled? -->
+      <when-property-is name="ClientBundle.enableInlining" value="true" />
+
+      <!-- Again, it's necessary to specify which types the generator runs  
on -->
+      <when-type-assignable
+        class="com.google.gwt.resources.client.ClientBundle" />
+
+      <!-- Do this only with IE6 browsers -->
+      <when-property-is name="user.agent" value="ie6" />
+    </all>
+  </generate-with>
+
+  <!-- Last-matches wins, so this will selectively override the previous  
rule -->
+  <generate-with
       
class="com.google.gwt.resources.rebind.context.InlineClientBundleGenerator">

      <!-- We have a number of conditions that must be satisfied -->
@@ -51,6 +69,7 @@
          <when-property-is name="user.agent" value="opera" />
          <when-property-is name="user.agent" value="gecko" />
          <when-property-is name="user.agent" value="gecko1_8" />
+        <when-property-is name="user.agent" value="ie8" />
        </any>
      </all>
    </generate-with>

Modified: trunk/user/src/com/google/gwt/resources/client/CssResource.java
==============================================================================
--- trunk/user/src/com/google/gwt/resources/client/CssResource.java      
(original)
+++ trunk/user/src/com/google/gwt/resources/client/CssResource.java     Wed May 
 
27 06:48:54 2009
@@ -90,8 +90,7 @@
   * </li>
   * </ul>
   *
- * @see <a
- *       
href="http://code.google.com/p/google-web-toolkit-incubator/wiki/CssResource";
+ * @see <a  
href="http://code.google.com/p/google-web-toolkit/wiki/CssResource";
   *      >CssResource design doc</a>
   */
  @ResourceGeneratorType(CssResourceGenerator.class)

Modified:  
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
==============================================================================
---  
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
        
(original)
+++  
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java
        
Wed May 27 06:48:54 2009
@@ -170,6 +170,7 @@
      FieldsImpl fields = new FieldsImpl();
      RequirementsImpl requirements = new RequirementsImpl(
          generatorContext.getPropertyOracle());
+    doAddFieldsAndRequirements(logger, generatorContext, fields,  
requirements);

      /*
       * Initialize the ResourceGenerators and prepare them for subsequent  
code
@@ -230,6 +231,7 @@
      }

      finish(logger, resourceContext, generators.keySet());
+    doFinish();

      // Return the name of the concrete class
      return createdClassName;
@@ -241,7 +243,23 @@
     * custom logic in the resource generation pass.
     */
    protected abstract AbstractResourceContext createResourceContext(
-      TreeLogger logger, GeneratorContext context, JClassType  
resourceBundleType);
+      TreeLogger logger, GeneratorContext context, JClassType  
resourceBundleType)
+      throws UnableToCompleteException;
+
+  /**
+   * Provides a hook for subtypes to add additional fields or requirements  
to
+   * the bundle.
+   */
+  protected void doAddFieldsAndRequirements(TreeLogger logger,
+      GeneratorContext context, ClientBundleFields fields,
+      ClientBundleRequirements requirements) throws  
UnableToCompleteException {
+  }
+
+  /**
+   * Provides a hook for finalizing generated resources.
+   */
+  protected void doFinish() throws UnableToCompleteException {
+  }

    /**
     * Create fields and assignments for a single ResourceGenerator.

Modified:  
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractResourceContext.java
==============================================================================
---  
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractResourceContext.java
      
(original)
+++  
trunk/user/src/com/google/gwt/resources/rebind/context/AbstractResourceContext.java
      
Wed May 27 06:48:54 2009
@@ -17,13 +17,32 @@

  import com.google.gwt.core.ext.GeneratorContext;
  import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
  import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.dev.util.Util;
  import com.google.gwt.resources.ext.ResourceContext;
+import com.google.gwt.resources.ext.ResourceGeneratorUtil;
+
+import java.io.IOException;
+import java.net.URL;

  /**
   * Defines base methods for ResourceContext implementations.
   */
  public abstract class AbstractResourceContext implements ResourceContext {
+  /**
+   * The largest file size that will be inlined. Note that this value is  
taken
+   * before any encodings are applied.
+   */
+  protected static final int MAX_INLINE_SIZE = 2 << 15;
+
+  protected static String toBase64(byte[] data) {
+    // This is bad, but I am lazy and don't want to write _another_ encoder
+    sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
+    String base64Contents = enc.encode(data).replaceAll("\\s+", "");
+    return base64Contents;
+  }
+
    private final TreeLogger logger;
    private final GeneratorContext context;
    private final JClassType resourceBundleType;
@@ -36,6 +55,20 @@
      this.resourceBundleType = resourceBundleType;
    }

+  public String deploy(URL resource, boolean xhrCompatible)
+      throws UnableToCompleteException {
+    String fileName = ResourceGeneratorUtil.baseName(resource);
+    byte[] bytes = Util.readURLAsBytes(resource);
+    try {
+      return deploy(fileName, resource.openConnection().getContentType(),
+          bytes, xhrCompatible);
+    } catch (IOException e) {
+      getLogger().log(TreeLogger.ERROR,
+          "Unable to determine mime type of resource", e);
+      throw new UnableToCompleteException();
+    }
+  }
+
    public JClassType getClientBundleType() {
      return resourceBundleType;
    }
@@ -50,6 +83,10 @@
            "Simple source name has not yet been set.");
      }
      return simpleSourceName;
+  }
+
+  protected GeneratorContext getContext() {
+    return context;
    }

    protected TreeLogger getLogger() {

Modified:  
trunk/user/src/com/google/gwt/resources/rebind/context/InlineResourceContext.java
==============================================================================
---  
trunk/user/src/com/google/gwt/resources/rebind/context/InlineResourceContext.java
        
(original)
+++  
trunk/user/src/com/google/gwt/resources/rebind/context/InlineResourceContext.java
        
Wed May 27 06:48:54 2009
@@ -21,15 +21,6 @@
  import com.google.gwt.core.ext.typeinfo.JClassType;

  class InlineResourceContext extends StaticResourceContext {
-  /**
-   * The largest file size that will be inlined. Note that this value is  
taken
-   * before any encodings are applied.
-   */
-  // The JLS specifies a maximum size for any string to be 2^16  
characters, so
-  // we'll leave some padding. Assuming a Base64 encoding, it is true that
-  // (2 ^ 15) * 4/3 < 2 ^ 16, so we can safely inline files up to 32k.
-  private static final int MAX_INLINE_SIZE = 2 << 15;
-
    InlineResourceContext(TreeLogger logger, GeneratorContext context,
        JClassType resourceBundleType) {
      super(logger, context, resourceBundleType);
@@ -44,9 +35,7 @@
      if ((!xhrCompatible) && (data.length < MAX_INLINE_SIZE)) {
        logger.log(TreeLogger.DEBUG, "Inlining", null);

-      // This is bad, but I am lazy and don't want to write _another_  
encoder
-      sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
-      String base64Contents = enc.encode(data).replaceAll("\\s+", "");
+      String base64Contents = toBase64(data);

        return "\"data:" + mimeType + ";base64," + base64Contents + "\"";
      } else {

Added:  
trunk/user/src/com/google/gwt/resources/rebind/context/MhtmlClientBundleGenerator.java
==============================================================================
--- (empty file)
+++  
trunk/user/src/com/google/gwt/resources/rebind/context/MhtmlClientBundleGenerator.java
   
Wed May 27 06:48:54 2009
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2009 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.resources.rebind.context;
+
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracleException;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.resources.ext.ClientBundleFields;
+import com.google.gwt.resources.ext.ClientBundleRequirements;
+
+/**
+ * Generates Multipart HTML files.
+ */
+public class MhtmlClientBundleGenerator extends  
AbstractClientBundleGenerator {
+
+  private static final String BUNDLE_EXTENSION = ".cache.txt";
+
+  private MhtmlResourceContext resourceContext;
+  private String partialPath;
+
+  @Override
+  protected AbstractResourceContext createResourceContext(TreeLogger  
logger,
+      GeneratorContext context, JClassType resourceBundleType) {
+    resourceContext = new MhtmlResourceContext(logger, context,
+        resourceBundleType);
+
+    /*
+     * TODO: figure out how to make the filename stable based on actual  
content.
+     */
+    partialPath =  
Util.computeStrongName(Util.getBytes(resourceBundleType.getQualifiedSourceName()
+        + System.currentTimeMillis()))
+        + BUNDLE_EXTENSION;
+    resourceContext.setPartialPath(partialPath);
+
+    return resourceContext;
+  }
+
+  @Override
+  protected void doAddFieldsAndRequirements(TreeLogger logger,
+      GeneratorContext generatorContext, ClientBundleFields fields,
+      ClientBundleRequirements requirements) throws  
UnableToCompleteException {
+    JType booleanType;
+    JType stringType;
+    try {
+      booleanType = generatorContext.getTypeOracle().parse("boolean");
+      stringType =  
generatorContext.getTypeOracle().parse("java.lang.String");
+    } catch (TypeOracleException e) {
+      logger.log(TreeLogger.ERROR, "Expected type not in type oracle", e);
+      throw new UnableToCompleteException();
+    }
+
+    // GWT.getModuleBaseURL().startsWith("https")
+    String isHttpsIdent = fields.define(booleanType, "isHttps",
+        "GWT.getModuleBaseURL().startsWith(\"https\")", true, true);
+    resourceContext.setIsHttpsIdent(isHttpsIdent);
+
+    // "mhtml:" + GWT.getModuleBaseURL() + "partialPath!cid:"
+    String bundleBaseIdent = fields.define(stringType, "bundleBase",
+        "\"mhtml:\" + GWT.getModuleBaseURL() + \"" + partialPath  
+ "!cid:\"",
+        true, true);
+    resourceContext.setBundleBaseIdent(bundleBaseIdent);
+  }
+
+  @Override
+  protected void doFinish() throws UnableToCompleteException {
+    resourceContext.finish();
+  }
+}

Added:  
trunk/user/src/com/google/gwt/resources/rebind/context/MhtmlResourceContext.java
==============================================================================
--- (empty file)
+++  
trunk/user/src/com/google/gwt/resources/rebind/context/MhtmlResourceContext.java
         
Wed May 27 06:48:54 2009
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2009 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.resources.rebind.context;
+
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+/**
+ * Encodes resources into Multipart HTML files. In order to avoid  
mixed-content
+ * warnings using the mhtml: protocol, this context will include a  
fallback to
+ * static files when the module has been loaded from an https source.
+ *
+ * @see "RFC 2557"
+ */
+public class MhtmlResourceContext extends StaticResourceContext {
+
+  /**
+   * The MIME multipart boundary token. This is chosen so that it does not
+   * overlap with any possible base64 sequences.
+   */
+  private static final String BOUNDARY = "_GWT";
+  private static final String ID_PREFIX = "r";
+
+  private String bundleBaseIdent;
+  private int id = 0;
+  private String isHttpsIdent;
+
+  /**
+   * Output is lazily initialized in the case that all deployed resources  
are
+   * large.
+   */
+  private OutputStream out;
+  private String partialPath;
+  private PrintWriter pw;
+
+  MhtmlResourceContext(TreeLogger logger, GeneratorContext context,
+      JClassType resourceBundleType) {
+    super(logger, context, resourceBundleType);
+  }
+
+  @Override
+  public String deploy(String suggestedFileName, String mimeType, byte[]  
data,
+      boolean xhrCompatible) throws UnableToCompleteException {
+
+    assert partialPath != null : "partialPath";
+    assert isHttpsIdent != null : "isHttpsIdent";
+    assert bundleBaseIdent != null : "bundleBaseIdent";
+
+    /*
+     * mhtml URLs don't work in HTTPS, so we'll always need the static  
versions
+     * as a fallback.
+     */
+    String staticLocation = super.deploy(suggestedFileName, mimeType, data,
+        xhrCompatible);
+
+    /*
+     * ie6 doesn't treat XHRs to mhtml as cross-site, but ie8 does, so  
we'll
+     * play it safe here.
+     */
+    if (xhrCompatible || data.length > MAX_INLINE_SIZE) {
+      return staticLocation;
+    }
+
+    if (out == null) {
+      out = getContext().tryCreateResource(getLogger(), partialPath);
+      pw = new PrintWriter(out);
+      pw.println("Content-Type: multipart/related; boundary=\"" + BOUNDARY
+          + "\"");
+      pw.println();
+    }
+
+    String location = ID_PREFIX + id++;
+    String base64 = toBase64(data);
+
+    pw.println("--" + BOUNDARY);
+    pw.println("Content-Id:<" + location + ">");
+    pw.println("Content-Type:" + mimeType);
+    pw.println("Content-Transfer-Encoding:base64");
+    pw.println();
+    pw.println(base64);
+    pw.println();
+
+    /*
+     * Return a Java expression:
+     *
+     * isHttps ? (staticLocation) : (bundleBaseIdent + "location")
+     */
+    return isHttpsIdent + " ? (" + staticLocation + ") : (" +  
bundleBaseIdent
+        + " + \"" + location + "\")";
+  }
+
+  public void finish() throws UnableToCompleteException {
+    if (out != null) {
+      pw.close();
+      getContext().commitResource(getLogger(), out);
+    }
+  }
+
+  @Override
+  public boolean supportsDataUrls() {
+    return true;
+  }
+
+  void setBundleBaseIdent(String ident) {
+    bundleBaseIdent = ident;
+  }
+
+  void setIsHttpsIdent(String ident) {
+    isHttpsIdent = ident;
+  }
+
+  void setPartialPath(String partialPath) {
+    this.partialPath = partialPath;
+  }
+}

Modified:  
trunk/user/src/com/google/gwt/resources/rebind/context/StaticResourceContext.java
==============================================================================
---  
trunk/user/src/com/google/gwt/resources/rebind/context/StaticResourceContext.java
        
(original)
+++  
trunk/user/src/com/google/gwt/resources/rebind/context/StaticResourceContext.java
        
Wed May 27 06:48:54 2009
@@ -23,11 +23,9 @@
  import com.google.gwt.core.ext.UnableToCompleteException;
  import com.google.gwt.core.ext.typeinfo.JClassType;
  import com.google.gwt.dev.util.Util;
-import com.google.gwt.resources.ext.ResourceGeneratorUtil;

  import java.io.IOException;
  import java.io.OutputStream;
-import java.net.URL;

  class StaticResourceContext extends AbstractResourceContext {
    /**
@@ -50,8 +48,7 @@
      // See if filename obfuscation should be enabled
      String enableRenaming = null;
      try {
-      ConfigurationProperty prop = propertyOracle.getConfigurationProperty(
-          ENABLE_RENAMING);
+      ConfigurationProperty prop =  
propertyOracle.getConfigurationProperty(ENABLE_RENAMING);
        enableRenaming = prop.getValues().get(0);
      } catch (BadPropertyValueException e) {
        logger.log(TreeLogger.ERROR, "Bad value for " + ENABLE_RENAMING, e);
@@ -103,20 +100,6 @@

      // Return a Java expression
      return "GWT.getModuleBaseURL() + \"" + outputName + "\"";
-  }
-
-  public String deploy(URL resource, boolean xhrCompatible)
-      throws UnableToCompleteException {
-    String fileName = ResourceGeneratorUtil.baseName(resource);
-    byte[] bytes = Util.readURLAsBytes(resource);
-    try {
-      return deploy(fileName, resource.openConnection().getContentType(),
-          bytes, xhrCompatible);
-    } catch (IOException e) {
-      getLogger().log(TreeLogger.ERROR,
-          "Unable to determine mime type of resource", e);
-      throw new UnableToCompleteException();
-    }
    }

    public boolean supportsDataUrls() {

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

Reply via email to