com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.java

Source

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