blob: 6ec516c3846d3f922d81f2d708ab39952a33dca3 [file] [log] [blame]
/*
* 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);
assert (customSerializersUsed != null);
for (JType type : customSerializersUsed) {
addCustomSerializerType(type);
}
assert (typesNotUsingCustomSerializers != null);
for (JType type : typesNotUsingCustomSerializers) {
addTypeNotUsingCustomSerializer(type);
}
}
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());
}
private void addCustomSerializerType(JType type) {
String sourceName = type.getQualifiedSourceName();
lastModifiedTimes.put(sourceName, getLastModifiedTime(type));
customSerializerTypes.add(sourceName);
}
private void addTypeNotUsingCustomSerializer(JType type) {
String sourceName = type.getQualifiedSourceName();
typesNotUsingCustomSerializer.add(sourceName);
}
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;
}
/*
* Finds a last modified time for a type, for testing cache reusability.
*/
private long getLastModifiedTime(JType type) {
if (type instanceof JArrayType) {
return getLastModifiedTime(type.getLeafType());
} else if (type instanceof JRawType) {
return getLastModifiedTime(((JRawType) type).getGenericType());
}
if (type instanceof JRealClassType) {
return ((JRealClassType) type).getLastModifiedTime();
} else {
// we have a type that is an array with a primitive leafType
assert type instanceof JPrimitiveType;
// this type is never out of date
return Long.MAX_VALUE;
}
}
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) {
assert (sto != null);
for (JType type : sto.getSerializableTypes()) {
String sourceName = type.getQualifiedSourceName();
lastModifiedTimes.put(sourceName, getLastModifiedTime(type));
serializable.add(sourceName);
if (sto.maybeInstantiated(type)) {
instantiable.add(sourceName);
}
}
}
}