Revision: 10357
Author:   jbrosenb...@google.com
Date:     Tue Jun 21 04:31:29 2011
Log:      Updated rpc generator result caching to support full cacheability
Also added support for changes to relevant properties and custom field serializers

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

http://code.google.com/p/google-web-toolkit/source/detail?r=10357

Added:
/trunk/user/src/com/google/gwt/user/rebind/rpc/CachedRpcTypeInformation.java
Modified:
 /trunk/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
/trunk/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java /trunk/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java
 /trunk/user/src/com/google/gwt/user/rebind/rpc/Shared.java
 /trunk/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java

=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/user/rebind/rpc/CachedRpcTypeInformation.java Tue Jun 21 04:31:29 2011
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2011 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.user.rebind.rpc;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JArrayType;
+import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JRawType;
+import com.google.gwt.core.ext.typeinfo.JRealClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A container for type information, for use with generator result caching.
+ */
+public class CachedRpcTypeInformation implements Serializable {
+ private final Map<String, Long> lastModifiedTimes = new HashMap<String, Long>(); + private final Set<String> instantiableFromBrowser = new HashSet<String>();
+  private final Set<String> instantiableToBrowser = new HashSet<String>();
+ private final Set<String> serializableFromBrowser = new HashSet<String>();
+  private final Set<String> serializableToBrowser = new HashSet<String>();
+ private final Set<String> typesNotUsingCustomSerializer = new HashSet<String>();
+  private final Set<String> customSerializerTypes = new HashSet<String>();
+
+  public CachedRpcTypeInformation(SerializableTypeOracle typesFromBrowser,
+ SerializableTypeOracle typesToBrowser, Set<JType> customSerializersUsed,
+      Set<JType> typesNotUsingCustomSerializers) {
+
+ recordTypes(serializableFromBrowser, instantiableFromBrowser, typesFromBrowser); + recordTypes(serializableToBrowser, instantiableToBrowser, typesToBrowser);
+
+    for (JType type : customSerializersUsed) {
+      addCustomSerializerType(type);
+    }
+
+    for (JType type : typesNotUsingCustomSerializers) {
+      addTypeNotUsingCustomSerializer(type);
+    }
+  }
+
+  public void addCustomSerializerType(JType type) {
+    String sourceName = type.getQualifiedSourceName();
+    lastModifiedTimes.put(sourceName, getLastModifiedTime(type));
+    customSerializerTypes.add(sourceName);
+  }
+
+  public void addTypeNotUsingCustomSerializer(JType type) {
+    String sourceName = type.getQualifiedSourceName();
+    typesNotUsingCustomSerializer.add(sourceName);
+  }
+
+  public boolean checkLastModifiedTime(JType type) {
+    Long cachedTime = lastModifiedTimes.get(type.getQualifiedSourceName());
+    if (cachedTime == null) {
+      return false;
+    }
+    return cachedTime == getLastModifiedTime(type);
+  }
+
+ public boolean checkTypeInformation(TreeLogger logger, TypeOracle typeOracle, + SerializableTypeOracle typesFromBrowser, SerializableTypeOracle typesToBrowser) {
+
+    JType[] typesFrom = typesFromBrowser.getSerializableTypes();
+    if (typesFrom.length != serializableFromBrowser.size()) {
+      if (logger.isLoggable(TreeLogger.TRACE)) {
+        logger.log(TreeLogger.TRACE,
+ "The number of serializable types sent from the browser has changed"); + logDifferencesBetweenCurrentAndCachedTypes(logger, typesFrom, serializableFromBrowser);
+      }
+      return false;
+    }
+
+    JType[] typesTo = typesToBrowser.getSerializableTypes();
+    if (typesTo.length != serializableToBrowser.size()) {
+      if (logger.isLoggable(TreeLogger.TRACE)) {
+        logger.log(TreeLogger.TRACE,
+ "The number of serializable types sent to the browser has changed"); + logDifferencesBetweenCurrentAndCachedTypes(logger, typesTo, serializableToBrowser);
+      }
+      return false;
+    }
+
+ if (!checkTypes(logger, serializableFromBrowser, instantiableFromBrowser, typesFromBrowser) + || !checkTypes(logger, serializableToBrowser, instantiableToBrowser, typesToBrowser)) {
+      return false;
+    }
+
+    for (String customSerializerType : customSerializerTypes) {
+      JType currType = typeOracle.findType(customSerializerType);
+      if (currType == null) {
+ logger.log(TreeLogger.TRACE, "Custom serializer no longer available: "
+            + customSerializerType);
+        return false;
+      }
+      if (!checkLastModifiedTime(currType)) {
+ logger.log(TreeLogger.TRACE, "A change was detected in custom serializer: "
+            + customSerializerType);
+        return false;
+      }
+    }
+
+    for (String sourceName : typesNotUsingCustomSerializer) {
+      String fieldSerializerName =
+ SerializableTypeOracleBuilder.getCustomFieldSerializerName(sourceName); + if (SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, fieldSerializerName) != null) { + logger.log(TreeLogger.TRACE, "A new custom serializer is available " + sourceName);
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  public boolean checkTypeNotUsingCustomSerializer(JType type) {
+ return typesNotUsingCustomSerializer.contains(type.getQualifiedSourceName());
+  }
+
+  /*
+   * Finds a last modified time for a type, for testing cacheability.
+   */
+  public long getLastModifiedTime(JType type) {
+    JType typeToCheck;
+    if (type instanceof JArrayType) {
+      typeToCheck = type.getLeafType();
+    } else if (type instanceof JRawType) {
+      typeToCheck = ((JRawType) type).getGenericType();
+    } else {
+      assert type instanceof JRealClassType;
+      typeToCheck = type;
+    }
+
+    if (typeToCheck instanceof JRealClassType) {
+      return ((JRealClassType) typeToCheck).getLastModifiedTime();
+    } else {
+      // we have a type that is an array with a primitive leafType
+      assert typeToCheck instanceof JPrimitiveType;
+      // this type is never out of date
+      return Long.MAX_VALUE;
+    }
+  }
+
+ private boolean checkTypes(TreeLogger logger, Set<String> serializable, Set<String> instantiable,
+      SerializableTypeOracle sto) {
+    for (JType type : sto.getSerializableTypes()) {
+      String sourceName = type.getQualifiedSourceName();
+      if (sto.isSerializable(type) != serializable.contains(sourceName)
+ || sto.maybeInstantiated(type) != instantiable.contains(sourceName)
+          || !checkLastModifiedTime(type)) {
+ logger.log(TreeLogger.TRACE, "A change was detected in type " + sourceName);
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private void logDifferencesBetweenCurrentAndCachedTypes(TreeLogger logger, JType[] currentTypes,
+      Set<String> cachedTypes) {
+
+    Set<String> remainingCachedTypes = new HashSet<String>(cachedTypes);
+    for (JType currentType : currentTypes) {
+      String sourceName = currentType.getQualifiedSourceName();
+      if (!remainingCachedTypes.remove(sourceName)) {
+ logger.log(TreeLogger.TRACE, "New type " + sourceName + " not in cached list");
+      }
+    }
+
+    for (String remainingCachedType : remainingCachedTypes) {
+ logger.log(TreeLogger.TRACE, "Cached type " + remainingCachedType + " not in new list");
+    }
+  }
+
+ private void recordTypes(Set<String> serializable, Set<String> instantiable,
+      SerializableTypeOracle sto) {
+    for (JType type : sto.getSerializableTypes()) {
+      String sourceName = type.getQualifiedSourceName();
+      lastModifiedTimes.put(sourceName, getLastModifiedTime(type));
+      serializable.add(sourceName);
+      if (sto.maybeInstantiated(type)) {
+        instantiable.add(sourceName);
+      }
+    }
+  }
+}
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java Tue Jun 14 12:19:31 2011 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java Tue Jun 21 04:31:29 2011
@@ -37,6 +37,10 @@
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.generator.NameFactory;
 import com.google.gwt.dev.javac.rebind.CachedClientDataMap;
+import com.google.gwt.dev.javac.rebind.CachedPropertyInformation;
+import com.google.gwt.dev.javac.rebind.CachedRebindResult;
+import com.google.gwt.dev.javac.rebind.RebindResult;
+import com.google.gwt.dev.javac.rebind.RebindStatus;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
 import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
@@ -71,6 +75,7 @@
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -82,16 +87,42 @@
  * as well as the necessary type and field serializers.
  */
 public class ProxyCreator {
+  /**
+   * Some keys for storing cached information for use with generator result
+   * caching.
+   */
+ public static final String CACHED_PROPERTY_INFO_KEY = "cached-property-info";
+  public static final String CACHED_TYPE_INFO_KEY = "cached-type-info";
+
   /**
    * The directory within which RPC manifests are placed for individual
    * permutations.
    */
public static final String MANIFEST_ARTIFACT_DIR = "rpcPolicyManifest/manifests";

- private static final Map<JPrimitiveType, ResponseReader> JPRIMITIVETYPE_TO_RESPONSEREADER =
-      new HashMap<JPrimitiveType, ResponseReader>();
+  /**
+   * Properties which need to be checked to determine cacheability.
+   */
+ private static final Collection<String> configPropsToCheck = Arrays.asList( + TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC, Shared.RPC_ENHANCED_CLASSES);
+  private static final Collection<String> selectionPropsToCheck = Arrays
+      .asList(Shared.RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS);

   private static final String PROXY_SUFFIX = "_Proxy";
+
+ private static final Map<JPrimitiveType, ResponseReader> JPRIMITIVETYPE_TO_RESPONSEREADER =
+      new HashMap<JPrimitiveType, ResponseReader>();
+  static {
+ JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BOOLEAN, ResponseReader.BOOLEAN); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BYTE, ResponseReader.BYTE); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.CHAR, ResponseReader.CHAR); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.DOUBLE, ResponseReader.DOUBLE); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.FLOAT, ResponseReader.FLOAT); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.INT, ResponseReader.INT); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.LONG, ResponseReader.LONG); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.SHORT, ResponseReader.SHORT); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.VOID, ResponseReader.VOID);
+  }

   /**
* Adds a root type for each type that appears in the RemoteService interface
@@ -196,7 +227,7 @@
     for (JType[] a : types) {
       typesList.addAll(Arrays.asList(a));
     }
-    JType[] serializableTypes = typesList.toArray(new JType[0]);
+ JType[] serializableTypes = typesList.toArray(new JType[typesList.size()]); Arrays.sort(serializableTypes, SerializableTypeOracleBuilder.JTYPE_COMPARATOR);
     return serializableTypes;
   }
@@ -205,24 +236,13 @@

   private boolean elideTypeNames;

-  private Map<String, Long> cachedTypeLastModifiedTimes = null;
-
   /**
    * The possibly obfuscated type signatures used to represent a type.
    */
   private Map<JType, String> typeStrings;

-  {
- JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BOOLEAN, ResponseReader.BOOLEAN); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BYTE, ResponseReader.BYTE); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.CHAR, ResponseReader.CHAR); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.DOUBLE, ResponseReader.DOUBLE); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.FLOAT, ResponseReader.FLOAT); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.INT, ResponseReader.INT); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.LONG, ResponseReader.LONG); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.SHORT, ResponseReader.SHORT); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.VOID, ResponseReader.VOID);
-  }
+  private Set<JType> customSerializersUsed;
+  private Set<JType> typesNotUsingCustomSerializers;

   public ProxyCreator(JClassType serviceIntf) {
     assert (serviceIntf.isInterface() != null);
@@ -234,7 +254,7 @@
    *
    * @throws UnableToCompleteException
    */
-  public String create(TreeLogger logger, GeneratorContextExt context)
+ public RebindResult create(TreeLogger logger, GeneratorContextExt context)
       throws UnableToCompleteException {
     TypeOracle typeOracle = context.getTypeOracle();

@@ -247,9 +267,8 @@
       throw new UnableToCompleteException();
     }

- SourceWriter srcWriter = getSourceWriter(logger, context, serviceAsync);
-    if (srcWriter == null) {
-      return getProxyQualifiedName();
+    if (checkAlreadyGenerated(typeOracle, serviceIntf)) {
+ return new RebindResult(RebindStatus.USE_EXISTING, getProxyQualifiedName());
     }

// Make sure that the async and synchronous versions of the RemoteService
@@ -265,15 +284,52 @@

     // Determine the set of serializable types
Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_STOB);
-
-    SerializableTypeOracleBuilder typesSentFromBrowserBuilder =
-        new SerializableTypeOracleBuilder(logger, propertyOracle, context);
-    typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter);
-    SerializableTypeOracleBuilder typesSentToBrowserBuilder =
-        new SerializableTypeOracleBuilder(logger, propertyOracle, context);
-    typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter);
-
- addRoots(logger, typeOracle, typesSentFromBrowserBuilder, typesSentToBrowserBuilder);
+    SerializableTypeOracle typesSentFromBrowser;
+    SerializableTypeOracle typesSentToBrowser;
+    String rpcLog;
+    try {
+      SerializableTypeOracleBuilder typesSentFromBrowserBuilder =
+ new SerializableTypeOracleBuilder(logger, propertyOracle, context);
+      typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter);
+      SerializableTypeOracleBuilder typesSentToBrowserBuilder =
+ new SerializableTypeOracleBuilder(logger, propertyOracle, context);
+      typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter);
+
+ addRoots(logger, typeOracle, typesSentFromBrowserBuilder, typesSentToBrowserBuilder);
+
+      // Decide what types to send in each direction.
+ // Log the decisions to a string that will be written later in this method
+      {
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(stringWriter);
+
+        typesSentFromBrowserBuilder.setLogOutputWriter(writer);
+        typesSentToBrowserBuilder.setLogOutputWriter(writer);
+
+        writer.write("====================================\n");
+        writer.write("Types potentially sent from browser:\n");
+        writer.write("====================================\n\n");
+        writer.flush();
+        typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger);
+
+        writer.write("===================================\n");
+        writer.write("Types potentially sent from server:\n");
+        writer.write("===================================\n\n");
+        writer.flush();
+        typesSentToBrowser = typesSentToBrowserBuilder.build(logger);
+
+        writer.close();
+        rpcLog = stringWriter.toString();
+      }
+    } finally {
+      event.end();
+    }
+
+    // Check generator result cacheability, to see if we can return now
+ if (checkGeneratorResultCacheability(logger, context, typesSentFromBrowser, typesSentToBrowser)) { + logger.log(TreeLogger.TRACE, "Reusing all cached artifacts for " + getProxyQualifiedName()); + return new RebindResult(RebindStatus.USE_ALL_CACHED, getProxyQualifiedName());
+    }

     try {
       ConfigurationProperty prop =
@@ -287,34 +343,12 @@
       throw new UnableToCompleteException();
     }

-    // Decide what types to send in each direction.
- // Log the decisions to a string that will be written later in this method
-    SerializableTypeOracle typesSentFromBrowser;
-    SerializableTypeOracle typesSentToBrowser;
-    String rpcLog;
-    {
-      StringWriter stringWriter = new StringWriter();
-      PrintWriter writer = new PrintWriter(stringWriter);
-
-      typesSentFromBrowserBuilder.setLogOutputWriter(writer);
-      typesSentToBrowserBuilder.setLogOutputWriter(writer);
-
-      writer.write("====================================\n");
-      writer.write("Types potentially sent from browser:\n");
-      writer.write("====================================\n\n");
-      writer.flush();
-      typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger);
-
-      writer.write("===================================\n");
-      writer.write("Types potentially sent from server:\n");
-      writer.write("===================================\n\n");
-      writer.flush();
-      typesSentToBrowser = typesSentToBrowserBuilder.build(logger);
-
-      writer.close();
-      rpcLog = stringWriter.toString();
-    }
-    event.end();
+ SourceWriter srcWriter = getSourceWriter(logger, context, serviceAsync);
+    if (srcWriter == null) {
+      // don't expect this to occur, but could happen if an instance was
+      // recently generated but not yet committed
+ return new RebindResult(RebindStatus.USE_EXISTING, getProxyQualifiedName());
+    }

generateTypeHandlers(logger, context, typesSentFromBrowser, typesSentToBrowser);

@@ -344,12 +378,26 @@
           serializationPolicyStrongName, rpcLog));
     }

-    return getProxyQualifiedName();
-  }
-
-  public void updateResultCacheData(CachedClientDataMap clientData) {
-    if (cachedTypeLastModifiedTimes != null) {
- clientData.put(TypeSerializerCreator.CACHED_TYPE_INFO_KEY, cachedTypeLastModifiedTimes);
+    if (context.isGeneratorResultCachingEnabled()) {
+ // Remember the type info that we care about for cacheability testing.
+      CachedClientDataMap clientData = new CachedClientDataMap();
+      CachedRpcTypeInformation cti =
+ new CachedRpcTypeInformation(typesSentFromBrowser, typesSentToBrowser,
+              customSerializersUsed, typesNotUsingCustomSerializers);
+      clientData.put(CACHED_TYPE_INFO_KEY, cti);
+      CachedPropertyInformation cpi =
+ new CachedPropertyInformation(logger, context.getPropertyOracle(), selectionPropsToCheck,
+              configPropsToCheck);
+      clientData.put(CACHED_PROPERTY_INFO_KEY, cpi);
+
+      /*
+       * Return with RebindStatus.USE_PARTIAL_CACHED, since we are allowing
+ * generator result caching for field serializers, but other generated
+       * types cannot be cached effectively.
+       */
+ return new RebindResult(RebindStatus.USE_PARTIAL_CACHED, getProxyQualifiedName(), clientData);
+    } else {
+ return new RebindResult(RebindStatus.USE_ALL_NEW_WITH_NO_CACHING, getProxyQualifiedName());
     }
   }

@@ -655,7 +703,8 @@
     typeStrings = new HashMap<JType, String>(tsc.getTypeStrings());
     typeStrings.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID);

-    cachedTypeLastModifiedTimes = tsc.getTypeLastModifiedTimeMap();
+    customSerializersUsed = tsc.getCustomSerializersUsed();
+ typesNotUsingCustomSerializers = tsc.getTypesNotUsingCustomSerializers();
   }

   protected String getProxySimpleName() {
@@ -776,6 +825,44 @@
       throw new UnableToCompleteException();
     }
   }
+
+ private boolean checkAlreadyGenerated(TypeOracle typeOracle, JClassType serviceAsync) {
+    JPackage serviceIntfPkg = serviceAsync.getPackage();
+ String packageName = serviceIntfPkg == null ? "" : serviceIntfPkg.getName();
+    return typeOracle.findType(packageName, getProxySimpleName()) != null;
+  }
+
+ private boolean checkGeneratorResultCacheability(TreeLogger logger, GeneratorContextExt ctx, + SerializableTypeOracle typesSentFromBrowser, SerializableTypeOracle typesSentToBrowser) {
+
+    CachedRebindResult lastResult = ctx.getCachedGeneratorResult();
+    if (lastResult == null || !ctx.isGeneratorResultCachingEnabled()) {
+      return false;
+    }
+
+    CachedPropertyInformation cpi =
+ (CachedPropertyInformation) lastResult.getClientData(CACHED_PROPERTY_INFO_KEY);
+    if (cpi == null) {
+      return false;
+    }
+
+    CachedRpcTypeInformation cti =
+ (CachedRpcTypeInformation) lastResult.getClientData(CACHED_TYPE_INFO_KEY);
+    if (cti == null) {
+      return false;
+    }
+
+ if (!cti.checkTypeInformation(logger, ctx.getTypeOracle(), typesSentFromBrowser,
+        typesSentToBrowser)) {
+      return false;
+    }
+
+ if (!cpi.checkPropertiesWithPropertyOracle(logger, ctx.getPropertyOracle())) {
+      return false;
+    }
+
+    return true;
+  }

private void emitPolicyFileArtifact(TreeLogger logger, GeneratorContextExt context,
       String partialPath) throws UnableToCompleteException {
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java Wed Jun 8 11:10:51 2011 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java Tue Jun 21 04:31:29 2011
@@ -404,7 +404,20 @@
       return null;
     }

- String customFieldSerializerName = type.getQualifiedSourceName() + "_CustomFieldSerializer"; + String customFieldSerializerName = getCustomFieldSerializerName(type.getQualifiedSourceName()); + return findCustomFieldSerializer(typeOracle, customFieldSerializerName);
+  }
+
+  /**
+   * Finds the custom field serializer for a given qualified source name.
+   *
+   * @param typeOracle
+   * @param customFieldSerializerName
+   * @return the custom field serializer for a type of <code>null</code> if
+   *         there is not one
+   */
+  public static JClassType findCustomFieldSerializer(TypeOracle typeOracle,
+      String customFieldSerializerName) {
JClassType customSerializer = typeOracle.findType(customFieldSerializerName);
     if (customSerializer == null) {
// If the type is in the java.lang or java.util packages then it will be
@@ -415,6 +428,16 @@

     return customSerializer;
   }
+
+  /**
+   * Returns the name for a custom field serializer, given a source name.
+   *
+   * @param sourceName
+   * @return the custom field serializer type name for a given source name.
+   */
+  public static String getCustomFieldSerializerName(String sourceName) {
+    return sourceName + "_CustomFieldSerializer";
+  }

   static JRealClassType getBaseType(JClassType type) {
     if (type.isParameterized() != null) {
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java Tue Jun 14 12:19:31 2011 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java Tue Jun 21 04:31:29 2011
@@ -21,9 +21,7 @@
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.javac.rebind.CachedClientDataMap;
 import com.google.gwt.dev.javac.rebind.RebindResult;
-import com.google.gwt.dev.javac.rebind.RebindStatus;

 /**
  * Generator for producing the asynchronous version of a
@@ -57,23 +55,7 @@
logger.branch(TreeLogger.DEBUG, "Generating client proxy for remote service interface '"
             + remoteService.getQualifiedSourceName() + "'", null);

-    String returnTypeName = proxyCreator.create(proxyLogger, ctx);
-
-    if (ctx.isGeneratorResultCachingEnabled()) {
- // Remember the type info that we care about for cacheability testing.
-      CachedClientDataMap clientData = new CachedClientDataMap();
-      proxyCreator.updateResultCacheData(clientData);
-
-      /*
-       * Return with RebindStatus.USE_PARTIAL_CACHED, since we are allowing
- * generator result caching for field serializers, but other generated
-       * types cannot be cached effectively.
-       */
- return new RebindResult(RebindStatus.USE_PARTIAL_CACHED, returnTypeName, clientData);
-    } else {
-      // If we can't be cacheable, don't return a cacheable result
- return new RebindResult(RebindStatus.USE_ALL_NEW_WITH_NO_CACHING, returnTypeName);
-    }
+    return proxyCreator.create(proxyLogger, ctx);
   }

   protected ProxyCreator createProxyCreator(JClassType remoteService) {
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/Shared.java Wed Jun 8 11:10:51 2011 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/Shared.java Tue Jun 21 04:31:29 2011
@@ -37,7 +37,7 @@
* Property used to control whether or not the RPC system will emit warnings
    * when a type has final fields.
    */
- private static final String RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS = + public static final String RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS =
       "gwt.suppressNonStaticFinalFieldWarnings";

   /**
@@ -45,7 +45,7 @@
* (potentially) enhanced with server-only fields, to be handled specially by
    * RPC.
    */
-  private static final String RPC_ENHANCED_CLASSES = "rpc.enhancedClasses";
+  public static final String RPC_ENHANCED_CLASSES = "rpc.enhancedClasses";

   /**
    * Capitalizes a name.
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java Tue Jun 14 12:19:31 2011 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java Tue Jun 21 04:31:29 2011
@@ -24,13 +24,9 @@
 import com.google.gwt.core.ext.GeneratorContextExt;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.JArrayType;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.JMethod;
 import com.google.gwt.core.ext.typeinfo.JParameterizedType;
-import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
-import com.google.gwt.core.ext.typeinfo.JRawType;
-import com.google.gwt.core.ext.typeinfo.JRealClassType;
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.javac.rebind.CachedRebindResult;
@@ -62,12 +58,6 @@
  */
 public class TypeSerializerCreator {

-  /**
- * A key for storing cached type information for use with generator result
-   * caching.
-   */
-  public static final String CACHED_TYPE_INFO_KEY = "cached-type-info";
-
   /**
    * Configuration property to use type indices instead of type signatures.
    */
@@ -127,10 +117,12 @@

   private final String typeSerializerSimpleName;

-  private final Map<String, Long> typeLastModifiedTimeMap;
-
private final Map<JType, String> typeStrings = new IdentityHashMap<JType, String>();

+  private final Set<JType> typesNotUsingCustomFieldSerializers;
+
+  private final Set<JType> customFieldSerializersUsed;
+
public TypeSerializerCreator(TreeLogger logger, SerializableTypeOracle serializationOracle, SerializableTypeOracle deserializationOracle, GeneratorContextExt context,
       String typeSerializerClassName, String typeSerializerSimpleName)
@@ -169,14 +161,20 @@
     }

     if (context.isGeneratorResultCachingEnabled()) {
-      typeLastModifiedTimeMap = new HashMap<String, Long>();
+      typesNotUsingCustomFieldSerializers = new HashSet<JType>();
+      customFieldSerializersUsed = new HashSet<JType>();
     } else {
-      typeLastModifiedTimeMap = null;
+      typesNotUsingCustomFieldSerializers = null;
+      customFieldSerializersUsed = null;
     }
   }

-  public Map<String, Long> getTypeLastModifiedTimeMap() {
-    return typeLastModifiedTimeMap;
+  public Set<JType> getCustomSerializersUsed() {
+    return customFieldSerializersUsed;
+  }
+
+  public Set<JType> getTypesNotUsingCustomSerializers() {
+    return typesNotUsingCustomFieldSerializers;
   }

   public Map<JType, String> getTypeStrings() {
@@ -246,12 +244,21 @@
        */
       assert (type.isClass() != null || type.isArray() != null);

+      // get custom field serializer, if available
+      JClassType customFieldSerializer =
+ SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type);
+
       if (ctx.isGeneratorResultCachingEnabled()) {
-        // get the last modified time for our type, and remember it
- typeLastModifiedTimeMap.put(type.getQualifiedSourceName(), getLastModifiedTime(type));
+        // update cacheable info for next iteration
+        if (customFieldSerializer != null) {
+          customFieldSerializersUsed.add(customFieldSerializer);
+        } else {
+          typesNotUsingCustomFieldSerializers.add(type);
+        }

// check the cache for a valid field serializer for the current type - if (findCacheableFieldSerializerAndMarkForReuseIfAvailable(logger, ctx, type)) { + if (findCacheableFieldSerializerAndMarkForReuseIfAvailable(logger, ctx, type,
+            customFieldSerializer)) {
// we can skip re-generation of the field serializer for the current
           // type
           return;
@@ -259,8 +266,6 @@
       }

       // generate a new field serializer
-      JClassType customFieldSerializer =
- SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type);
       FieldSerializerCreator creator =
new FieldSerializerCreator(context, serializationOracle, deserializationOracle,
               (JClassType) type, customFieldSerializer);
@@ -290,7 +295,7 @@
    * return false.
    */
private boolean findCacheableFieldSerializerAndMarkForReuseIfAvailable(TreeLogger logger,
-      GeneratorContextExt ctx, JType type) {
+      GeneratorContextExt ctx, JType type, JType customFieldSerializer) {

     CachedRebindResult lastResult = ctx.getCachedGeneratorResult();
     if (lastResult == null || !ctx.isGeneratorResultCachingEnabled()) {
@@ -302,6 +307,12 @@
     if (type instanceof JClassType) {
       // check that it is available for reuse
       if (!lastResult.isTypeCached(fieldSerializerName)) {
+        if (logger.isLoggable(TreeLogger.TRACE)) {
+          if (ctx.getTypeOracle().findType(fieldSerializerName) == null) {
+ logger.log(TreeLogger.TRACE, "No cached field serializer available for "
+                + type.getQualifiedSourceName());
+          }
+        }
         return false;
       }
     } else {
@@ -309,14 +320,15 @@
     }

     @SuppressWarnings("unchecked")
-    Map<String, Long> cachedLastModifiedTimes =
-        (Map<String, Long>) lastResult.getClientData(CACHED_TYPE_INFO_KEY);
-    String sourceName = type.getQualifiedSourceName();
-
-    assert cachedLastModifiedTimes != null;
-    assert typeLastModifiedTimeMap.get(sourceName) != null;
+    CachedRpcTypeInformation cachedTypeInfo =
+ (CachedRpcTypeInformation) lastResult.getClientData(ProxyCreator.CACHED_TYPE_INFO_KEY);
+
+    assert cachedTypeInfo != null;
     boolean foundMatch = false;
- if (typeLastModifiedTimeMap.get(sourceName).equals(cachedLastModifiedTimes.get(sourceName))) {
+    if (cachedTypeInfo.checkLastModifiedTime(type)
+        && ((customFieldSerializer != null && cachedTypeInfo
+ .checkLastModifiedTime(customFieldSerializer)) || (customFieldSerializer == null && cachedTypeInfo
+            .checkTypeNotUsingCustomSerializer(type)))) {
       // use cached version, if available
       foundMatch = ctx.reuseTypeFromCacheIfAvailable(fieldSerializerName);
     }
@@ -333,29 +345,6 @@

     return foundMatch;
   }
-
-  private long getLastModifiedTime(JType type) {
-    JType typeToCheck;
-    if (type instanceof JArrayType) {
-      typeToCheck = ((JArrayType) type).getLeafType();
-    } else if (type instanceof JRawType) {
-      typeToCheck = ((JRawType) type).getGenericType();
-    } else {
-      assert type instanceof JRealClassType;
-      typeToCheck = type;
-    }
-
-    long lastModifiedTime;
-    if (typeToCheck instanceof JRealClassType) {
- lastModifiedTime = ((JRealClassType) typeToCheck).getLastModifiedTime();
-    } else {
-      // we have a type that is an array with a primitive leafType
-      assert typeToCheck instanceof JPrimitiveType;
-      lastModifiedTime = Long.MAX_VALUE;
-    }
-
-    return lastModifiedTime;
-  }

   private String[] getPackageAndClassName(String fullClassName) {
     String className = fullClassName;

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

Reply via email to