All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.rpc.server.CommandSerializationUtil Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2009 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.rpc.server;

import com.google.gwt.rpc.client.ast.BooleanValueCommand;
import com.google.gwt.rpc.client.ast.ByteValueCommand;
import com.google.gwt.rpc.client.ast.CharValueCommand;
import com.google.gwt.rpc.client.ast.DoubleValueCommand;
import com.google.gwt.rpc.client.ast.FloatValueCommand;
import com.google.gwt.rpc.client.ast.IntValueCommand;
import com.google.gwt.rpc.client.ast.LongValueCommand;
import com.google.gwt.rpc.client.ast.ShortValueCommand;
import com.google.gwt.rpc.client.ast.StringValueCommand;
import com.google.gwt.rpc.client.ast.ValueCommand;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.IdentityHashMap;
import java.util.Map;

import sun.misc.Unsafe;

/**
 * Contains common utility code.
 */
public class CommandSerializationUtil {

  /**
   * Defines methods for getting and setting fields.
   */
  public interface Accessor {
    boolean canMakeValueCommand();

    /**
     * Indicates if set can be called with a value of the given type.
     */
    boolean canSet(Class clazz);

    Object get(Object instance, Field f);

    Class getTargetType();

    ValueCommand makeValueCommand(Object value);

    Object readNext(SerializationStreamReader reader)
        throws SerializationException;

    void set(Object instance, Field f, Object value);

    void set(Object array, int index, Object value);
  }

  /**
   * Defines type-specific methods of getting and setting fields.
   */
  private static enum TypeAccessor implements Accessor {
    BOOL {
      @Override
      public boolean canSet(Class clazz) {
        return Boolean.class.isAssignableFrom(clazz)
            || Number.class.isAssignableFrom(clazz)
            || String.class.isAssignableFrom(clazz);
      }

      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getBoolean(instance, offset);
      }

      @Override
      public Object getDefaultValue() {
        return false;
      }

      @Override
      public Class getTargetType() {
        return boolean.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new BooleanValueCommand((Boolean) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readBoolean();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putBoolean(instance, offset, toBoolean(value));
      }

      private boolean toBoolean(Object value) {
        if (value instanceof Number) {
          return ((Number) value).intValue() != 0;
        } else if (value instanceof String) {
          return Boolean.valueOf((String) value);
        } else {
          // returns false if the value is null.
          return Boolean.TRUE.equals(value);
        }
      }

    },
    BYTE {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getByte(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return byte.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new ByteValueCommand((Byte) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readByte();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putByte(instance, offset, ((Number) value).byteValue());
      }
    },
    CHAR {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getChar(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return char.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new CharValueCommand((Character) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readChar();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        char c = (value instanceof Number) ? (char) ((Number) value).intValue()
            : (Character) value;
        theUnsafe.putChar(instance, offset, c);
      }
    },
    DOUBLE {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getDouble(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return double.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new DoubleValueCommand((Double) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readDouble();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putDouble(instance, offset, ((Number) value).doubleValue());
      }
    },
    FLOAT {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getFloat(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return float.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new FloatValueCommand((Float) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readFloat();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putFloat(instance, offset, ((Number) value).floatValue());
      }
    },
    INT {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getInt(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return int.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new IntValueCommand(((Number) value).intValue());
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readInt();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putInt(instance, offset, ((Number) value).intValue());
      }
    },
    LONG {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getLong(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return long.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new LongValueCommand((Long) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readLong();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putLong(instance, offset, ((Number) value).longValue());
      }
    },
    OBJECT {
      @Override
      public boolean canMakeValueCommand() {
        return false;
      }

      @Override
      public boolean canSet(Class clazz) {
        return Object.class.isAssignableFrom(clazz);
      }

      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getObject(instance, offset);
      }

      @Override
      public Object getDefaultValue() {
        return null;
      }

      @Override
      public Class getTargetType() {
        return Object.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        throw new RuntimeException("Cannot call makeValueCommand for Objects");
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readObject();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putObject(instance, offset, value);
      }
    },
    SHORT {
      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getShort(instance, offset);
      }

      @Override
      public Class getTargetType() {
        return short.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new ShortValueCommand((Short) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readShort();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putShort(instance, offset, ((Number) value).shortValue());
      }
    },
    STRING {
      @Override
      public boolean canSet(Class clazz) {
        return true;
      }

      @Override
      public Object get(Object instance, long offset) {
        return theUnsafe.getObject(instance, offset);
      }

      @Override
      public Object getDefaultValue() {
        return null;
      }

      @Override
      public Class getTargetType() {
        return String.class;
      }

      @Override
      public ValueCommand makeValueCommand(Object value) {
        return new StringValueCommand((String) value);
      }

      @Override
      public Object readNext(SerializationStreamReader reader)
          throws SerializationException {
        return reader.readObject();
      }

      @Override
      public void set(Object instance, long offset, Object value) {
        theUnsafe.putObject(instance, offset, value == null ? null
            : value.toString());
      }
    };

    private final Class arrayType = Array.newInstance(getTargetType(), 0).getClass();
    private final long arrayBase = theUnsafe.arrayBaseOffset(arrayType);
    private final long arrayIndexScale = theUnsafe.arrayIndexScale(arrayType);

    public boolean canMakeValueCommand() {
      return true;
    }

    public boolean canSet(Class clazz) {
      return Number.class.isAssignableFrom(clazz);
    }

    public Object get(Object instance, Field f) {
      long offset = objectFieldOffset(f);
      return get(instance, offset);
    }

    public abstract Object get(Object instance, long offset);

    public Object getDefaultValue() {
      return 0;
    }

    public abstract Class getTargetType();

    public abstract ValueCommand makeValueCommand(Object value);

    public abstract Object readNext(SerializationStreamReader reader)
        throws SerializationException;

    public void set(Object instance, Field f, Object value) {
      long offset = objectFieldOffset(f);
      set(instance, offset, value == null ? getDefaultValue() : value);
    }

    public void set(Object array, int index, Object value) {
      set(array, arrayBase + arrayIndexScale * index, value);
    }

    public abstract void set(Object instance, long offset, Object value);
  }

  private static final Map, Accessor> ACCESSORS = new IdentityHashMap, Accessor>();
  private static final Unsafe theUnsafe;

  static {
    Exception ex = null;
    Unsafe localUnsafe = null;
    try {
      Field f = Unsafe.class.getDeclaredField("theUnsafe");
      f.setAccessible(true);
      localUnsafe = (Unsafe) f.get(null);
    } catch (SecurityException e) {
      ex = e;
    } catch (NoSuchFieldException e) {
      ex = e;
    } catch (IllegalArgumentException e) {
      ex = e;
    } catch (IllegalAccessException e) {
      ex = e;
    }
    if (ex != null) {
      throw new RuntimeException("Unable to get Unsafe instance", ex);
    } else {
      theUnsafe = localUnsafe;
    }

    for (TypeAccessor setter : TypeAccessor.values()) {
      ACCESSORS.put(setter.getTargetType(), setter);
    }
  }

  public static Accessor getAccessor(Class clazz) {
    Accessor toReturn = ACCESSORS.get(clazz);
    if (toReturn == null) {
      toReturn = TypeAccessor.OBJECT;
    }
    return toReturn;
  }

  /**
   * TODO: In the future it may be preferable to use a custom ClassLoader to
   * inject a constructor that will initialize all of the final fields that we
   * care about.
   */
  static  T allocateInstance(Class clazz) throws InstantiationException {
    Object obj = theUnsafe.allocateInstance(clazz);
    return clazz.cast(obj);
  }

  private static long objectFieldOffset(Field f) {
    return theUnsafe.objectFieldOffset(f);
  }

  private CommandSerializationUtil() {
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy