| /* |
| * 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); |
| } |
| } |
| } |
| } |