| /* |
| * Copyright 2008 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.client.rpc.impl; |
| |
| import com.google.gwt.user.client.rpc.SerializationException; |
| import com.google.gwt.user.client.rpc.SerializationStreamWriter; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.IdentityHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Base class for the client and server serialization streams. This class |
| * handles the basic serialization and deserialization formatting for primitive |
| * types since these are common between the client and the server. It also |
| * handles Object- and String-tracking for building graph references. |
| */ |
| public abstract class AbstractSerializationStreamWriter extends |
| AbstractSerializationStream implements SerializationStreamWriter { |
| |
| private static final double TWO_PWR_16_DBL = 0x10000; |
| private static final double TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; |
| |
| /** |
| * Return a pair of doubles { low, high } that add up to the given number, |
| * such that "low" is always between 0 and 2^32-1 inclusive and "high" is |
| * always between -2^63 and 2^63-2^32 inclusive and is a multiple of 2^32. |
| */ |
| public static double[] getAsDoubleArray(long value) { |
| int lowBits = (int) (value & 0xffffffff); |
| int highBits = (int) (value >> 32); |
| return makeLongComponents(lowBits, highBits); |
| } |
| |
| // Equivalent to getAsDoubleArray((long) highBits << 32 | lowBits); |
| protected static double[] makeLongComponents(int lowBits, int highBits) { |
| double high = highBits * TWO_PWR_32_DBL; |
| double low = lowBits; |
| if (lowBits < 0) { |
| low += TWO_PWR_32_DBL; |
| } |
| return new double[] {low, high}; |
| } |
| |
| private int objectCount; |
| |
| private Map<Object, Integer> objectMap = new IdentityHashMap<Object, Integer>(); |
| |
| private Map<String, Integer> stringMap = new HashMap<String, Integer>(); |
| |
| private List<String> stringTable = new ArrayList<String>(); |
| |
| public void prepareToWrite() { |
| objectCount = 0; |
| objectMap.clear(); |
| stringMap.clear(); |
| stringTable.clear(); |
| } |
| |
| @Override |
| public abstract String toString(); |
| |
| public void writeBoolean(boolean fieldValue) { |
| append(fieldValue ? "1" : "0"); |
| } |
| |
| public void writeByte(byte fieldValue) { |
| append(String.valueOf(fieldValue)); |
| } |
| |
| public void writeChar(char ch) { |
| // just use an int, it's more foolproof |
| append(String.valueOf((int) ch)); |
| } |
| |
| public void writeDouble(double fieldValue) { |
| append(String.valueOf(fieldValue)); |
| } |
| |
| public void writeFloat(float fieldValue) { |
| writeDouble(fieldValue); |
| } |
| |
| public void writeInt(int fieldValue) { |
| append(String.valueOf(fieldValue)); |
| } |
| |
| public abstract void writeLong(long value); |
| |
| public void writeObject(Object instance) throws SerializationException { |
| if (instance == null) { |
| // write a null string |
| writeString(null); |
| return; |
| } |
| |
| int objIndex = getIndexForObject(instance); |
| if (objIndex >= 0) { |
| // We've already encoded this object, make a backref |
| // Transform 0-based to negative 1-based |
| writeInt(-(objIndex + 1)); |
| return; |
| } |
| |
| saveIndexForObject(instance); |
| |
| // Serialize the type signature |
| String typeSignature = getObjectTypeSignature(instance); |
| writeString(typeSignature); |
| // Now serialize the rest of the object |
| serialize(instance, typeSignature); |
| } |
| |
| public void writeShort(short value) { |
| append(String.valueOf(value)); |
| } |
| |
| public void writeString(String value) { |
| writeInt(addString(value)); |
| } |
| |
| /** |
| * Add a string to the string table and return its index. |
| * |
| * @param string the string to add |
| * @return the index to the string |
| */ |
| protected int addString(String string) { |
| if (string == null) { |
| return 0; |
| } |
| Integer o = stringMap.get(string); |
| if (o != null) { |
| return o; |
| } |
| stringTable.add(string); |
| // index is 1-based |
| int index = stringTable.size(); |
| stringMap.put(string, index); |
| return index; |
| } |
| |
| /** |
| * Append a token to the underlying output buffer. |
| * |
| * @param token the token to append |
| */ |
| protected abstract void append(String token); |
| |
| /** |
| * Get the index for an object that may have previously been saved via |
| * {@link #saveIndexForObject(Object)}. |
| * |
| * @param instance the object to save |
| * @return the index associated with this object, or -1 if this object hasn't |
| * been seen before |
| */ |
| protected int getIndexForObject(Object instance) { |
| return objectMap.containsKey(instance) ? objectMap.get(instance) : -1; |
| } |
| |
| /** |
| * Compute and return the type signature for an object. |
| * |
| * @param instance the instance to inspect |
| * @return the type signature of the instance |
| */ |
| protected abstract String getObjectTypeSignature(Object instance) |
| throws SerializationException; |
| |
| /** |
| * Gets the string table. |
| */ |
| protected List<String> getStringTable() { |
| return stringTable; |
| } |
| |
| /** |
| * Remember this object as having been seen before. |
| * |
| * @param instance the object to remember |
| */ |
| protected void saveIndexForObject(Object instance) { |
| objectMap.put(instance, objectCount++); |
| } |
| |
| /** |
| * Serialize an object into the stream. |
| * |
| * @param instance the object to serialize |
| * @param typeSignature the type signature of the object |
| * @throws SerializationException |
| */ |
| protected abstract void serialize(Object instance, String typeSignature) |
| throws SerializationException; |
| } |