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

com.gemstone.gemfire.internal.InternalDataSerializer Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * 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. See accompanying
 * LICENSE file.
 */

/*
 * Following functions has been taken from google protobuf:
 *  writeSignedVL(long data, DataOutput out)
 *  writeUnsignedVL(long data, DataOutput out)
 *  writeUnsignedVL(long data, ByteBuffer buf)
 *  readUnsignedVL(DataInput in)
 *  readSignedVL(DataInput in)
 *  decodeZigZag64(long n)
 *  encodeZigZag64(long n)
 * which are under the below license.
 *
 * Copyright 2014, Google Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
 *     * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Code generated by the Protocol Buffer compiler is owned by the owner
 * of the input file used when generating it.  This code is not
 * standalone and requires a support library to be linked with it.  This
 * support library is itself covered by the above license.
 */
package com.gemstone.gemfire.internal;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.NotSerializableException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UTFDataFormatException;
import java.lang.ref.WeakReference;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.gemstone.gemfire.CancelException;
import com.gemstone.gemfire.CanonicalInstantiator;
import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.GemFireIOException;
import com.gemstone.gemfire.GemFireRethrowable;
import com.gemstone.gemfire.Instantiator;
import com.gemstone.gemfire.InternalGemFireError;
import com.gemstone.gemfire.InternalGemFireException;
import com.gemstone.gemfire.SerializationException;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.ToDataException;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheClosedException;
import com.gemstone.gemfire.cache.execute.Function;
import com.gemstone.gemfire.distributed.internal.DMStats;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.LonerDistributionManager;
import com.gemstone.gemfire.distributed.internal.PooledDistributionMessage;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.i18n.StringIdImpl;
import com.gemstone.gemfire.internal.DSFIDFactory.GfxdDSFID;
import com.gemstone.gemfire.internal.cache.EnumListenerEvent;
import com.gemstone.gemfire.internal.cache.EventID;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.PoolManagerImpl;
import com.gemstone.gemfire.internal.cache.tier.sockets.CacheClientNotifier;
import com.gemstone.gemfire.internal.cache.tier.sockets.CacheServerHelper;
import com.gemstone.gemfire.internal.cache.tier.sockets.ClientDataSerializerMessage;
import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
import com.gemstone.gemfire.internal.cache.tier.sockets.Part;
import com.gemstone.gemfire.internal.concurrent.CFactory;
import com.gemstone.gemfire.internal.concurrent.CM;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.shared.ClientSharedUtils;
import com.gemstone.gemfire.internal.shared.Version;
import com.gemstone.gemfire.internal.util.concurrent.CopyOnWriteHashMap;
import com.gemstone.gemfire.pdx.NonPortableClassException;
import com.gemstone.gemfire.pdx.PdxInstance;
import com.gemstone.gemfire.pdx.PdxSerializable;
import com.gemstone.gemfire.pdx.PdxSerializer;
import com.gemstone.gemfire.pdx.internal.AutoSerializableManager;
import com.gemstone.gemfire.pdx.internal.AutoSerializableManager.AutoClassInfo;
import com.gemstone.gemfire.pdx.internal.EnumInfo;
import com.gemstone.gemfire.pdx.internal.PdxInputStream;
import com.gemstone.gemfire.pdx.internal.PdxInstanceEnum;
import com.gemstone.gemfire.pdx.internal.PdxInstanceImpl;
import com.gemstone.gemfire.pdx.internal.PdxOutputStream;
import com.gemstone.gemfire.pdx.internal.PdxReaderImpl;
import com.gemstone.gemfire.pdx.internal.PdxType;
import com.gemstone.gemfire.pdx.internal.PdxWriterImpl;
import com.gemstone.gemfire.pdx.internal.TypeRegistry;
import com.gemstone.gnu.trove.TObjectObjectProcedure;
import com.gemstone.org.jgroups.util.StreamableFixedID;
import com.gemstone.org.jgroups.util.StringId;
import com.gemstone.org.jgroups.util.VersionedStreamable;

/**
 * Contains static methods for data serializing instances of internal
 * GemFire classes.  It also contains the implementation of the
 * distribution messaging (and shared memory management) needed to
 * support data serialization.
 *
 * @author David Whitlock
 * @since 3.5
 */
public abstract class InternalDataSerializer extends DataSerializer implements DSCODE {

  /** Logger for writing DEBUG output */
  public static LogWriterI18n logger =
    new LocalLogWriter(LogWriterImpl.ALL_LEVEL, System.out);

  public static final Class[] ZERO_CLASS_ARGS = new Class[0];
  public static final Object[] ZERO_ARGS = new Object[0];

  private static final Set loggedClasses = new HashSet();
  /**
   * Maps Class names to their DataSerializer.  This is used to
   * find a DataSerializer during serialization.
   */
  private static final ConcurrentHashMap classesToSerializers = new ConcurrentHashMap();
  
  // used by sqlFire
  public static ConcurrentHashMap getClassesToSerializers() {
    return classesToSerializers;
  }

  private static final String serializationVersionTxt = System.getProperty("gemfire.serializationVersion");
  /**
   * Any time new serialization format is added then a new enum needs to be added here.
   * @author darrel
   * @since 6.6.2
   */
  private static enum SERIALIZATION_VERSION {
    vINVALID,
    v660, // includes 6.6.0.x and 6.6.1.x. Note that no serialization changes were made in 6.6 until 6.6.2
    v662 // 6.6.2.x or later
    // NOTE if you add a new constant make sure and update "latestVersion".
  }
  /**
   * Change this constant to be the last one in SERIALIZATION_VERSION
   */
  private static final SERIALIZATION_VERSION latestVersion = SERIALIZATION_VERSION.v662;
  
  private static SERIALIZATION_VERSION calculateSerializationVersion() {
    if (serializationVersionTxt == null || serializationVersionTxt.equals("")) {
      return latestVersion;
    } else if (serializationVersionTxt.startsWith("6.6.0") || serializationVersionTxt.startsWith("6.6.1")) {
      return SERIALIZATION_VERSION.v660;
    } else if (serializationVersionTxt.startsWith("6.6.2")) {
      return SERIALIZATION_VERSION.v662;
    } else {
      return SERIALIZATION_VERSION.vINVALID;
    }
  }
  private static final SERIALIZATION_VERSION serializationVersion = calculateSerializationVersion();

  public static boolean is662SerializationEnabled() {
    return serializationVersion.ordinal() >= SERIALIZATION_VERSION.v662.ordinal()
      || GemFireCacheImpl.gfxdSystem();
  }
  
  public static void checkSerializationVersion() {
    if (serializationVersion == SERIALIZATION_VERSION.vINVALID) {
      throw new IllegalArgumentException("The system property \"gemfire.serializationVersion\" was set to \"" + serializationVersionTxt + "\" which is not a valid serialization version. Valid versions must start with \"6.6.0\", \"6.6.1\", or \"6.6.2\"");
    }
  }

  static {
    initializeWellKnownSerializers();
  }
  private static void initializeWellKnownSerializers() { 
    // ArrayBlockingQueue does not have zero-arg constructor
    // LinkedBlockingQueue does have zero-arg constructor but no way to get capacity
  
    classesToSerializers.put("java.lang.String",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 try {
                                   writeString((String)o, out);
                                 }
                                 catch (UTFDataFormatException ex) {
                                   // See bug 30428
                                   String s = "While writing a String of length " +
                                     ((String)o).length();
                                   UTFDataFormatException ex2 = new UTFDataFormatException(s);
                                   ex2.initCause(ex);
                                   throw ex2;
                                 }
                                 return true;
                               }});
    classesToSerializers.put("java.net.InetAddress",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 InetAddress address = (InetAddress) o;
                                 out.writeByte(INET_ADDRESS);
                                 writeInetAddress(address, out);
                                 return true;
                               }});
    classesToSerializers.put("java.net.Inet4Address",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 InetAddress address = (InetAddress) o;
                                 out.writeByte(INET_ADDRESS);
                                 writeInetAddress(address, out);
                                 return true;
                               }});
    classesToSerializers.put("java.net.Inet6Address",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 InetAddress address = (InetAddress) o;
                                 out.writeByte(INET_ADDRESS);
                                 writeInetAddress(address, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Class",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Class c = (Class) o;
                                 if (c.isPrimitive()) {
                                   writePrimitiveClass(c, out);
                                 }
                                 else {
                                   out.writeByte(CLASS);
                                   writeClass(c, out);
                                 }
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Boolean",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Boolean value = (Boolean) o;
                                 out.writeByte(BOOLEAN);
                                 writeBoolean(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Character",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Character value = (Character) o;
                                 out.writeByte(CHARACTER);
                                 writeCharacter(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Byte",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Byte value = (Byte) o;
                                 out.writeByte(BYTE);
                                 writeByte(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Short",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Short value = (Short) o;
                                 out.writeByte(SHORT);
                                 writeShort(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Integer",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Integer value = (Integer) o;
                                 out.writeByte(INTEGER);
                                 writeInteger(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Long",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Long value = (Long) o;
                                 out.writeByte(LONG);
                                 writeLong(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Float",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Float value = (Float) o;
                                 out.writeByte(FLOAT);
                                 writeFloat(value, out);
                                 return true;
                               }});
    classesToSerializers.put("java.lang.Double",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Double value = (Double) o;
                                 out.writeByte(DOUBLE);
                                 writeDouble(value, out);
                                 return true;
                               }});
    classesToSerializers.put("[Z", // boolean[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(BOOLEAN_ARRAY);
                                 writeBooleanArray((boolean[]) o, out);
                                 return true;
                               }});
    classesToSerializers.put("[B", // byte[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 byte[] array = (byte[]) o;
                                 out.writeByte(BYTE_ARRAY);
                                 writeByteArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("[C", // char[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(CHAR_ARRAY);
                                 writeCharArray((char[]) o, out);
                                 return true;
                               }});
    classesToSerializers.put("[D", // double[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 double[] array = (double[]) o;
                                 out.writeByte(DOUBLE_ARRAY);
                                 writeDoubleArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("[F", // float[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 float[] array = (float[]) o;
                                 out.writeByte(FLOAT_ARRAY);
                                 writeFloatArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("[I", // int[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 int[] array = (int[]) o;
                                 out.writeByte(INT_ARRAY);
                                 writeIntArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("[J", // long[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 long[] array = (long[]) o;
                                 out.writeByte(LONG_ARRAY);
                                 writeLongArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("[S", // short[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 short[] array = (short[]) o;
                                 out.writeByte(SHORT_ARRAY);
                                 writeShortArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("[Ljava.lang.String;", // String[]
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 String[] array = (String[]) o;
                                 out.writeByte(STRING_ARRAY);
                                 writeStringArray(array, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.concurrent.TimeUnit",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 TimeUnit unit = (TimeUnit) o;
                                 out.writeByte(TIME_UNIT);
                                 writeTimeUnit(unit, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.Date",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Date date = (Date) o;
                                 out.writeByte(DATE);
                                 writeDate(date, out);
                                 return true;
                               }});
    classesToSerializers.put("java.io.File",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 File file = (File) o;
                                 out.writeByte(FILE);
                                 writeFile(file, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.ArrayList",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 ArrayList list = (ArrayList) o;
                                 out.writeByte(ARRAY_LIST);
                                 writeArrayList(list, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.LinkedList",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 LinkedList list = (LinkedList) o;
                                 out.writeByte(LINKED_LIST);
                                 writeLinkedList(list, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.Vector",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(VECTOR);
                                 writeVector((Vector) o, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.Stack",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(STACK);
                                 writeStack((Stack) o, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.HashSet",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 HashSet list = (HashSet) o;
                                 out.writeByte(HASH_SET);
                                 writeHashSet(list, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.LinkedHashSet",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(LINKED_HASH_SET);
                                 writeLinkedHashSet((LinkedHashSet) o, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.HashMap",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 HashMap list = (HashMap) o;
                                 out.writeByte(HASH_MAP);
                                 writeHashMap(list, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.IdentityHashMap",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(IDENTITY_HASH_MAP);
                                 writeIdentityHashMap((IdentityHashMap) o, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.Hashtable",
                             new WellKnownPdxDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(HASH_TABLE);
                                 writeHashtable((Hashtable) o, out);
                                 return true;
                               }});
    // We can't add this here because it would cause writeObject to not be compatible with previous releases
//    classesToSerializers.put("java.util.concurrent.ConcurrentHashMap",
//                             new WellKnownDS() {
//                              @Override
//                              public final boolean toData(Object o, DataOutput out)
//                                throws IOException {
//                                out.writeByte(CONCURRENT_HASH_MAP);
//                                writeConcurrentHashMap((ConcurrentHashMap) o, out);
//                                return true;
//                              }});
    classesToSerializers.put("java.util.Properties",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 Properties props  = (Properties) o;
                                 out.writeByte(PROPERTIES);
                                 writeProperties(props, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.TreeMap",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(TREE_MAP);
                                 writeTreeMap((TreeMap) o, out);
                                 return true;
                               }});
    classesToSerializers.put("java.util.TreeSet",
                             new WellKnownDS() {
      @Override
                               public final boolean toData(Object o, DataOutput out)
                                 throws IOException {
                                 out.writeByte(TREE_SET);
                                 writeTreeSet((TreeSet) o, out);
                                 return true;
                               }});
    if (is662SerializationEnabled()) {
      classesToSerializers.put("java.math.BigInteger",
          new WellKnownDS() {
        @Override
        public final boolean toData(Object o, DataOutput out)
        throws IOException {
          out.writeByte(BIG_INTEGER);
          writeBigInteger((BigInteger) o, out);
          return true;
        }});
      classesToSerializers.put("java.math.BigDecimal",
          new WellKnownDS() {
        @Override
        public final boolean toData(Object o, DataOutput out)
        throws IOException {
          out.writeByte(BIG_DECIMAL);
          writeBigDecimal((BigDecimal) o, out);
          return true;
        }});
      classesToSerializers.put("java.util.UUID",
          new WellKnownDS() {
        @Override
        public final boolean toData(Object o, DataOutput out)
        throws IOException {
          out.writeByte(UUID);
          writeUUID((UUID) o, out);
          return true;
        }});
      classesToSerializers.put("java.sql.Timestamp",
          new WellKnownDS() {
        @Override
        public final boolean toData(Object o, DataOutput out)
        throws IOException {
          out.writeByte(TIMESTAMP);
          writeTimestamp((Timestamp) o, out);
          return true;
        }});
    }
    // @todo add: LinkedHashMap (hard to do because it might not be insertion ordered)
  }
  
  /** Maps the id of a serializer to its DataSerializer.
   */
  private static final CM/**/ idsToSerializers = CFactory.createCM();

  /**
   * Contains the classnames of the data serializers (and not the supported
   * classes) not yet loaded into the vm as keys and their corresponding holder
   * instances as values.
   */
  private static final ConcurrentHashMap dsClassesToHolders = new ConcurrentHashMap();

  /**
   * Contains the id of the data serializers not yet loaded into the vm as keys
   * and their corresponding holder instances as values.
   */
  private static final ConcurrentHashMap idsToHolders = new ConcurrentHashMap();

  /**
   * Contains the classnames of supported classes as keys and their
   * corresponding SerializerAttributesHolder instances as values. This applies
   * only to the data serializers which have not been loaded into the vm.
   */
  private static final ConcurrentHashMap supportedClassesToHolders = new ConcurrentHashMap();

  /** RegistrationListeners that receive callbacks when
   * DataSerializers and Instantiators are
   * registered.
   * Note: copy-on-write access used for this set
   */
  private static volatile Set listeners = new HashSet();
  private static final Object listenersSync = new Object();

  ////////////////////  Static Methods  ////////////////////

  /**
   * Convert the given unsigned byte to an int.
   * The returned value will be in the range [0..255] inclusive
   */
  private static final int ubyteToInt(byte ub) {
    return ub & 0xFF;
  }

  /**
   * Instantiates an instance of DataSerializer
   *
   * @throws IllegalArgumentException
   *         If the class can't be instantiated
   *
   * @see DataSerializer#register(Class)
   */
  private static DataSerializer newInstance(Class c) {
    if (!DataSerializer.class.isAssignableFrom(c)) {
      throw new IllegalArgumentException(LocalizedStrings.DataSerializer_0_DOES_NOT_EXTEND_DATASERIALIZER.toLocalizedString(c.getName()));
    }

    Constructor init;
    try {
      init = c.getDeclaredConstructor(ZERO_CLASS_ARGS);

    } catch (NoSuchMethodException ex) {
      StringId s = LocalizedStrings.DataSerializer_CLASS_0_DOES_NOT_HAVE_A_ZEROARGUMENT_CONSTRUCTOR;
      Object[] args = new Object[] {c.getName()};
      if (c.getDeclaringClass() != null) {
        s = LocalizedStrings.DataSerializer_CLASS_0_DOES_NOT_HAVE_A_ZEROARGUMENT_CONSTRUCTOR_IT_IS_AN_INNER_CLASS_OF_1_SHOULD_IT_BE_A_STATIC_INNER_CLASS;
        args = new Object[] {c.getName(), c.getDeclaringClass()};
      } 
      throw new IllegalArgumentException(s.toLocalizedString(args));
    }

    DataSerializer s;
    try {
      init.setAccessible(true);
      s = (DataSerializer) init.newInstance(ZERO_ARGS);

    } catch (IllegalAccessException ex) {
      throw new IllegalArgumentException(LocalizedStrings.DataSerializer_COULD_NOT_INSTANTIATE_AN_INSTANCE_OF_0.toLocalizedString(c.getName()));

    } catch (InstantiationException ex) {
      logger.severe(LocalizedStrings.ONE_ARG,
          "exception in deserialization", ex);
      RuntimeException ex2 = new IllegalArgumentException(LocalizedStrings
          .DataSerializer_COULD_NOT_INSTANTIATE_AN_INSTANCE_OF_0
          .toLocalizedString(c.getName()));
      ex2.initCause(ex);
      throw ex2;
    } catch (InvocationTargetException ex) {
      logger.severe(LocalizedStrings.ONE_ARG,
          "exception in deserialization", ex);
      RuntimeException ex2 = new IllegalArgumentException(LocalizedStrings
          .DataSerializer_WHILE_INSTANTIATING_AN_INSTANCE_OF_0
          .toLocalizedString(c.getName()));
      ex2.initCause(ex);
      throw ex2;
    }

    return s;
  }
  
  public static DataSerializer register(Class c, boolean distribute, EventID eventId,
      ClientProxyMembershipID context) {
    DataSerializer s = newInstance(c);
    // This method is only called when server connection and
    // CacheClientUpdaterThread
    s.setEventId(eventId);
    s.setContext(context);
    return _register(s, distribute);
  }

  /**
   * Registers a DataSerializer instance with the data
   * serialization framework.
   *
   * @param distribute
   *        Should the registered DataSerializer be
   *        distributed to other members of the distributed system?
   *
   * @see DataSerializer#register(Class)
   */
  public static DataSerializer register(Class c, boolean distribute) {
    final DataSerializer s = newInstance(c);
    return _register(s, distribute);
  }
  
  public static DataSerializer _register(DataSerializer s,
                                        boolean distribute) {
    final int id = s.getId();
    DataSerializer dsForMarkers = s;
    if (id == 0) {
      throw new IllegalArgumentException(LocalizedStrings.InternalDataSerializer_CANNOT_CREATE_A_DATASERIALIZER_WITH_ID_0.toLocalizedString());
    }
    final Class[] classes = s.getSupportedClasses();
    if (classes == null || classes.length == 0) {
      final StringId msg = LocalizedStrings.InternalDataSerializer_THE_DATASERIALIZER_0_HAS_NO_SUPPORTED_CLASSES_ITS_GETSUPPORTEDCLASSES_METHOD_MUST_RETURN_AT_LEAST_ONE_CLASS;
      throw new IllegalArgumentException(msg.toLocalizedString(s.getClass().getName()));
    }
    {
      for (int i = 0; i < classes.length; i++) {
        if (classes[i] == null) {
          final StringId msg = LocalizedStrings.InternalDataSerializer_THE_DATASERIALIZER_GETSUPPORTEDCLASSES_METHOD_FOR_0_RETURNED_AN_ARRAY_THAT_CONTAINED_A_NULL_ELEMENT;
          throw new IllegalArgumentException(msg.toLocalizedString(s.getClass().getName()));
        } else if (classes[i].isArray()) {
          final StringId msg = LocalizedStrings.InternalDataSerializer_THE_DATASERIALIZER_GETSUPPORTEDCLASSES_METHOD_FOR_0_RETURNED_AN_ARRAY_THAT_CONTAINED_AN_ARRAY_CLASS_WHICH_IS_NOT_ALLOWED_SINCE_ARRAYS_HAVE_BUILTIN_SUPPORT;
          throw new IllegalArgumentException(msg.toLocalizedString(s.getClass().getName()));
        }
      }
    }

    final Integer idx = Integer.valueOf(id);
    boolean retry;
    Marker oldMarker = null;
    final Marker m = new InitMarker();
    do {
      retry = false;
      Object oldSerializer = idsToSerializers.putIfAbsent(idx, m);
      if (oldSerializer != null) {
        if (oldSerializer instanceof Marker) {
          retry = !idsToSerializers.replace(idx, oldSerializer, m);
          if (!retry) {
            oldMarker = (Marker)oldSerializer;
          }
        } else if (oldSerializer.getClass().equals(s.getClass())) {
          // We've already got one of these registered
          if (distribute) {
            sendRegistrationMessage(s);
          }
          return (DataSerializer) oldSerializer;
        } else {
          DataSerializer other = (DataSerializer) oldSerializer;
          throw new IllegalStateException(LocalizedStrings.InternalDataSerializer_A_DATASERIALIZER_OF_CLASS_0_IS_ALREADY_REGISTERED_WITH_ID_1_SO_THE_DATASERIALIZER_OF_CLASS_2_COULD_NOT_BE_REGISTERED.toLocalizedString(new Object[] {other.getClass().getName(), Integer.valueOf(other.getId())}));
        }
      }
    } while (retry);

    try {
      for (int i = 0; i < classes.length; i++) {
        DataSerializer oldS = classesToSerializers.putIfAbsent(classes[i].getName(), s);
        if (oldS != null) {
          if (!s.equals(oldS)) {
            // cleanup the ones we have already added
            for (int j = 0; j < i; j++) {
              classesToSerializers.remove(classes[j].getName(), s);
            }
            dsForMarkers = null;
            String oldMsg;
            if (oldS.getId() == 0) {
              oldMsg = "DataSerializer has built-in support for class ";
            } else {
              oldMsg = "A DataSerializer of class "
                + oldS.getClass().getName()
                + " is already registered to support class ";
            }
            String msg = oldMsg
              + classes[i].getName()
              + " so the DataSerializer of class "
              + s.getClass().getName()
              + " could not be registered.";
            if (oldS.getId() == 0) {
              throw new IllegalArgumentException(msg);
            } else {
              throw new IllegalStateException(msg);
            }
          }
        }
      }
    } finally {
      if (dsForMarkers == null) {
        idsToSerializers.remove(idx, m);
      } else {
        idsToSerializers.replace(idx, m, dsForMarkers);
      }
      if (oldMarker != null) {
        oldMarker.setSerializer(dsForMarkers);
      }
      m.setSerializer(dsForMarkers);
    }

 // if dataserializer is getting registered for first time
    // its EventID will be null, so generate a new event id
    // the the distributed system is connected
    GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
    if (cache != null && s.getEventId() == null) {
      s.setEventId(new EventID(cache.getDistributedSystem()));
    }
    
    if (distribute) {
      // send a message to other peers telling them about a newly-registered
      // dataserializer, it also send event id of the originator along with the
      // dataserializer
      sendRegistrationMessage(s);
      // send it to cache servers if it is a client
      sendRegistrationMessageToServers(s);
    }
    // send it to all cache clients irelevent of distribute
    // bridge servers send it all the clients irelevent of
    // originator VM
    sendRegistrationMessageToClients(s);
    
    fireNewDataSerializer(s);

    return s;
  }

  /**
   * Marks a DataSerializer className for registration with the
   * data serialization framework. Does not necessarily load the classes into
   * this VM.
   * 
   * @param className Name of the DataSerializer class.
   * @param distribute
   *          If true, distribute this data serializer.
   * @param eventId
   *          Event id
   * @param proxyId
   *          proxy id
   * @see DataSerializer#register(Class)
   */
  public static void register(String className, boolean distribute,
      EventID eventId, ClientProxyMembershipID proxyId, int id) {
    register(className, distribute, new SerializerAttributesHolder(className,
        eventId, proxyId, id));
  }

  /**
   * Marks a DataSerializer className for registration with the
   * data serialization framework. Does not necessarily load the classes into
   * this VM.
   * 
   * @param className
   * @param distribute
   *          If true, distribute this data serializer.
   * @see DataSerializer#register(Class)
   */
  public static void register(String className, boolean distribute) {
    register(className, distribute, new SerializerAttributesHolder());
  }

  private static void register(String className, boolean distribute,
      SerializerAttributesHolder holder) {
    if (className == null || className.trim().equals("")) {
      throw new IllegalArgumentException("Class name cannot be null or empty.");
    }

    SerializerAttributesHolder oldValue = dsClassesToHolders.putIfAbsent(
        className, holder);
    if (oldValue != null) {
      if (oldValue.getId() != 0 && holder.getId() != 0
          && oldValue.getId() != holder.getId()) {
        throw new IllegalStateException(
            LocalizedStrings.InternalDataSerializer_A_DATASERIALIZER_OF_CLASS_0_IS_ALREADY_REGISTERED_WITH_ID_1_SO_THE_DATASERIALIZER_OF_CLASS_2_COULD_NOT_BE_REGISTERED
                .toLocalizedString(new Object[] {oldValue.getClass().getName(),
                    Integer.valueOf(oldValue.getId())}));
      }
    }

    idsToHolders.putIfAbsent(holder.getId(), holder);

    Object ds = idsToSerializers.get(holder.getId());
    if (ds instanceof Marker) {
      synchronized (ds) {
        ((Marker)ds).notifyAll();
      }
    }

    if (distribute) {
      sendRegistrationMessageToServers(holder);
    }
  }

  public static void updateSupportedClassesMap(
      HashMap> map) {
    for (Entry> e : map.entrySet()) {
      for (String supportedClassName : e.getValue()) {
        supportedClassesToHolders.putIfAbsent(supportedClassName,
            idsToHolders.get(e.getKey()));
      }
    }
  }

  public static void updateSupportedClassesMap(String dsClassName,
      String supportedClassName) {
    supportedClassesToHolders.putIfAbsent(supportedClassName,
        dsClassesToHolders.get(dsClassName));
  }

  public static class SerializerAttributesHolder {
    private String className = "";
    private EventID eventId = null;
    private ClientProxyMembershipID proxyId = null;
    private int id = 0;
    
    public SerializerAttributesHolder () {
    }

    public SerializerAttributesHolder(String name, EventID event,
        ClientProxyMembershipID proxy, int id) {
      this.className = name;
      this.eventId = event;
      this.proxyId = proxy;
      this.id = id;
    }

    /**
     * 
     * @return String the classname of the data serializer this instance
     *         represents.
     */
    public String getClassName() {
      return this.className;
    }

    public EventID getEventId() {
      return this.eventId;
    }

    public ClientProxyMembershipID getProxyId() {
      return this.proxyId;
    }

    public int getId() {
      return this.id;
    }

    @Override
    public String toString() {
      return "SerializerAttributesHolder[name=" + this.className + ",id=" + this.id + ",eventId=" + this.eventId + "]";
    }
  }

  private static void sendRegistrationMessageToServers(DataSerializer dataSerializer)
  {
    PoolManagerImpl.allPoolsRegisterDataSerializers(dataSerializer);
  }

  private static void sendRegistrationMessageToServers(
      SerializerAttributesHolder holder) {
    PoolManagerImpl.allPoolsRegisterDataSerializers(holder);
  }

  private static void sendRegistrationMessageToClients(DataSerializer dataSerializer)
  {
    Cache cache = GemFireCacheImpl.getInstance();
    if (cache == null) {
      // A cache has not yet been created.
      // we can't propagate it to clients
      return;
    }
    byte[][] serializedDataSerializer = new byte[2][];
    try {
      serializedDataSerializer[0] = CacheServerHelper.serialize(dataSerializer
          .getClass().toString().substring(6));
      {
        byte[] idBytes = new byte[4];
        Part.encodeInt(dataSerializer.getId(), idBytes);
        serializedDataSerializer[1] = idBytes;
      }
    }
    catch (IOException e) {
        if(logger.fineEnabled()){
          logger.fine("InternalDataSerializer encountered an IOException while serializing DataSerializer :" + dataSerializer);
        }
      }
    ClientDataSerializerMessage clientDataSerializerMessage = new ClientDataSerializerMessage(
        EnumListenerEvent.AFTER_REGISTER_DATASERIALIZER, serializedDataSerializer,
        (ClientProxyMembershipID)dataSerializer.getContext(),
        (EventID)dataSerializer.getEventId(),
        new Class[][]{dataSerializer.getSupportedClasses()}, logger);
    // Deliver it to all the clients
    CacheClientNotifier.routeClientMessage(clientDataSerializerMessage);
  }

  public static EventID generateEventId(){
    GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
    if(cache == null){
      // A cache has not yet created
      return null;
    }
    return new EventID(InternalDistributedSystem.getAnyInstance());
  }
  /**
   * Unregisters a Serializer that was previously
   * registered with the data serialization framework.
   */
  public static void unregister(int id) {
    final Integer idx = Integer.valueOf(id);
    Object o = idsToSerializers.remove(idx);
    if (o != null) {
      if (o instanceof InitMarker) {
        o = ((Marker)o).getSerializer();
      }
    }
    if (o instanceof DataSerializer) {
      DataSerializer s = (DataSerializer)o;
      Class[] classes = s.getSupportedClasses();
      for (int i = 0; i < classes.length; i++) {
        classesToSerializers.remove(classes[i].getName(), s);
        supportedClassesToHolders.remove(classes[i].getName());
      }
      dsClassesToHolders.remove(s.getClass().getName());
      idsToHolders.remove(idx);
    }
  }
  
  // testHook used to clean up any registered DataSerializers
  public static void reinitialize() {
    idsToSerializers.clear();
    classesToSerializers.clear();
    supportedClassesToHolders.clear();
    dsClassesToHolders.clear();
    idsToHolders.clear();
    initializeWellKnownSerializers();
  }

  /**
   * Returns the DataSerializer for the given class.  If
   * no class has been registered, null is returned.
   * Remember that it is okay to return null in this
   * case.  This method is invoked when writing an object.  If a
   * serializer isn't available, then its the user's fault.
   */
  public static DataSerializer getSerializer(Class c) {
    DataSerializer ds = classesToSerializers.get(c.getName());
    if (ds == null) {
      SerializerAttributesHolder sah = supportedClassesToHolders.get(c.getName());
      if (sah != null) {
        Class dsClass = null;
        try {
          dsClass = getCachedClass(sah.getClassName());

          DataSerializer serializer = register(dsClass, false);
          dsClassesToHolders.remove(dsClass.getName());
          idsToHolders.remove(serializer.getId());
          for (Class clazz : serializer.getSupportedClasses()) {
            supportedClassesToHolders.remove(clazz.getName());
          }
          return serializer;
        } catch (ClassNotFoundException cnfe) {
          if (logger.infoEnabled()) {
            logger.info(LocalizedStrings.InternalDataSerializer_COULD_NOT_LOAD_DATASERIALIZER_CLASS_0, dsClass);
          }
        }
      }
    }
    return ds;
  }

  /**
   * Returns the DataSerializer with the given id.
   */
  public static DataSerializer getSerializer(int id) {
    final Integer idx = Integer.valueOf(id);
    final GetMarker marker = new GetMarker();
    DataSerializer result = null;
    boolean timedOut = false;
    while (result == null && !timedOut && idsToHolders.get(idx) == null) {
      Object o = idsToSerializers.putIfAbsent(idx, marker);
      if (o == null) {
        result = marker.getSerializer();
        if (result == null) {
          // timed out
          timedOut = true;
          idsToSerializers.remove(idx, marker);
        }
      } else if (o instanceof Marker) {
        result = ((Marker)o).getSerializer();
      } else {
        result = (DataSerializer) o;
      }
    }
    if (result == null) {
      SerializerAttributesHolder sah = idsToHolders.get(idx);
      if (sah != null) {
        Class dsClass = null;
        try {
          dsClass = getCachedClass(sah.getClassName());

          DataSerializer ds = register(dsClass, false);
          dsClassesToHolders.remove(sah.getClassName());
          idsToHolders.remove(id);
          for (Class clazz : ds.getSupportedClasses()) {
            supportedClassesToHolders.remove(clazz.getName());
          }
          return ds;
        } catch (ClassNotFoundException cnfe) {
          if (logger.infoEnabled()) {
            logger
                .info(
                    LocalizedStrings.InternalDataSerializer_COULD_NOT_LOAD_DATASERIALIZER_CLASS_0,
                    dsClass);
          }
        }
      }
    }
    return result;
  }
  /**
   * Returns all of the currently registered serializers
   */
  public static DataSerializer[] getSerializers() {
    final int size = idsToSerializers.size();
    Collection coll = new ArrayList(size);
    Iterator it = idsToSerializers.values().iterator();
    while (it.hasNext()) {
      Object v = it.next();
      if (v instanceof InitMarker) {
        v = ((Marker)v).getSerializer();
      }
      if (v instanceof DataSerializer) {
        coll.add(v);
      }
    }

    Iterator> iterator = dsClassesToHolders.entrySet().iterator();
    while (iterator.hasNext()) {
      Entry entry = iterator.next();
      String name = entry.getKey();
      SerializerAttributesHolder holder = entry.getValue();
      try {
        Class cl = getCachedClass(name); 
        DataSerializer ds = null;
        if (holder.getEventId() != null) {
          ds = register(cl, false, holder.getEventId(), holder.getProxyId());
        } else {
          ds = register(cl, false);
        }
        coll.add(ds);
        iterator.remove();
        idsToHolders.remove(ds.getId());
        for (Class clazz : ds.getSupportedClasses()) {
          supportedClassesToHolders.remove(clazz.getName());
        }
      } catch (ClassNotFoundException cnfe) {
        if (logger.infoEnabled()) {
          logger
              .info(
                  LocalizedStrings.InternalDataSerializer_COULD_NOT_LOAD_DATASERIALIZER_CLASS_0,
                  name);
        }
      }
    }

    return (DataSerializer[]) coll.toArray(new DataSerializer[coll.size()]);
  }

  /**
   * Returns all the data serializers in this vm. This method, unlike
   * {@link #getSerializers()}, does not force loading of the data serializers
   * which were not loaded in the vm earlier.
   * 
   * @return Array of {@link SerializerAttributesHolder}
   */
  public static SerializerAttributesHolder[] getSerializersForDistribution() {

    final int size = idsToSerializers.size() + dsClassesToHolders.size();
    Collection coll = new ArrayList(
        size);

    Iterator it = idsToSerializers.values().iterator();
    while (it.hasNext()) {
      Object v = it.next();
      if (v instanceof InitMarker) {
        v = ((Marker)v).getSerializer();
      }
      if (v instanceof DataSerializer) {
        DataSerializer s = (DataSerializer)v;
        coll.add(new SerializerAttributesHolder(s.getClass().getName(),
            (EventID)s.getEventId(), (ClientProxyMembershipID)s.getContext(), s
                .getId()));
      }
    }

    Iterator> iterator = dsClassesToHolders
        .entrySet().iterator();
    while (iterator.hasNext()) {
      SerializerAttributesHolder v = iterator.next().getValue();
      coll.add(v);
    }

    return coll.toArray(new SerializerAttributesHolder[coll.size()]);
  }

  /**
   * Persist this class's map to out 
   */
  public static void saveRegistrations(DataOutput out) throws IOException {
    Iterator it = idsToSerializers.values().iterator();
    while (it.hasNext()) {
      Object v = it.next();
      if (v instanceof InitMarker) {
        v = ((Marker)v).getSerializer();
      }
      if (v instanceof DataSerializer) {
        DataSerializer ds = (DataSerializer)v;
        out.writeInt(ds.getId()); // since 5.7 an int instead of a byte
        DataSerializer.writeClass(ds.getClass(), out);
      }
    }
    if (!dsClassesToHolders.isEmpty()) {
      Iterator> iterator = dsClassesToHolders
          .entrySet().iterator();
      Class dsClass = null;
      while (iterator.hasNext()) {
        try {
          dsClass = getCachedClass(iterator.next().getKey());
        } catch (ClassNotFoundException cnfe) {
          if (logger.infoEnabled()) {
            logger.info(LocalizedStrings.InternalDataSerializer_COULD_NOT_LOAD_DATASERIALIZER_CLASS_0, dsClass);
          }
          continue;
        }
        DataSerializer ds = register(dsClass, false);
        iterator.remove();
        idsToHolders.remove(ds.getId());
        for (Class clazz : ds.getSupportedClasses()) {
          supportedClassesToHolders.remove(clazz.getName());
        }

        out.writeInt(ds.getId()); // since 5.7 an int instead of a byte
        DataSerializer.writeClass(ds.getClass(), out);
      }
    }
    // We know that DataSerializer's id must be > 0 so write a zero
    // to mark the end of the ds list.
    out.writeInt(0); // since 5.7 an int instead of a byte
  }

  /**
   * Read the data from in and register it with this class.
   * @throws IllegalArgumentException if a registration fails
   */
  public static void loadRegistrations(DataInput in) throws IOException
  {
    while (in.readInt() != 0) {
      Class dsClass = null;
      boolean skip = false;
      try {
        dsClass = DataSerializer.readClass(in);
      } catch (ClassNotFoundException ex) {
        skip = true;
      }
      if (skip) {
        continue;
      }
      register(dsClass, /*dsId,*/ true);
    }
  }

  /**
   * Adds a RegistrationListener that will receive
   * callbacks when DataSerializers and
   * Instantiators are registered.
   */
  public static void addRegistrationListener(RegistrationListener l) {
    synchronized (listenersSync) {
      Set newSet = new HashSet(listeners);
      newSet.add(l);
      listeners = newSet;
    }
  }

  /**
   * Removes a RegistrationListener so that it no longer
   * receives callbacks.
   */
  public static void removeRegistrationListener(RegistrationListener l) {
    synchronized (listenersSync) {
      Set newSet = new HashSet(listeners);
      newSet.remove(l);
      listeners = newSet;
    }
  }

  /**
   * Alerts all RegistrationListeners that a new
   * DataSerializer has been registered
   *
   * @see InternalDataSerializer.RegistrationListener#newDataSerializer
   */
  private static void fireNewDataSerializer(DataSerializer ds) {
    Iterator iter = listeners.iterator();
    while (iter.hasNext()) {
      RegistrationListener listener = (RegistrationListener) iter.next();
      listener.newDataSerializer(ds);
    }
  }

  /**
   * Alerts all RegistrationListeners that a new
   * Instantiator has been registered
   *
   * @see InternalDataSerializer.RegistrationListener#newInstantiator
   */
  static void fireNewInstantiator(Instantiator instantiator) {
    Iterator iter = listeners.iterator();
    while (iter.hasNext()) {
      RegistrationListener listener = (RegistrationListener) iter.next();
      listener.newInstantiator(instantiator);
    }
  }

  /**
   * If we are connected to a distributed system, send a message to
   * other members telling them about a newly-registered serializer.
   */
  private static void sendRegistrationMessage(DataSerializer s) {
    InternalDistributedSystem system = InternalDistributedSystem.getConnectedInstance();
    if (system != null) {
      RegistrationMessage m = new RegistrationMessage(s);
      system.getDistributionManager().putOutgoing(m);
    }
  }

  ///////////////// START DataSerializer Implementation Methods ///////////

  public static final void writeDSFID(DataSerializableFixedID o, DataOutput out)
    throws IOException {
    int dsfid = o.getDSFID();
    if (dsfid == DataSerializableFixedID.ILLEGAL) {
      throw new IllegalStateException(LocalizedStrings
          .InternalDataSerializer_ATTEMPTED_TO_SERIALIZE_ILLEGAL_DSFID
          .toLocalizedString());
    }
    if (DEBUG) {
      logger.info(LocalizedStrings.DEBUG, "writeDSFID " + dsfid + " class=" + o.getClass());
    }
    if (DEBUG_DSFID) {
      if (dsfid != DataSerializableFixedID.NO_FIXED_ID) {
        // consistency check to make sure that the same DSFID is not used
        // for two different classes
        String newClassName = o.getClass().getName();
        String existingClassName = (String)dsfidToClassMap.putIfAbsent(Integer.valueOf(dsfid), newClassName);
        if (existingClassName != null && !existingClassName.equals(newClassName)) {
          logger.error( StringIdImpl.LITERAL,
                       "dsfid=" + dsfid
                       + " is used for class " + existingClassName
                       + " and class " + newClassName);
        }
      }
    }
    if (dsfid <= Byte.MAX_VALUE && dsfid >= Byte.MIN_VALUE) {
      out.writeByte(DS_FIXED_ID_BYTE);
      out.writeByte(dsfid);
    } else if (dsfid <= Short.MAX_VALUE && dsfid >= Short.MIN_VALUE) {
      out.writeByte(DS_FIXED_ID_SHORT);
      out.writeShort(dsfid);
    } else if (dsfid == DataSerializableFixedID.NO_FIXED_ID) {
      out.writeByte(DS_NO_FIXED_ID);
      DataSerializer.writeClass(o.getClass(), out);
    } else {
      out.writeByte(DS_FIXED_ID_INT);
      out.writeInt(dsfid);
    }
    try {
      // Check if instance of GfxdDataSerializable to write gfxdID first.
      if (dsfid == DataSerializableFixedID.GFXD_TYPE) {
        out.writeByte(((GfxdDSFID)o).getGfxdID());
      }
      invokeToData(o, out);
    } catch (IOException io) {
      // Note: this is not a user code toData but one from our
      // internal code since only GemFire product code implements DSFID
      throw io;
    } catch (CancelException ex) {
      //Serializing a PDX can result in a cache closed exception. Just rethrow
      throw ex;
    } catch (ToDataException ex) {
      throw ex;
    } catch (GemFireRethrowable ex) {
      throw ex;
    } catch (Throwable t) {
      Error err;
      if (t instanceof Error && SystemFailure.isJVMFailureError(
          err = (Error)t)) {
        SystemFailure.initiateFailure(err);
        // If this ever returns, rethrow the error. We're poisoned
        // now, so don't let this thread continue.
        throw err;
      }
      // Whenever you catch Error or Throwable, you must also
      // check for fatal JVM error (see above).  However, there is
      // _still_ a possibility that you are dealing with a cascading
      // error condition, so you also need to check to see if the JVM
      // is still usable:
      SystemFailure.checkFailure();
      throw new ToDataException("toData failed on dsfid=" + dsfid+" msg:"+t.getMessage(),  t);
    }
  }

  public static final void writeStreamableFixedID(StreamableFixedID o,
      DataOutput out) throws IOException {
    int dsfid = o.getDSFID();
    if (dsfid == DataSerializableFixedID.ILLEGAL) {
      throw new IllegalStateException(LocalizedStrings
          .InternalDataSerializer_ATTEMPTED_TO_SERIALIZE_ILLEGAL_DSFID
          .toLocalizedString());
    }
    if (dsfidToClassMap != null && DEBUG_DSFID) {
      logger.fine("writeDSFID " + dsfid + " class=" + o.getClass());
      if (dsfid != DataSerializableFixedID.NO_FIXED_ID) {
        // consistency check to make sure that the same DSFID is not used
        // for two different classes
        String newClassName = o.getClass().getName();
        String existingClassName = (String)dsfidToClassMap.putIfAbsent(
            dsfid, newClassName);
        if (existingClassName != null && !existingClassName.equals(newClassName)) {
          logger.fine("dsfid=" + dsfid + " is used for class "
              + existingClassName + " and class " + newClassName);
        }
      }
    }
    if (dsfid <= Byte.MAX_VALUE && dsfid >= Byte.MIN_VALUE) {
      out.writeByte(DS_FIXED_ID_BYTE);
      out.writeByte(dsfid);
    } else if (dsfid <= Short.MAX_VALUE && dsfid >= Short.MIN_VALUE) {
      out.writeByte(DS_FIXED_ID_SHORT);
      out.writeShort(dsfid);
    } else if (dsfid == DataSerializableFixedID.NO_FIXED_ID) {
      out.writeByte(DS_NO_FIXED_ID);
      DataSerializer.writeClass(o.getClass(), out);
    } else {
      out.writeByte(DS_FIXED_ID_INT);
      out.writeInt(dsfid);
    }
    try {
      invokeToData(o, out);
    } catch (IOException io) {
      // Note: this is not a user code toData but one from our
      // internal code since only GemFire product code implements DSFID
      throw io;
    } catch (CancelException ex) {
      //Serializing a PDX can result in a cache closed exception. Just rethrow
      throw ex;
    } catch (ToDataException ex) {
      throw ex;
    } catch (GemFireRethrowable ex) {
      throw ex;
    } catch (VirtualMachineError err) {
      SystemFailure.initiateFailure(err);
      // If this ever returns, rethrow the error.  We're poisoned
      // now, so don't let this thread continue.
      throw err;
    } catch (Throwable t) {
      // Whenever you catch Error or Throwable, you must also
      // catch VirtualMachineError (see above).  However, there is
      // _still_ a possibility that you are dealing with a cascading
      // error condition, so you also need to check to see if the JVM
      // is still usable:
      SystemFailure.checkFailure();
      throw new ToDataException("toData failed on dsfid=" + dsfid + " msg: "
          + t.getMessage(), t);
    }
  }

  /**
   * Data serializes an instance of a well-known class to the given
   * DataOutput.
   *
   * @return true if o was actually
   *         written to out
   */
  public static boolean writeWellKnownObject(Object o,
      DataOutput out, boolean ensurePdxCompatibility)
    throws IOException {
    return writeUserObject(o, out, ensurePdxCompatibility);
  }
  /**
   * Data serializes an instance of a "user class" (that is, a class
   * that can be handled by a registered DataSerializer)
   * to the given DataOutput.
   *
   * @return true if o was written to
   *         out.
   */
  private static boolean writeUserObject(Object o, DataOutput out,
      boolean ensurePdxCompatibility) throws IOException {

    final Class c = o.getClass();
    final DataSerializer serializer =
      InternalDataSerializer.getSerializer(c);
    if (serializer != null) {
      int id = serializer.getId();
      if (id != 0) {
        checkPdxCompatible(o, ensurePdxCompatibility);
        // id will be 0 if it is a WellKnowDS
        if (id <= Byte.MAX_VALUE && id >= Byte.MIN_VALUE) {
          out.writeByte(USER_CLASS);
          out.writeByte((byte)id);
        } else if (id <= Short.MAX_VALUE && id >= Short.MIN_VALUE) {
          out.writeByte(USER_CLASS_2);
          out.writeShort(id);
        } else {
          out.writeByte(USER_CLASS_4);
          out.writeInt(id);
        }
      } else {
        if (ensurePdxCompatibility) {
          if (!(serializer instanceof WellKnownPdxDS)) {
            checkPdxCompatible(o, ensurePdxCompatibility);
          }
        }
      }
      boolean toDataResult = false;
      try {
        toDataResult = serializer.toData(o, out);
      } catch (IOException io) {
        // We no longer rethrow IOException here
        // because if usee code throws an IOException we want
        // to create a ToDataException to report it as a problem
        // with the plugin code.
        throw new ToDataException("toData failed on DataSerializer with id=" + id + " for class " + c,  io);
      } catch (ToDataException ex) {
        throw ex;
      } catch (CancelException ex) {
        //Serializing a PDX can result in a cache closed exception. Just rethrow
        throw ex;
      } catch (GemFireRethrowable ex) {
        throw ex;
      } catch (Throwable t) {
        Error err;
        if (t instanceof Error && SystemFailure.isJVMFailureError(
            err = (Error)t)) {
          SystemFailure.initiateFailure(err);
          // If this ever returns, rethrow the error. We're poisoned
          // now, so don't let this thread continue.
          throw err;
        }
        // Whenever you catch Error or Throwable, you must also
        // check for fatal JVM error (see above).  However, there is
        // _still_ a possibility that you are dealing with a cascading
        // error condition, so you also need to check to see if the JVM
        // is still usable:
        SystemFailure.checkFailure();
        throw new ToDataException("toData failed on DataSerializer with id=" + id + " for class " + c,  t);
      }
      if (toDataResult) {
        return true;
      } else {
        throw new ToDataException(
          LocalizedStrings.DataSerializer_SERIALIZER_0_A_1_SAID_THAT_IT_COULD_SERIALIZE_AN_INSTANCE_OF_2_BUT_ITS_TODATA_METHOD_RETURNED_FALSE
          .toLocalizedString(new Object[]{Integer.valueOf(serializer.getId()), serializer.getClass().getName(), o.getClass().getName()}));
      }
      // Do byte[][] and Object[] here to fix bug 44060
    } else if (o instanceof byte[][]) {
      byte[][] byteArrays = (byte[][])o;
      out.writeByte(ARRAY_OF_BYTE_ARRAYS);
      writeArrayOfByteArrays(byteArrays, out);
      return true;
    } else if (o instanceof Object[]) {
      Object[] array = (Object[]) o;
      out.writeByte(OBJECT_ARRAY);
      writeObjectArray(array, out, ensurePdxCompatibility);
      return true;
    } else if (is662SerializationEnabled() && o.getClass().isEnum()) {
      if (isPdxSerializationInProgress()) {
        writePdxEnum((Enum)o, out);
      } else {
        // TODO once .NET is enhanced to support inline enums then it should be compatible.
        checkPdxCompatible(o, ensurePdxCompatibility);
        writeGemFireEnum((Enum)o, out);
      }
      return true;
    } else {
      PdxSerializer pdxSerializer = TypeRegistry.getPdxSerializer();
      if (pdxSerializer != null) {
        return writePdx(out, null, o, pdxSerializer);
      }
//       DSDataOutput out2 = new DSDataOutput(out);

//       for (int i = 0; i < serializers.length; i++) {
//         final DataSerializer myserializer =
//           (DataSerializer) serializers[i];
//         out2.setSerializerId(myserializer.getId());
//         if (myserializer.toData(o, out2)) {
//           if (!out2.hasWritten()) {
//             String s = "Serializer " + serializer + " serialized a " +
//               o.getClass().getName() + ", but it did not write " +
//               "any data";
//             throw new IOException(s);
//           }
//           return true;

//         } else {
//           if (out2.hasWritten()) {
//             String s = "Serializer " + myserializer +
//               " did not serialize a " + o.getClass().getName() +
//               ", but it wrote data";
//             throw new IOException(s);
//           }
//         }
//       }
      return false;
    }
  }


  public static boolean autoSerialized(Object o, DataOutput out) throws IOException {
    AutoSerializableManager asm = TypeRegistry.getAutoSerializableManager();
    if (asm != null) {
      AutoClassInfo aci = asm.getExistingClassInfo(o.getClass());
      if (aci != null) {
        GemFireCacheImpl gfc = GemFireCacheImpl.getForPdx("PDX registry is unavailable because the Cache has been closed.");
        TypeRegistry tr = gfc.getPdxRegistry();

        PdxWriterImpl writer;
        {
          PdxOutputStream os;
          if (out instanceof HeapDataOutputStream) {
            os = new PdxOutputStream((HeapDataOutputStream) out);
          } else {
            os = new PdxOutputStream();
          }
          writer = new PdxWriterImpl(tr, o, aci, os);
        }
        try {
          if (is662SerializationEnabled()) {
            boolean alreadyInProgress = isPdxSerializationInProgress();
            if (!alreadyInProgress) {
              setPdxSerializationInProgress(true);
              try {
                asm.writeData(writer, o, aci);
              } finally {
                setPdxSerializationInProgress(false);
              }
            } else {
              asm.writeData(writer, o, aci);
            }
          } else {
            asm.writeData(writer, o, aci);
          }
        } catch (ToDataException ex) {
          throw ex;
        } catch (CancelException ex) {
          //Serializing a PDX can result in a cache closed exception. Just rethrow
          throw ex;
        } catch (NonPortableClassException ex) {
          throw ex;
        } catch (GemFireRethrowable ex) {
          throw ex;
        } catch (Throwable t) {
          Error err;
          if (t instanceof Error
              && SystemFailure.isJVMFailureError(err = (Error)t)) {
            SystemFailure.initiateFailure(err);
            // If this ever returns, rethrow the error. We're poisoned
            // now, so don't let this thread continue.
            throw err;
          }
          // Whenever you catch Error or Throwable, you must also
          // check for fatal JVM error (see above). However, there is
          // _still_ a possibility that you are dealing with a cascading
          // error condition, so you also need to check to see if the JVM
          // is still usable:
          SystemFailure.checkFailure();
          throw new ToDataException(
              "PdxSerializer failed when calling toData on " + o.getClass(), t);
        }
        int bytesWritten = writer.completeByteStreamGeneration();
        getDMStats(gfc).incPdxSerialization(bytesWritten);
        if (!(out instanceof HeapDataOutputStream)) {
          writer.sendTo(out);
        }
        return true;
      }
    }
    return false;
  }

  public static void checkPdxCompatible(Object o, boolean ensurePdxCompatibility) {
    if (ensurePdxCompatibility) {
      throw new NonPortableClassException("Instances of " + o.getClass() + " are not compatible with non-java PDX.");
    }
  }

  /**
   * Test to see if the object is in the gemfire package,
   * to see if we should pass it on to a users custom serializater.
   * 
   * TODO - this is a hack. We should have different flavor of
   * write object for user objects that calls the serializer. Other
   * kinds of write object shouldn't even get to the pdx serializer.
   */
  private static boolean isGemfireObject(Object o) {
    return ((o instanceof Function) // fixes 43691
            || o.getClass().getName().startsWith("com.gemstone."))
      && !(o instanceof PdxSerializerObject);
  }

  /**
   * Reads an object that was serialized by a customer ("user")
   * DataSerializer from the given DataInput.
   *
   * @throws IOException
   *         If the serializer that can deserialize the object is
   *         not registered.
   */
  private static Object readUserObject(DataInput in, int serializerId)
    throws IOException, ClassNotFoundException {
    DataSerializer serializer =
      InternalDataSerializer.getSerializer(serializerId);

    if (serializer == null) {
      throw new IOException(LocalizedStrings.DataSerializer_SERIALIZER_0_IS_NOT_REGISTERED.toLocalizedString(new Object[] { Integer.valueOf(serializerId) }));
    }

    return serializer.fromData(in);
  }

  /**
   * Checks to make sure a DataOutput is not
   * null.
   *
   * @throws NullPointerException
   *         If out is null
   */
  public static void checkOut(DataOutput out) {
    if (out == null) {
      String s = "Null DataOutput";
      throw new NullPointerException(s);
    }
  }
  /**
   * Checks to make sure a DataInput is not
   * null.
   *
   * @throws NullPointerException
   *         If in is null
   */
  public static void checkIn(DataInput in) {
    if (in == null) {
      String s = "Null DataInput";
      throw new NullPointerException(s);
    }
  }



  /**
   * Writes a Set to a DataOutput.
   *
   * 

* * This method is internal because its semantics (that is, its * ability to write any kind of Set) are different from * the writeXXX methods of the external * DataSerializer. * * @throws IOException * A problem occurs while writing to out * * @see #readSet * * @since 4.0 */ public static void writeSet(Collection set, DataOutput out) throws IOException { checkOut(out); int size; if (set == null) { size = -1; } else { size = set.size(); } writeArrayLength(size, out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing HashSet with " + size + " elements: " + set); } if (size > 0) { for (Object element : set) { writeObject(element, out); } } } /** * Reads a Set from a DataInput. * * @throws IOException * A problem occurs while writing to out * @throws ClassNotFoundException * The class of one of the HashSet's * elements cannot be found. * * @see #writeSet * * @since 4.0 */ public static Set readSet(DataInput in) throws IOException, ClassNotFoundException { return readHashSet(in); } /** * Passed to {@link InternalDataSerializer#readCollection(DataInput, CollectionCreator)}. */ @SuppressWarnings("rawtypes") public static interface CollectionCreator { C newCollection(int initialCapacity); } /** * Reads a Collection from a DataInput given a * {@link CollectionCreator} for it. * * @throws IOException * A problem occurs while writing to out * @throws ClassNotFoundException * The class of one of the Set's elements cannot be * found. * * @see #writeSet * * @since 7.0 */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static C readCollection(DataInput in, CollectionCreator ctr) throws IOException, ClassNotFoundException { InternalDataSerializer.checkIn(in); final int size = InternalDataSerializer.readArrayLength(in); if (size >= 0) { final C coll = ctr.newCollection(size); for (int i = 0; i < size; i++) { coll.add(DataSerializer.readObject(in)); } if (DEBUG) { InternalDataSerializer.logger.info(LocalizedStrings.DEBUG, "Read Set (" + coll.getClass().getName() + ") with " + size + " elements: " + coll); } return coll; } return null; } /** * Reads a Set from a DataInput into the given * non-null collection. Returns true if collection read is non-null else * returns false. * * @throws IOException * A problem occurs while reading from in * @throws ClassNotFoundException * The class of one of the Set's elements cannot be * found. * * @see #writeSet */ public static boolean readCollection(DataInput in, Collection c) throws IOException, ClassNotFoundException { checkIn(in); final int size = readArrayLength(in); if (size >= 0) { E element; for (int index = 0; index < size; ++index) { element = DataSerializer. readObject(in); c.add(element); } if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read Collection with " + size + " elements: " + c); } return true; } return false; } /** * write a set of Long objects * @param set the set of Long objects * @param hasLongIDs if false, write only ints, not longs * @param out the output stream */ public static void writeSetOfLongs(Set set, boolean hasLongIDs, DataOutput out) throws IOException { if (set == null) { out.writeInt(-1); } else { out.writeInt(set.size()); out.writeBoolean(hasLongIDs); for (Iterator it=set.iterator(); it.hasNext(); ) { Long l = (Long)it.next(); if (hasLongIDs) { out.writeLong(l.longValue()); } else { out.writeInt((int)l.longValue()); } } } } /** read a set of Long objects */ public static Set readSetOfLongs(DataInput in) throws IOException { int size = in.readInt(); if (size < 0) { return null; } else { Set result = new HashSet(size); boolean longIDs = in.readBoolean(); for (int i=0; i readListOfLongs(DataInput in) throws IOException { int size = in.readInt(); if (size < 0) { return null; } else { List result = new LinkedList(); boolean longIDs = in.readBoolean(); for (int i=0; iDataOutput. */ public static final void writePrimitiveClass(Class c, DataOutput out) throws IOException { if (c == Boolean.TYPE) { out.writeByte(BOOLEAN_TYPE); } else if (c == Character.TYPE) { out.writeByte(CHARACTER_TYPE); } else if (c == Byte.TYPE) { out.writeByte(BYTE_TYPE); } else if (c == Short.TYPE) { out.writeByte(SHORT_TYPE); } else if (c == Integer.TYPE) { out.writeByte(INTEGER_TYPE); } else if (c == Long.TYPE) { out.writeByte(LONG_TYPE); } else if (c == Float.TYPE) { out.writeByte(FLOAT_TYPE); } else if (c == Double.TYPE) { out.writeByte(DOUBLE_TYPE); } else if (c == Void.TYPE) { out.writeByte(VOID_TYPE); } else if (c == null) { out.writeByte(NULL); } else { throw new InternalGemFireError(LocalizedStrings.InternalDataSerializer_UNKNOWN_PRIMITIVE_TYPE_0.toLocalizedString(c.getName())); } } public static final Class decodePrimitiveClass(byte typeCode) { switch (typeCode) { case BOOLEAN_TYPE: return Boolean.TYPE; case CHARACTER_TYPE: return Character.TYPE; case BYTE_TYPE: return Byte.TYPE; case SHORT_TYPE: return Short.TYPE; case INTEGER_TYPE: return Integer.TYPE; case LONG_TYPE: return Long.TYPE; case FLOAT_TYPE: return Float.TYPE; case DOUBLE_TYPE: return Double.TYPE; case VOID_TYPE: return Void.TYPE; case NULL: return null; default: throw new InternalGemFireError(LocalizedStrings.InternalDataSerializer_UNEXPECTED_TYPECODE_0.toLocalizedString(Byte.valueOf(typeCode))); } } private static final byte TIME_UNIT_NANOSECONDS = -1; private static final byte TIME_UNIT_MICROSECONDS = -2; private static final byte TIME_UNIT_MILLISECONDS = -3; private static final byte TIME_UNIT_SECONDS = -4; /** * Writes a TimeUnit to a DataOutput. * * @throws IOException * A problem occurs while writing to out * * @see #readTimeUnit */ public static void writeTimeUnit(TimeUnit unit, DataOutput out) throws IOException { InternalDataSerializer.checkOut(out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing TimeUnit: " + unit); } if (unit.equals(TimeUnit.NANOSECONDS)) { out.writeByte(TIME_UNIT_NANOSECONDS); } else if (unit.equals(TimeUnit.MICROSECONDS)) { out.writeByte(TIME_UNIT_MICROSECONDS); } else if (unit.equals(TimeUnit.MILLISECONDS)) { out.writeByte(TIME_UNIT_MILLISECONDS); } else if (unit.equals(TimeUnit.SECONDS)) { out.writeByte(TIME_UNIT_SECONDS); } else { throw new InternalGemFireException(LocalizedStrings.DataSerializer_UNSUPPORTED_TIMEUNIT_0.toLocalizedString(unit)); } } /** * Reads a TimeUnit from a DataInput. * * @throws IOException * A problem occurs while writing to out * * @see #writeTimeUnit */ public static TimeUnit readTimeUnit(DataInput in) throws IOException { InternalDataSerializer.checkIn(in); byte type = in.readByte(); TimeUnit unit; switch (type) { case TIME_UNIT_NANOSECONDS: unit = TimeUnit.NANOSECONDS; break; case TIME_UNIT_MICROSECONDS: unit = TimeUnit.MICROSECONDS; break; case TIME_UNIT_MILLISECONDS: unit = TimeUnit.MILLISECONDS; break; case TIME_UNIT_SECONDS: unit = TimeUnit.SECONDS; break; default: throw new IOException(LocalizedStrings.DataSerializer_UNKNOWN_TIMEUNIT_TYPE_0.toLocalizedString(Byte.valueOf(type))); } if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read TimeUnit: " + unit); } return unit; } public static void writeTimestamp(Timestamp o, DataOutput out) throws IOException { InternalDataSerializer.checkOut(out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing Timestamp: " + o); } DataSerializer.writePrimitiveLong(o.getTime(), out); } public static Timestamp readTimestamp(DataInput in) throws IOException { InternalDataSerializer.checkIn(in); Timestamp result = new Timestamp(DataSerializer.readPrimitiveLong(in)); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read Timestamp: " + result); } return result; } public static void writeUUID(java.util.UUID o, DataOutput out) throws IOException { InternalDataSerializer.checkOut(out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing UUID: " + o); } DataSerializer.writePrimitiveLong(o.getMostSignificantBits(), out); DataSerializer.writePrimitiveLong(o.getLeastSignificantBits(), out); } public static UUID readUUID(DataInput in) throws IOException { InternalDataSerializer.checkIn(in); long mb = DataSerializer.readPrimitiveLong(in); long lb = DataSerializer.readPrimitiveLong(in); UUID result = new UUID(mb, lb); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read UUID: " + result); } return result; } public static void writeBigDecimal(BigDecimal o, DataOutput out) throws IOException { InternalDataSerializer.checkOut(out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing BigDecimal: " + o); } // using a more optimized serialization for GemFireXD; precision never exceeds // 127 in GFXD, so writing a byte for scale works fine if (GemFireCacheImpl.gfxdSystem()) { int scale = o.scale(); if (scale < 0) { o = o.setScale(0); scale = 0; } out.writeByte(scale); writeBigInteger(o.unscaledValue(), out); } else { DataSerializer.writeString(o.toString(), out); } } public static BigDecimal readBigDecimal(DataInput in) throws IOException { InternalDataSerializer.checkIn(in); BigDecimal result; // using a more optimized serialization for GemFireXD if (GemFireCacheImpl.gfxdSystem()) { int scale = in.readByte(); BigInteger unscaledValue = readBigInteger(in); result = new BigDecimal(unscaledValue, scale); } else { result = new BigDecimal(DataSerializer.readString(in)); } if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read BigDecimal: " + result); } return result; } public static void writeBigInteger(BigInteger o, DataOutput out) throws IOException { InternalDataSerializer.checkOut(out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing BigInteger: " + o); } // using a more efficient version for GemFireXD but not for // GemFire for backward compatibility if (GemFireCacheImpl.gfxdSystem()) { out.writeByte(o.signum()); final int[] mag = ClientSharedUtils.getBigIntInternalMagnitude(o); if (mag != null) { serializeBigIntMagnitude(mag, out); } else { DataSerializer.writeByteArray(o.abs().toByteArray(), out); } } else { DataSerializer.writeByteArray(o.toByteArray(), out); } } public static BigInteger readBigInteger(DataInput in) throws IOException { InternalDataSerializer.checkIn(in); BigInteger result; if (GemFireCacheImpl.gfxdSystem()) { int sig = in.readByte(); result = new BigInteger(sig, DataSerializer.readByteArray(in)); } else { result = new BigInteger(DataSerializer.readByteArray(in)); } if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read BigInteger: " + result); } return result; } /** * Serialize the given magnitude array from {@link BigInteger} to given * DataOutput. The serialization is compatible with the * {@link BigInteger#BigInteger(int, byte[])} constructor not including the * initial byte array length written using * {@link #writeArrayLength(int, DataOutput)}. */ public static void serializeBigIntMagnitude(final int[] magnitude, final DataOutput out) throws IOException { final int size_1 = magnitude.length - 1; if (size_1 >= 0) { // Write in big-endian format to be compatible with // BigInteger(int,byte[]) constructor. // We don't write from the end to allow using the same strategy when // writing to DataOutput and since this may also be slightly more // efficient reading from memory in forward direction rather than reverse. final long firstInt = (magnitude[0] & ClientSharedUtils.MAG_MASK); int numBytesInFirstInt = ClientSharedUtils.numBytesWithoutZeros(firstInt); final int numBytes = (size_1 << 2) + numBytesInFirstInt; writeArrayLength(numBytes, out); // first write the actual number of bytes required for first integer while (numBytesInFirstInt-- > 0) { out.writeByte((int)((firstInt >>> (8 * numBytesInFirstInt)) & 0xFF)); } // now write the remaining integers that will each require four bytes int intValue; for (int index = 1; index <= size_1; ++index) { intValue = magnitude[index]; out.writeInt(intValue); } } else { writeArrayLength(0, out); } } /** * Serialize the given magnitude array from {@link BigInteger} to given byte * array starting at offset. Returns the number of bytes required for * serialization. The serialization is compatible with the * {@link BigInteger#BigInteger(int, byte[])} constructor. */ public static int serializeBigIntMagnitudeToBytes(final int[] magnitude, final byte[] outBytes, final int startPos) { final int size_1 = magnitude.length - 1; if (size_1 >= 0) { // Write in big-endian format to be compatible with // BigInteger(int,byte[]) constructor. // We don't write from the end to allow using the same strategy when // writing to DataOutput and since this may also be slightly more // efficient reading from memory in forward direction rather than reverse. final long firstInt = ((long)magnitude[0] & ClientSharedUtils.MAG_MASK); int numBytesInFirstInt = ClientSharedUtils.numBytesWithoutZeros(firstInt); // first write the actual number of bytes required for first integer int offset = startPos; while (numBytesInFirstInt-- > 0) { outBytes[offset++] = (byte)(firstInt >>> (8 * numBytesInFirstInt)); } // now write the remaining integers that will each require four bytes int intValue; for (int index = 1; index <= size_1; ++index) { intValue = magnitude[index]; outBytes[offset++] = (byte)((intValue >>> 24) & 0xFF); outBytes[offset++] = (byte)((intValue >>> 16) & 0xFF); outBytes[offset++] = (byte)((intValue >>> 8) & 0xFF); outBytes[offset++] = (byte)(intValue & 0xFF); } final int numBytes; assert (offset - startPos) == (numBytes = ((size_1 << 2) + ClientSharedUtils.numBytesWithoutZeros(firstInt))): "unexpected " + "mismatch of byte length, expected=" + numBytes + " actual=" + (offset - startPos); return (offset - startPos); } return 0; } private static final boolean DEBUG_DSFID = Boolean.getBoolean("InternalDataSerializer.DEBUG_DSFID"); //private static final HashSet seenClassNames = DEBUG_DSFID ? new HashSet(): null; private static final CM dsfidToClassMap = DEBUG_DSFID ? CFactory.createCM(): null; public static final void writeUserDataSerializableHeader(int classId, DataOutput out) throws IOException { if (classId <= Byte.MAX_VALUE && classId >= Byte.MIN_VALUE) { out.writeByte(USER_DATA_SERIALIZABLE); out.writeByte(classId); } else if (classId <= Short.MAX_VALUE && classId >= Short.MIN_VALUE) { out.writeByte(USER_DATA_SERIALIZABLE_2); out.writeShort(classId); } else { out.writeByte(USER_DATA_SERIALIZABLE_4); out.writeInt(classId); } } /** * Writes given number of characters from array of chars to a * DataOutput. * * @throws IOException * A problem occurs while writing to out * * @see DataSerializer#readCharArray * @since 6.6 */ public static void writeCharArray(char[] array, int length, DataOutput out) throws IOException { checkOut(out); if (array == null) { length = -1; } writeArrayLength(length, out); if (DEBUG) { InternalDataSerializer.logger.info(LocalizedStrings.DEBUG, "Writing char array of length " + length); } if (length > 0) { for (int i = 0; i < length; i++) { out.writeChar(array[i]); } } } /** * returns true if the byte array is the serialized form of a null reference * @param serializedForm the serialized byte array */ public static final boolean isSerializedNull(byte[] serializedForm) { return serializedForm.length == 1 && serializedForm[0] == NULL; } public static final void basicWriteObject(Object o, DataOutput out, boolean ensurePdxCompatibility) throws IOException { checkOut(out); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "basicWriteObject: " + o); } // Handle special objects first if (o == null) { out.writeByte(NULL); } else if (o instanceof DataSerializableFixedID) { checkPdxCompatible(o, ensurePdxCompatibility); DataSerializableFixedID dsfid = (DataSerializableFixedID)o; writeDSFID(dsfid, out); } else if (o instanceof StreamableFixedID) { if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing JGroups StreamableFixedID: " + o); } StreamableFixedID sf = (StreamableFixedID)o; writeStreamableFixedID(sf, out); } else if (o instanceof VersionedStreamable) { if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing JGroups VersionedStreamable: " + o); } VersionedStreamable vs = (VersionedStreamable)o; Class c = o.getClass(); out.writeByte(DATA_SERIALIZABLE); DataSerializer.writeClass(c, out); invokeToData(vs, out); } else if (autoSerialized(o, out)) { // all done } else if (o instanceof DataSerializable.Replaceable) { // do this first to fix bug 31609 // do this before DataSerializable Object replacement = ((DataSerializable.Replaceable) o).replace(); basicWriteObject(replacement, out, ensurePdxCompatibility); } else if (o instanceof PdxSerializable) { writePdx(out, GemFireCacheImpl.getForPdx("PDX registry is unavailable because the Cache has been closed."), o, null); } else if (o instanceof DataSerializable) { if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Writing DataSerializable: " + o); } checkPdxCompatible(o, ensurePdxCompatibility); // @todo darrel: make a subinterface of DataSerializable // named InstantiatedDataSerializable // which adds one method which returns the instantiator code. // This would allow the serialization side to not need a map lookup (instead they just call the method) // which also helps the DataSerializable case to no longer do the lookup. // We could also use it to get rid of the need for static register calls // but that would mean that when we find one of these that we check to see // if that class had been registered and do so if not. // So from the customer's point of view this would be easier; just implement // a method that returns an int. Class c = o.getClass(); // Is "c" a user class registered with an Instantiator? int classId = InternalInstantiator.getClassId(c); if (classId != 0) { writeUserDataSerializableHeader(classId, out); } else { out.writeByte(DATA_SERIALIZABLE); // if (DEBUG_DSFID) { // if (logger.infoEnabled()) { // boolean alreadySeen; // synchronized (seenClassNames) { // alreadySeen = seenClassNames.add(c.getName()); // } // if (alreadySeen) { // // this class should be made a DSFID if it is a product class // logger.info("DataSerialized class " + c.getName(), new RuntimeException("CALLSTACK")); // } // } // } DataSerializer.writeClass(c, out); } DataSerializable ds = (DataSerializable) o; invokeToData(ds, out); } else if (o instanceof Sendable) { if (!(o instanceof PdxInstance) || o instanceof PdxInstanceEnum) { checkPdxCompatible(o, ensurePdxCompatibility); } ((Sendable)o).sendTo(out); } else if (writeWellKnownObject(o, out, ensurePdxCompatibility)) { // Nothing more to do... } else { checkPdxCompatible(o, ensurePdxCompatibility); if (DUMP_SERIALIZED || DEBUG) { logger.info(LocalizedStrings.DEBUG, "DataSerializer Serializing an " + "instance of " + o.getClass().getName()); } /* If the (internally known) ThreadLocal named "DataSerializer.DISALLOW_JAVA_SERIALIZATION" is set, * then an exception will be thrown if we try to do standard Java Serialization. * This is used to catch Java serialization early for the case where the data is being * sent to a non-Java client */ if (disallowJavaSerialization() && (o instanceof Serializable)) { throw new NotSerializableException(LocalizedStrings.DataSerializer_0_IS_NOT_DATASERIALIZABLE_AND_JAVA_SERIALIZATION_IS_DISALLOWED.toLocalizedString(o.getClass().getName())); } // if (out instanceof DSDataOutput) { // // Unwrap the DSDataOutput to avoid one layer of // // delegation. This also prevents us from having to flush // // the ObjectOutputStream. // out = ((DSDataOutput) out).out; // } writeSerializableObject(o, out); } } private static boolean disallowJavaSerialization() { Boolean v = DISALLOW_JAVA_SERIALIZATION.get(); return v != null && v; } /** * @throws IOException * @since 6.6.2 */ private static void writePdxEnum(Enum e, DataOutput out) throws IOException { TypeRegistry tr = GemFireCacheImpl.getForPdx("PDX registry is unavailable because the Cache has been closed.").getPdxRegistry(); int eId = tr.getEnumId(e); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "write PdxEnum id=" + eId + " enum=" + e); } writePdxEnumId(eId, out); } public static void writePdxEnumId(int eId, DataOutput out) throws IOException { out.writeByte(PDX_ENUM); out.writeByte(eId >> 24); writeArrayLength(eId & 0xFFFFFF, out); } /** * @throws IOException * since 6.6.2 */ private static Object readPdxEnum(DataInput in) throws IOException { int dsId = in.readByte(); int tmp = readArrayLength(in); int enumId = (dsId << 24) | (tmp & 0xFFFFFF); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "read PdxEnum id=" + enumId); } GemFireCacheImpl gfc = GemFireCacheImpl.getForPdx("PDX registry is unavailable because the Cache has been closed."); TypeRegistry tr = gfc.getPdxRegistry(); Object result = tr.getEnumById(enumId); if (result instanceof PdxInstance) { getDMStats(gfc).incPdxInstanceCreations(); } return result; } private static void writeGemFireEnum(Enum e, DataOutput out) throws IOException { boolean isGemFireObject = isGemfireObject(e); DataSerializer.writePrimitiveByte(isGemFireObject ? GEMFIRE_ENUM : PDX_INLINE_ENUM, out); DataSerializer.writeString(e.getDeclaringClass().getName(), out); DataSerializer.writeString(e.name(), out); if (!isGemFireObject) { InternalDataSerializer.writeArrayLength(e.ordinal(), out); } } @SuppressWarnings("unchecked") private static Enum readGemFireEnum(DataInput in) throws IOException, ClassNotFoundException { String className = DataSerializer.readString(in); String enumName = DataSerializer.readString(in); @SuppressWarnings("rawtypes") Class c = getCachedClass(className); return Enum.valueOf(c, enumName); } private static Object readPdxInlineEnum(DataInput in) throws IOException, ClassNotFoundException { GemFireCacheImpl gfc = GemFireCacheImpl.getInstance(); if (gfc != null && gfc.getPdxReadSerializedByAnyGemFireServices()) { String className = DataSerializer.readString(in); String enumName = DataSerializer.readString(in); int enumOrdinal = InternalDataSerializer.readArrayLength(in); getDMStats(gfc).incPdxInstanceCreations(); return new PdxInstanceEnum(className, enumName, enumOrdinal); } else { Enum e = readGemFireEnum(in); InternalDataSerializer.readArrayLength(in); return e; } } /** * write an object in java Serializable form with a SERIALIZABLE DSCODE so * that it can be deserialized with DataSerializer.readObject() * @param o the object to serialize * @param out the data output to serialize to * @throws IOException */ public static final void writeSerializableObject(Object o, DataOutput out) throws IOException { out.writeByte(SERIALIZABLE); if (out instanceof ObjectOutputStream) { ((ObjectOutputStream)out).writeObject(o); } else { OutputStream stream; if (out instanceof OutputStream) { stream = (OutputStream)out; } else { final DataOutput out2 = out; stream = new OutputStream() { @Override public void write(int b) throws IOException { out2.write(b); } // public void write(byte[] b) throws IOException { // out.write(b); // } // public void write(byte[] b, int off, int len) // throws IOException { // out.write(b, off, len); // } }; } ObjectOutput oos = new ObjectOutputStream(stream); if ( stream instanceof VersionedDataStream ) { Version v = ((VersionedDataStream)stream).getVersion(); if (v != null && v != Version.CURRENT) { oos = new VersionedObjectOutput(oos, v); } } oos.writeObject(o); // To fix bug 35568 just call flush. We can't call close because // it calls close on the wrapped OutputStream. oos.flush(); } } /** * For backward compatibility this method should be used to invoke * toData on a DSFID or DataSerializable. It will invoke the * correct toData method based on the class's version information. * This method does not write information about the class of the * object. When deserializing use the method invokeFromData to * read the contents of the object. * * @param ds the object to write * @param out the output stream. */ public static final void invokeToData(DataSerializableFixedID ds, DataOutput out) throws IOException { try { if (!invokeVersionedToData(ds, out)) { ds.toData(out); } } catch (IOException io) { // DSFID serialization expects an IOException but otherwise // we want to catch it and transform into a ToDataException // since it might be in user code and we want to report it // as a problem with the plugin code throw io; } catch (ToDataException ex) { throw ex; } catch (Throwable t) { handleToDataException(t, ds); } } /** * For backward compatibility this method should be used to invoke * toData on a DSFID or DataSerializable. It will invoke the * correct toData method based on the class's version information. * This method does not write information about the class of the * object. When deserializing use the method invokeFromData to * read the contents of the object. * * @param ds the object to write * @param out the output stream. */ public static final void invokeToData(DataSerializable ds, DataOutput out) throws IOException { try { if (!invokeVersionedToData(ds, out)) { ds.toData(out); } } catch (IOException io) { // DSFID serialization expects an IOException but otherwise // we want to catch it and transform into a ToDataException // since it might be in user code and we want to report it // as a problem with the plugin code throw new ToDataException("toData failed on DataSerializable " + ds.getClass(), io); } catch (Throwable t) { handleToDataException(t, ds); } } /** * For backward compatibility this method should be used to invoke * toData on a DSFID or DataSerializable. It will invoke the * correct toData method based on the class's version information. * This method does not write information about the class of the * object. When deserializing use the method invokeFromData to * read the contents of the object. * * @param ds the object to write * @param out the output stream. */ public static final void invokeToData(VersionedStreamable ds, DataOutput out) throws IOException { try { if (!invokeVersionedToData(ds, out)) { ds.toData(out); } } catch (IOException io) { // DSFID serialization expects an IOException but otherwise // we want to catch it and transform into a ToDataException // since it might be in user code and we want to report it // as a problem with the plugin code throw new ToDataException("toData failed on DataSerializable " + ds.getClass(), io); } catch (Throwable t) { handleToDataException(t, ds); } } private static final boolean invokeVersionedToData(Object ds, DataOutput out) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { Version v = getVersionForDataStreamOrNull(out); if (v == null || v == Version.CURRENT) { return false; } // get versions where DataOutput was upgraded Version[] versions; if (ds instanceof SerializationVersions) { SerializationVersions sv = (SerializationVersions)ds; versions = sv.getSerializationVersions(); } else if (ds instanceof VersionedStreamable) { VersionedStreamable vs = (VersionedStreamable)ds; short[] ordinals = vs.getSerializationVersions(); if (ordinals == null || ordinals.length == 0) { versions = null; } else { versions = new Version[ordinals.length]; for (int i = 0; i < ordinals.length; i++) { versions[i] = Version.fromOrdinalOrCurrent(ordinals[i]); } } } else { return false; } // check if the version of the peer or diskstore is different and // there has been a change in the message if (versions != null && versions.length > 0) { for (int i = 0; i < versions.length; i++) { // if peer version is less than the greatest upgraded version if (v.compareTo(versions[i]) < 0) { ds.getClass() .getMethod("toDataPre_" + versions[i].getMethodSuffix(), new Class[] { DataOutput.class }).invoke(ds, out); return true; } } } return false; } private static void handleToDataException(Throwable t, Object ds) { if (t instanceof ToDataException) { throw (ToDataException)t; } else if (t instanceof CancelException) { //Serializing a PDX can result in a cache closed exception. Just rethrow throw (CancelException)t; } else if (t instanceof GemFireRethrowable) { throw (GemFireRethrowable)t; } else if (t instanceof Error) { Error err = (Error)t; if (SystemFailure.isJVMFailureError(err)) { // GemStoneAddition SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); throw new ToDataException("toData failed on DataSerializable " + ds.getClass(), t); } /** * For backward compatibility this method should be used to invoke * fromData on a DSFID or DataSerializable. It will invoke the * correct fromData method based on the class's version information. * This method does not read information about the class of the * object. When serializing use the method invokeToData to * write the contents of the object. * * @param ds the object to write * @param in the input stream. */ public static final void invokeFromData(DataSerializableFixedID ds, DataInput in) throws IOException, ClassNotFoundException { try { if (!invokeVersionedFromData(ds, in)) { ds.fromData(in); } } catch (EOFException ex) { // client went away - ignore throw ex; } catch (ClassNotFoundException ex) { throw ex; } catch (CacheClosedException cce) { throw cce; } catch (Exception ex) { logger.severe(LocalizedStrings.ONE_ARG, "exception in deserialization", ex); SerializationException ex2 = new SerializationException(LocalizedStrings .DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_0.toLocalizedString( ds.getClass().getName()), ex); throw ex2; } } /** * For backward compatibility this method should be used to invoke * fromData on a DSFID or DataSerializable. It will invoke the * correct fromData method based on the class's version information. * This method does not read information about the class of the * object. When serializing use the method invokeToData to * write the contents of the object. * * @param ds the object to write * @param in the input stream. */ public static final void invokeFromData(DataSerializable ds, DataInput in) throws IOException, ClassNotFoundException { try { if (!invokeVersionedFromData(ds, in)) { ds.fromData(in); } } catch (EOFException ex) { // client went away - ignore throw ex; } catch (ClassNotFoundException ex) { throw ex; } catch (CacheClosedException cce) { throw cce; } catch (Exception ex) { logger.severe(LocalizedStrings.ONE_ARG, "exception in deserialization", ex); SerializationException ex2 = new SerializationException(LocalizedStrings .DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_0.toLocalizedString( ds.getClass().getName()), ex); throw ex2; } } /** * For backward compatibility this method should be used to invoke * fromData on a DSFID or DataSerializable. It will invoke the * correct fromData method based on the class's version information. * This method does not read information about the class of the * object. When serializing use the method invokeToData to * write the contents of the object. * * @param ds the object to write * @param in the input stream. */ public static final void invokeFromData(VersionedStreamable ds, DataInput in) throws IOException, ClassNotFoundException { try { if (!invokeVersionedFromData(ds, in)) { ds.fromData(in); } } catch (EOFException ex) { // client went away - ignore throw ex; } catch (ClassNotFoundException ex) { throw ex; } catch (CacheClosedException cce) { throw cce; } catch (Exception ex) { logger.severe(LocalizedStrings.ONE_ARG, "exception in deserialization", ex); SerializationException ex2 = new SerializationException(LocalizedStrings .DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_0.toLocalizedString( ds.getClass().getName()), ex); throw ex2; } } private static final boolean invokeVersionedFromData(Object ds, DataInput in) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { Version v = getVersionForDataStreamOrNull(in); if (v == null || v == Version.CURRENT) { return false; } // get versions where DataOutput was upgraded Version[] versions; if (ds instanceof SerializationVersions) { SerializationVersions vds = (SerializationVersions)ds; versions = vds.getSerializationVersions(); } else if (ds instanceof VersionedStreamable) { VersionedStreamable vs = (VersionedStreamable)ds; short[] ordinals = vs.getSerializationVersions(); if (ordinals == null || ordinals.length == 0) { versions = null; } else { versions = new Version[ordinals.length]; for (int i = 0; i < ordinals.length; i++) { versions[i] = Version.fromOrdinalOrCurrent(ordinals[i]); } } } else { return false; } // check if the version of the peer or diskstore is different and // there has been a change in the message if (versions != null && versions.length > 0) { for (int i = 0; i < versions.length; i++) { // if peer version is less than the greatest upgraded version if (v.compareTo(versions[i]) < 0) { ds.getClass() .getMethod("fromDataPre" + "_" + versions[i].getMethodSuffix(), new Class[]{DataInput.class}).invoke(ds, in); return true; } } } return false; } private static final Object readDataSerializable(final DataInput in) throws IOException, ClassNotFoundException { Class c = readClass(in); try { Constructor init = c.getConstructor(ZERO_CLASS_ARGS); init.setAccessible(true); Object o = init.newInstance(ZERO_ARGS); if (o instanceof DataSerializable) { invokeFromData((DataSerializable)o, in); } else { invokeFromData((VersionedStreamable)o, in); } if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read DataSerializable " + o); } return o; } catch (EOFException ex) { // client went away - ignore throw ex; } catch (Exception ex) { logger.severe(LocalizedStrings.ONE_ARG, "exception in deserialization", ex); SerializationException ex2 = new SerializationException(LocalizedStrings .DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_0 .toLocalizedString(c.getName()), ex); throw ex2; } } private static final DataSerializableFixedID readDataSerializableFixedID( final DataInput in) throws IOException, ClassNotFoundException { Class c = readClass(in); try { Constructor init = c.getConstructor(ZERO_CLASS_ARGS); init.setAccessible(true); DataSerializableFixedID ds = (DataSerializableFixedID)init.newInstance( ZERO_ARGS); invokeFromData(ds, in); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read DataSerializableFixedID " + ds); } return ds; } catch (Exception ex) { logger.severe(LocalizedStrings.ONE_ARG, "exception in deserialization", ex); SerializationException ex2 = new SerializationException(LocalizedStrings .DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_0 .toLocalizedString(c.getName()), ex); throw ex2; } } /** * Get the {@link Version} of the peer or disk store that created this * {@link DataInput}. */ public static final Version getVersionForDataStream(DataInput in) { // check if this is a versioned data input if (in instanceof VersionedDataStream) { final Version v = ((VersionedDataStream)in).getVersion(); return v != null ? v : Version.CURRENT; } else { // assume latest version return Version.CURRENT; } } /** * Get the {@link Version} of the peer or disk store that created this * {@link DataInput}. Returns null if the version is same as this member's. */ public static final Version getVersionForDataStreamOrNull(DataInput in) { // check if this is a versioned data input if (in instanceof VersionedDataStream) { return ((VersionedDataStream)in).getVersion(); } else { // assume latest version return null; } } /** * Get the {@link Version} of the peer or disk store that created this * {@link DataOutput}. */ public static final Version getVersionForDataStream(DataOutput out) { // check if this is a versioned data output if (out instanceof VersionedDataStream) { final Version v = ((VersionedDataStream)out).getVersion(); return v != null ? v : Version.CURRENT; } else { // assume latest version return Version.CURRENT; } } /** * Get the {@link Version} of the peer or disk store that created this * {@link DataOutput}. Returns null if the version is same as this member's. */ public static final Version getVersionForDataStreamOrNull(DataOutput out) { // check if this is a versioned data output if (out instanceof VersionedDataStream) { return ((VersionedDataStream)out).getVersion(); } else { // assume latest version return null; } } public static final byte NULL_ARRAY = -1; // array is null /** * @since 5.7 */ private static final byte SHORT_ARRAY_LEN = -2; // array len encoded as unsigned short in next 2 bytes /** * @since 5.7 */ public static final byte INT_ARRAY_LEN = -3; // array len encoded as int in next 4 bytes private static final int MAX_BYTE_ARRAY_LEN = ((byte)-4) & 0xFF; public static final class WriteKeyValue implements TObjectObjectProcedure { private final DataOutput out; public WriteKeyValue(final DataOutput out) { this.out = out; } @Override public boolean execute(Object a, Object b) { try { writeObject(a, out); writeObject(b, out); } catch (IOException e) { return false; } return true; } } public static void writeArrayLength(int len, DataOutput out) throws IOException { if (len == -1) { out.writeByte(NULL_ARRAY); } else if (len <= MAX_BYTE_ARRAY_LEN) { out.writeByte(len); } else if (len <= 0xFFFF) { out.writeByte(SHORT_ARRAY_LEN); out.writeShort(len); } else { out.writeByte(INT_ARRAY_LEN); out.writeInt(len); } } public static int readArrayLength(DataInput in) throws IOException { byte code = in.readByte(); if (code == NULL_ARRAY) { return -1; } else { int result = ubyteToInt(code); if (result > MAX_BYTE_ARRAY_LEN) { if (code == SHORT_ARRAY_LEN) { result = in.readUnsignedShort(); } else if (code == INT_ARRAY_LEN) { result = in.readInt(); } else { throw new IllegalStateException("unexpected array length code=" + code); } } return result; } } public static int writeArrayLength(int len, byte[] buffer, int offset) throws IOException { if (len == -1) { buffer[offset++] = NULL_ARRAY; return offset; } else if (len <= MAX_BYTE_ARRAY_LEN) { buffer[offset++] = (byte)len; return offset; } else if (len <= 0xFFFF) { buffer[offset++] = SHORT_ARRAY_LEN; buffer[offset++] = (byte)((len >>> 8) & 0xFF); buffer[offset++] = (byte)(len & 0xFF); return offset; } else { buffer[offset++] = INT_ARRAY_LEN; buffer[offset++] = (byte)((len >>> 24) & 0xFF); buffer[offset++] = (byte)((len >>> 16) & 0xFF); buffer[offset++] = (byte)((len >>> 8) & 0xFF); buffer[offset++] = (byte)(len & 0xFF); return offset; } } /** * The minimum value a compact value can have and still be stored in the * archive as one byte. */ static final int MIN_1BYTE_COMPACT_VALUE = Byte.MIN_VALUE + 3; /** * Means the next 2 bytes hold the compact value's data. */ static final int COMPACT_VALUE_2_TOKEN = Byte.MIN_VALUE; /** * now used only for compatibility with GFXD 1.0.3 disk files. DO NOT USE * OTHERWISE IN NEW CODE -- INSTEAD SEE {@link #readSignedVL(DataInput)}, * {@link #readUnsignedVL(DataInput)}. */ public static int readCompactInt(final DataInput in) throws IOException { final boolean dump = DataSerializer.DEBUG; int v = in.readByte(); if (dump) { logger.info(LocalizedStrings.DEBUG, "readCompactValue(byte1)=" + v); } if (v < MIN_1BYTE_COMPACT_VALUE) { if (v == COMPACT_VALUE_2_TOKEN) { v = in.readShort(); if (dump) { logger.info(LocalizedStrings.DEBUG, "readCompactValue(short)=" + v); } } else { int bytesToRead = (v - COMPACT_VALUE_2_TOKEN) + 2; v = in.readByte(); // note the first byte will be a signed byte. if (dump) { logger.info(LocalizedStrings.DEBUG, "readCompactValue(byte2[" + bytesToRead + "])=" + v); } bytesToRead--; while (bytesToRead > 0) { v <<= 8; int b = in.readUnsignedByte(); v |= b; if (dump) { logger.info(LocalizedStrings.DEBUG, "readCompactValue(" + bytesToRead + ")=" + b); logger.info(LocalizedStrings.DEBUG, "readCompactValue v=" + v); } bytesToRead--; } } } return v; } /** * Reads and discards an array of bytes from a * DataInput. * * @throws IOException * A problem occurs while writing to out * * @see #writeByteArray(byte[], DataOutput) */ public static void skipByteArray(DataInput in) throws IOException { InternalDataSerializer.checkIn(in); int length = InternalDataSerializer.readArrayLength(in); if (length != -1) { in.skipBytes(length); if (DEBUG) { InternalDataSerializer.logger.info( LocalizedStrings.DEBUG, "Skipped byte array of length " + length); } } } public static final Object readDSFID(final DataInput in) throws IOException, ClassNotFoundException { checkIn(in); byte header = in.readByte(); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "readDSFID: header=" + header); } if (header == DS_FIXED_ID_BYTE) { return DSFIDFactory.create(in.readByte(), in); } else if (header == DS_FIXED_ID_SHORT) { return DSFIDFactory.create(in.readShort(), in); } else if (header == DS_NO_FIXED_ID) { return readDataSerializableFixedID(in); } else if (header == DS_FIXED_ID_INT) { return DSFIDFactory.create(in.readInt(), in); } else { throw new IllegalStateException("unexpected byte: " + header + " while reading dsfid"); } } /** * Reads an instance of String from a * DataInput given the header byte already being read. * The return value may be null. * * @throws IOException * A problem occurs while reading from in * * @since 5.7 */ public static String readString(DataInput in, byte header) throws IOException { if (header == DSCODE.STRING_BYTES) { int len = in.readUnsignedShort(); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Reading STRING_BYTES of len="+len); } byte[] buf = new byte[len]; in.readFully(buf, 0, len); return new String(buf, 0); // intentionally using deprecated constructor } else if (header == DSCODE.STRING) { if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Reading utf STRING"); } return in.readUTF(); } else if (header == DSCODE.NULL_STRING) { if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Reading NULL_STRING"); } return null; } else if (header == DSCODE.HUGE_STRING_BYTES) { int len = in.readInt(); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Reading HUGE_STRING_BYTES of len="+len); } byte[] buf = new byte[len]; in.readFully(buf, 0, len); return new String(buf, 0); // intentionally using deprecated constructor } else if (header == DSCODE.HUGE_STRING) { int len = in.readInt(); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Reading HUGE_STRING of len="+len); } char[] buf = new char[len]; for (int i=0; i < len; i++) { buf[i] = in.readChar(); } return new String(buf); } else { String s = "Unknown String header " + header; throw new IOException(s); } } private static DataSerializer dvddeserializer; public static void registerDVDDeserializer(DataSerializer dvddeslzr) { dvddeserializer = dvddeslzr; } /** * Just like readObject but make sure and pdx deserialized is not * a PdxInstance. * @since 6.6.2 */ public static final T readNonPdxInstanceObject(final DataInput in) throws IOException, ClassNotFoundException { boolean wouldReadSerialized = PdxInstanceImpl.getPdxReadSerialized(); if (!wouldReadSerialized) { return DataSerializer.readObject(in); } else { PdxInstanceImpl.setPdxReadSerialized(false); try { return DataSerializer.readObject(in); } finally { PdxInstanceImpl.setPdxReadSerialized(true); } } } public static final Object basicReadObject(final DataInput in) throws IOException, ClassNotFoundException { checkIn(in); // Read the header byte byte header = in.readByte(); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "basicReadObject: header=" + header); } return readObject(header, in); } public static final Object readObject(final byte header, final DataInput in) throws IOException, ClassNotFoundException { switch (header) { case DS_FIXED_ID_BYTE: return DSFIDFactory.create(in.readByte(), in); case DS_FIXED_ID_SHORT: return DSFIDFactory.create(in.readShort(), in); case DS_FIXED_ID_INT: return DSFIDFactory.create(in.readInt(), in); case DS_NO_FIXED_ID: return readDataSerializableFixedID(in); case GFXD_DVD_ARR: return dvddeserializer.fromData(in); case NULL: return null; case NULL_STRING: case STRING: case HUGE_STRING: case STRING_BYTES: case HUGE_STRING_BYTES: return readString(in, header); case CLASS: return readClass(in); case DATE: return readDate(in); case FILE: return readFile(in); case INET_ADDRESS: return readInetAddress(in); case BOOLEAN: return readBoolean(in); case CHARACTER: return readCharacter(in); case BYTE: return readByte(in); case SHORT: return readShort(in); case INTEGER: return readInteger(in); case LONG: return readLong(in); case FLOAT: return readFloat(in); case DOUBLE: return readDouble(in); case BYTE_ARRAY: return readByteArray(in); case ARRAY_OF_BYTE_ARRAYS: return readArrayOfByteArrays(in); case SHORT_ARRAY: return readShortArray(in); case STRING_ARRAY: return readStringArray(in); case INT_ARRAY: return readIntArray(in); case LONG_ARRAY: return readLongArray(in); case FLOAT_ARRAY: return readFloatArray(in); case DOUBLE_ARRAY: return readDoubleArray(in); case BOOLEAN_ARRAY: return readBooleanArray(in); case CHAR_ARRAY: return readCharArray(in); case OBJECT_ARRAY: return readObjectArray(in); case ARRAY_LIST: return readArrayList(in); case LINKED_LIST: return readLinkedList(in); case HASH_SET: return readHashSet(in); case LINKED_HASH_SET: return readLinkedHashSet(in); case HASH_MAP: return readHashMap(in); case IDENTITY_HASH_MAP: return readIdentityHashMap(in); case HASH_TABLE: return readHashtable(in); case CONCURRENT_HASH_MAP: return readConcurrentHashMap(in); case PROPERTIES: return readProperties(in); case TIME_UNIT: return readTimeUnit(in); case USER_CLASS: return readUserObject(in, in.readByte()); case USER_CLASS_2: return readUserObject(in, in.readShort()); case USER_CLASS_4: return readUserObject(in, in.readInt()); case VECTOR: return readVector(in); case STACK: return readStack(in); case TREE_MAP: return readTreeMap(in); case TREE_SET: return readTreeSet(in); case BOOLEAN_TYPE: return Boolean.TYPE; case CHARACTER_TYPE: return Character.TYPE; case BYTE_TYPE: return Byte.TYPE; case SHORT_TYPE: return Short.TYPE; case INTEGER_TYPE: return Integer.TYPE; case LONG_TYPE: return Long.TYPE; case FLOAT_TYPE: return Float.TYPE; case DOUBLE_TYPE: return Double.TYPE; case VOID_TYPE: return Void.TYPE; case USER_DATA_SERIALIZABLE: return readUserDataSerializable(in, in.readByte()); case USER_DATA_SERIALIZABLE_2: return readUserDataSerializable(in, in.readShort()); case USER_DATA_SERIALIZABLE_4: return readUserDataSerializable(in, in.readInt()); case DATA_SERIALIZABLE: return readDataSerializable(in); case SERIALIZABLE: { Object serializableResult = null; if (in instanceof DSObjectInputStream) { serializableResult = ((DSObjectInputStream)in).readObject(); } else { InputStream stream; if (in instanceof InputStream) { stream = (InputStream)in; } else { stream = new InputStream() { @Override public int read() throws IOException { try { return in.readUnsignedByte(); // fix for bug 47249 } catch (EOFException enfOfStream) { // InputStream.read() should return -1 on EOF return -1; } } // public int read(byte[] b, int off, int len) // throws IOException { // // @todo davidw Do read() and readFully() have the // // same semantics in this case? // in.readFully(b, off, len); // return len; // } // public long skip(long n) throws IOException { // // @todo davidw Is casting the right thing to do? // return in.skipBytes((int) n); // } }; } ObjectInput ois = new DSObjectInputStream(stream); if ( stream instanceof VersionedDataStream ) { Version v = ((VersionedDataStream)stream).getVersion(); if (v != null && v != Version.CURRENT) { ois = new VersionedObjectInput(ois, v); } } serializableResult = ois.readObject(); if (DEBUG) { logger.info(LocalizedStrings.DEBUG, "Read Serializable object: " + serializableResult); } } if (TRACE_SERIALIZABLE) { logger.info(LocalizedStrings.DEBUG, "deserialized instanceof " + serializableResult.getClass()); } return serializableResult; } case PDX: return readPdxSerializable(in); case PDX_ENUM: return readPdxEnum(in); case GEMFIRE_ENUM: return readGemFireEnum(in); case PDX_INLINE_ENUM: return readPdxInlineEnum(in); case BIG_INTEGER: return readBigInteger(in); case BIG_DECIMAL: return readBigDecimal(in); case UUID: return readUUID(in); case TIMESTAMP: return readTimestamp(in); default: String s = "Unknown header byte: " + header; throw new IOException(s); } } private static final Object readUserDataSerializable(final DataInput in, int classId) throws IOException, ClassNotFoundException { Instantiator instantiator = InternalInstantiator.getInstantiator(classId); if (instantiator == null) { logger.error(LocalizedStrings.DataSerializer_NO_INSTANTIATOR_HAS_BEEN_REGISTERED_FOR_CLASS_WITH_ID_0, Integer.valueOf(classId)); throw new IOException(LocalizedStrings.DataSerializer_NO_INSTANTIATOR_HAS_BEEN_REGISTERED_FOR_CLASS_WITH_ID_0.toLocalizedString(Integer.valueOf(classId))); } else { try { DataSerializable ds; if (instantiator instanceof CanonicalInstantiator) { CanonicalInstantiator ci = (CanonicalInstantiator)instantiator; ds = ci.newInstance(in); } else { ds = instantiator.newInstance(); } ds.fromData(in); return ds; } catch (Exception ex) { logger.severe(LocalizedStrings.ONE_ARG, "exception in deserialization", ex); SerializationException ex2 = new SerializationException(LocalizedStrings .DataSerializer_COULD_NOT_DESERIALIZE_AN_INSTANCE_OF_0 .toLocalizedString(instantiator.getInstantiatedClass().getName()), ex); throw ex2; } } } private static final ThreadLocal pdxSerializationInProgress = new ThreadLocal(); public static boolean isPdxSerializationInProgress() { Boolean v = pdxSerializationInProgress.get(); return v != null && v; } public static void setPdxSerializationInProgress(boolean v) { if (v) { pdxSerializationInProgress.set(true); } else { pdxSerializationInProgress.set(false); } } public final static boolean writePdx(DataOutput out, GemFireCacheImpl gfc, Object pdx, PdxSerializer pdxSerializer) throws IOException { TypeRegistry tr = null; if (gfc != null) { tr = gfc.getPdxRegistry(); } PdxWriterImpl writer; { PdxOutputStream os; if (out instanceof HeapDataOutputStream) { os = new PdxOutputStream((HeapDataOutputStream) out); } else { os = new PdxOutputStream(); } writer = new PdxWriterImpl(tr, pdx, os); } try { if (pdxSerializer != null) { //Hack to make sure we don't pass internal objects to the user's //serializer if(isGemfireObject(pdx)) { return false; } if (is662SerializationEnabled()) { boolean alreadyInProgress = isPdxSerializationInProgress(); if (!alreadyInProgress) { setPdxSerializationInProgress(true); try { if (!pdxSerializer.toData(pdx, writer)) { return false; } } finally { setPdxSerializationInProgress(false); } } else { if (!pdxSerializer.toData(pdx, writer)) { return false; } } } else { if (!pdxSerializer.toData(pdx, writer)) { return false; } } } else { if (is662SerializationEnabled()) { boolean alreadyInProgress = isPdxSerializationInProgress(); if (!alreadyInProgress) { setPdxSerializationInProgress(true); try { ((PdxSerializable) pdx).toData(writer); } finally { setPdxSerializationInProgress(false); } } else { ((PdxSerializable) pdx).toData(writer); } } else { ((PdxSerializable) pdx).toData(writer); } } } catch (ToDataException ex) { throw ex; } catch (CancelException ex) { //Serializing a PDX can result in a cache closed exception. Just rethrow throw ex; } catch (NonPortableClassException ex) { throw ex; } catch (GemFireRethrowable ex) { throw ex; } catch (Throwable t) { Error err; if (t instanceof Error && SystemFailure.isJVMFailureError( err = (Error)t)) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); if (pdxSerializer != null) { throw new ToDataException("PdxSerializer failed when calling toData on " + pdx.getClass(), t); } else { throw new ToDataException("toData failed on PdxSerializable " + pdx.getClass(), t); } } int bytesWritten = writer.completeByteStreamGeneration(); getDMStats(gfc).incPdxSerialization(bytesWritten); if (!(out instanceof HeapDataOutputStream)) { writer.sendTo(out); } return true; } public static DMStats getDMStats(GemFireCacheImpl gfc) { if (gfc != null) { return gfc.getDistributionManager().getStats(); } else { DMStats result = InternalDistributedSystem.getDMStats(); if (result == null) { result = new LonerDistributionManager.DummyDMStats(); } return result; } } private static final Object readPdxSerializable(final DataInput in) throws IOException, ClassNotFoundException { int len = in.readInt(); int typeId = in.readInt(); GemFireCacheImpl gfc = GemFireCacheImpl.getForPdx("PDX registry is unavailable because the Cache has been closed."); PdxType pdxType = gfc.getPdxRegistry().getType(typeId); if (DEBUG) { gfc.getLogger().info("readPdxSerializable pdxType="+ pdxType); } if (pdxType == null) { throw new IllegalStateException("Unknown pdx type=" + typeId); } DMStats dmStats = getDMStats(gfc); dmStats.incPdxDeserialization(len+9); // check if PdxInstance needs to be returned. if (pdxType.getNoDomainClass() || gfc.getPdxReadSerializedByAnyGemFireServices()) { // if (DEBUG) { // gfc.getLogger().info("returning PdxInstance", new Exception("stack trace")); // } dmStats.incPdxInstanceCreations(); return new PdxInstanceImpl(pdxType, in, len); } else { // if (DEBUG) { // gfc.getLogger().info("returning domain object", new Exception("stack trace")); // } // return domain object. PdxReaderImpl pdxReader = new PdxReaderImpl(pdxType, in, len); return pdxReader.getObject(); } } /** * Reads a PdxInstance from dataBytes and returns it. If the first object * read is not pdx encoded returns null. */ public static final PdxInstance readPdxInstance(final byte[] dataBytes, GemFireCacheImpl gfc) { try { byte type = dataBytes[0]; if (type == PDX) { PdxInputStream in = new PdxInputStream(dataBytes); in.readByte(); // throw away the type byte int len = in.readInt(); int typeId = in.readInt(); PdxType pdxType = gfc.getPdxRegistry().getType(typeId); //gfc.getLogger().info("DEBUG: pdxType="+ pdxType); if (pdxType == null) { throw new IllegalStateException("Unknown pdx type=" + typeId); } return new PdxInstanceImpl(pdxType, in, len); } else if (type == DSCODE.PDX_ENUM) { PdxInputStream in = new PdxInputStream(dataBytes); in.readByte(); // throw away the type byte int dsId = in.readByte(); int tmp = readArrayLength(in); int enumId = (dsId << 24) | (tmp & 0xFFFFFF); TypeRegistry tr = gfc.getPdxRegistry(); EnumInfo ei = tr.getEnumInfoById(enumId); if (ei == null) { throw new IllegalStateException("Unknown pdx enum id=" + enumId); } return ei.getPdxInstance(enumId); } else if (type == DSCODE.PDX_INLINE_ENUM) { PdxInputStream in = new PdxInputStream(dataBytes); in.readByte(); // throw away the type byte String className = DataSerializer.readString(in); String enumName = DataSerializer.readString(in); int enumOrdinal = InternalDataSerializer.readArrayLength(in); return new PdxInstanceEnum(className, enumName, enumOrdinal); } } catch (IOException ignore) { } return null; } ///////////////////////////// START Test only methods ///////////////////////////// public static int getLoadedDataSerializers() { return idsToSerializers.size(); } public final static Map getDsClassesToHoldersMap() { return dsClassesToHolders; } public final static Map getIdsToHoldersMap() { return idsToHolders; } public final static Map getSupportedClassesToHoldersMap() { return supportedClassesToHolders; } ///////////////////////////// END Test only methods ///////////////////////////// ///////////////// END DataSerializer Implementation Methods /////////// /////////////////////// Inner Classes /////////////////////// /** * A marker object for DataSerializers that have not * been registered. Using this marker object allows us to * asynchronously send DataSerializer registration * updates. If the serialized bytes arrive at a VM before the * registration message does, the deserializer will wait an amount * of time for the registration message to arrive. */ static abstract class Marker { /** The DataSerializer that is filled in upon registration */ protected DataSerializer serializer = null; /** set to true once setSerializer is called. */ protected boolean hasBeenSet = false; abstract DataSerializer getSerializer(); /** * Sets the serializer associated with this marker. It will * notify any threads that are waiting for the serializer to be * registered. */ void setSerializer(DataSerializer serializer) { synchronized (this) { this.hasBeenSet = true; this.serializer = serializer; this.notifyAll(); } } } /** * A marker object for DataSerializers that have not * been registered. Using this marker object allows us to * asynchronously send DataSerializer registration * updates. If the serialized bytes arrive at a VM before the * registration message does, the deserializer will wait an amount * of time for the registration message to arrive. * @since 5.7 */ static class GetMarker extends Marker { /** * Number of milliseconds to wait. Also used by InternalInstantiator. * Note that some tests set this to a small amount to speed up failures. */ static int WAIT_MS = 60 * 1000; /** * Returns the serializer associated with this marker. If the * serializer has not been registered yet, then this method will * wait until the serializer is registered. If this method has to * wait for too long, then null is returned. */ @Override DataSerializer getSerializer() { boolean firstTime = true; long endTime = 0; synchronized (this) { while (!this.hasBeenSet) { if (firstTime) { firstTime = false; endTime = System.currentTimeMillis() + WAIT_MS; } try { long remainingMs = endTime - System.currentTimeMillis(); if (remainingMs > 0) { this.wait(remainingMs); // spurious wakeup ok // if (!this.hasBeenSet) { // logger.info("DEBUG getSerializer had to wait for " + remainingMs + "ms", // new Exception("STACK")); // } } else { // timed out call setSerializer just to make sure that anyone else // also waiting on this marker times out also setSerializer(null); break; } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); // Just return null, let it fail return null; } } return this.serializer; } } } /** * A marker object for DataSerializers that is in the process * of being registered. * It is possible for getSerializer to return null * * @since 5.7 */ static class InitMarker extends Marker { /** * Returns the serializer associated with this marker. If the * serializer has not been registered yet, then this method will * wait until the serializer is registered. If this method has to * wait for too long, then null is returned. */ /** * Returns the serializer associated with this marker. * Waits forever (unless interrupted) for it to be initialized. * Returns null if this Marker failed to initialize. */ @Override DataSerializer getSerializer() { synchronized (this) { while (!this.hasBeenSet) { try { this.wait(); // spurious wakeup ok } catch (InterruptedException ex) { Thread.currentThread().interrupt(); // Just return null, let it fail return null; } } return this.serializer; } } } /** * A distribution message that alerts other members of the * distributed cache of a new DataSerializer being * registered. */ public static final class RegistrationMessage extends PooledDistributionMessage { /** The id of the DataSerializer that was * registered * since 5.7 an int instead of a byte */ private int id; /** The eventId of the DataSerializer that was * registered */ protected EventID eventId; /** The name of the DataSerializer class */ private String className; /** The versions in which this message was modified */ private static final Version[] dsfidVersions = new Version[]{}; /** * Constructor for DataSerializable */ public RegistrationMessage() { } /** * Creates a new RegistrationMessage that broadcasts * that the given DataSerializer was registered. */ public RegistrationMessage(DataSerializer s) { this.className = s.getClass().getName(); this.id = s.getId(); this.eventId = (EventID)s.getEventId(); } public static String getFullMessage(Throwable t) { StringBuffer sb = new StringBuffer(); getFullMessage(sb, t); return sb.toString(); } private static void getFullMessage(StringBuffer sb, Throwable t) { if (t.getMessage() != null) { sb.append(t.getMessage()); } else { sb.append(t.getClass()); } if (t.getCause() != null) { sb.append(" caused by: "); getFullMessage(sb, t.getCause()); } } @Override protected void process(DistributionManager dm) { if (CacheClientNotifier.getInstance() != null) { // This is a server so we need to send the dataserializer to clients // right away. For that we need to load the class as the constructor of // ClientDataSerializerMessage requires list of supported classes. Class c = null; try { c = getCachedClass(this.className); // fix for bug 41206 } catch (ClassNotFoundException ex) { // fixes bug 44112 dm.getLoggerI18n().warning(LocalizedStrings.ONE_ARG, "Could not load data serializer class " + this.className + " so both clients of this server and this server will not have this data serializer. Load failed because: " + getFullMessage(ex)); return; } DataSerializer s = null; try { s = newInstance(c); } catch (IllegalArgumentException ex) { // fixes bug 44112 dm.getLoggerI18n().warning(LocalizedStrings.ONE_ARG, "Could not create an instance of data serializer for class " + this.className + " so both clients of this server and this server will not have this data serializer. Create failed because: " + getFullMessage(ex)); return; } s.setEventId(this.eventId); try { InternalDataSerializer._register(s, false); } catch (IllegalArgumentException ex) { dm.getLoggerI18n().warning(LocalizedStrings.ONE_ARG, "Could not register data serializer for class " + this.className + " so both clients of this server and this server will not have this data serializer. Registration failed because: " + getFullMessage(ex)); return; } catch (IllegalStateException ex) { dm.getLoggerI18n().warning(LocalizedStrings.ONE_ARG, "Could not register data serializer for class " + this.className + " so both clients of this server and this server will not have this data serializer. Registration failed because: " + getFullMessage(ex)); return; } } else { try { InternalDataSerializer.register(this.className, false, this.eventId, null, this.id); } catch (IllegalArgumentException ex) { dm.getLoggerI18n().warning(LocalizedStrings.ONE_ARG, "Could not register data serializer for class " + this.className + " so it will not be available in this JVM. Registration failed because: " + getFullMessage(ex)); return; } catch (IllegalStateException ex) { dm.getLoggerI18n().warning(LocalizedStrings.ONE_ARG, "Could not register data serializer for class " + this.className + " so it will not be available in this JVM. Registration failed because: " + getFullMessage(ex)); return; } } } public int getDSFID() { return IDS_REGISTRATION_MESSAGE; } @Override public void toData(DataOutput out) throws IOException { super.toData(out); DataSerializer.writeNonPrimitiveClassName(this.className, out); out.writeInt(this.id); DataSerializer.writeObject(this.eventId, out); } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); InternalDataSerializer.checkIn(in); this.className = DataSerializer.readNonPrimitiveClassName(in); this.id = in.readInt(); this.eventId = (EventID)DataSerializer.readObject(in); } @Override public String toString() { return LocalizedStrings.InternalDataSerializer_REGISTER_DATASERIALIZER_0_OF_CLASS_1 .toLocalizedString(new Object[]{Integer.valueOf(this.id), this.className}); } @Override public Version[] getSerializationVersions() { return dsfidVersions; } } /** * A listener whose listener methods are invoked when {@link * DataSerializer}s and {@link Instantiator}s are registered. This * is part of the fix for bug 31422. * * @see InternalDataSerializer#addRegistrationListener * @see InternalDataSerializer#removeRegistrationListener */ public interface RegistrationListener { /** * Invoked when a new Instantiator is {@linkplain * Instantiator#register(Instantiator) registered}. */ public void newInstantiator(Instantiator instantiator); /** * Invoked when a new DataSerializer is {@linkplain * DataSerializer#register(Class) registered}. */ public void newDataSerializer(DataSerializer ds); } /** * An ObjectInputStream whose {@link #resolveClass} * method loads classes from the current context class loader. */ private static class DSObjectInputStream extends ObjectInputStream { /** * Creates a new DSObjectInputStream that delegates * its behavior to a given InputStream. */ public DSObjectInputStream(InputStream stream) throws IOException { super(stream); } @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String className = desc.getName(); try { return getCachedClass(className); } catch (ClassNotFoundException ex) { return super.resolveClass(desc); } } @Override protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { ClassLoader nonPublicLoader = null; boolean hasNonPublicInterface = false; // define proxy in class loader of non-public // interface(s), if any Class[] classObjs = new Class[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { Class cl = getCachedClass(interfaces[i]); if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { if (hasNonPublicInterface) { if (nonPublicLoader != cl.getClassLoader()) { String s = "conflicting non-public interface class loaders"; throw new IllegalAccessError(s); } } else { nonPublicLoader = cl.getClassLoader(); hasNonPublicInterface = true; } } classObjs[i] = cl; } try { if (hasNonPublicInterface) { return Proxy.getProxyClass(nonPublicLoader, classObjs); } else { return ClassPathLoader.getLatest().getProxyClass(classObjs); } } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } } } // /** // * A DataOutput that writes special header information // * before it writes any other data. It is passed to a // * DataSerializer's {@link // * DataSerializer#toData(Object, DataOutput)} method to ensure // * that the stream has the correct format. // */ // private static class DSDataOutput implements DataOutput { // /** Has the header information been written? */ // private boolean headerWritten = false; // /** The id of serializer that is writing to this output */ // private byte serializerId; // /** The output stream to which this DSDataOutput writes */ // protected DataOutput out; // ////////////////////// Constructors ////////////////////// // /** // * Creates a new DSDataOutput that write to the // * given output stream. // */ // DSDataOutput(DataOutput out) { // this.out = out; // } // ///////////////////// Instance Methods //////////////////// // /** // * Sets the id of the serializer that will possibly write to // * this stream. // */ // void setSerializerId(byte id) { // this.serializerId = id; // } // /** // * Returns whether or not any data hass been written to this // * stream. // */ // boolean hasWritten() { // return this.headerWritten; // } // /** // * Write the {@link #USER_CLASS} "class id" followed by the id // * of the serializer. // */ // private void writeHeader() throws IOException { // if (!headerWritten) { // out.writeByte(USER_CLASS); // out.writeByte(serializerId); // this.headerWritten = true; // } // } // public void write(int b) throws IOException { // writeHeader(); // out.write(b); // } // public void write(byte[] b) throws IOException { // writeHeader(); // out.write(b); // } // public void write(byte[] b, int off, int len) // throws IOException { // writeHeader(); // out.write(b, off, len); // } // public void writeBoolean(boolean v) throws IOException { // writeHeader(); // out.writeBoolean(v); // } // public void writeByte(int v) throws IOException { // writeHeader(); // out.writeByte(v); // } // public void writeShort(int v) throws IOException { // writeHeader(); // out.writeShort(v); // } // public void writeChar(int v) throws IOException { // writeHeader(); // out.writeChar(v); // } // public void writeInt(int v) throws IOException { // writeHeader(); // out.writeInt(v); // } // public void writeLong(long v) throws IOException { // writeHeader(); // out.writeLong(v); // } // public void writeFloat(float v) throws IOException { // writeHeader(); // out.writeFloat(v); // } // public void writeDouble(double v) throws IOException { // writeHeader(); // out.writeDouble(v); // } // public void writeBytes(String s) throws IOException { // writeHeader(); // out.writeBytes(s); // } // public void writeChars(String s) throws IOException { // writeHeader(); // out.writeChars(s); // } // public void writeUTF(String str) throws IOException { // writeHeader(); // out.writeUTF(str); // } // } /** * Used to implement serialization code for the well known classes we support * in DataSerializer. * @since 5.7 */ protected static abstract class WellKnownDS extends DataSerializer { @Override public final int getId() { // illegal for a customer to use but since our WellKnownDS is never registered // with this id it gives us one to use return 0; } @Override public final Class[] getSupportedClasses() { // illegal for a customer to return null but we can do it since we never register // this serializer. return null; } @Override public final Object fromData(DataInput in) throws IOException, ClassNotFoundException { throw new IllegalStateException(LocalizedStrings.SHOULDNT_INVOKE.toLocalizedString()); } // subclasses need to implement toData } /** * Just like a WellKnownDS but its type is compatible with PDX. * @author darrel * */ protected static abstract class WellKnownPdxDS extends WellKnownDS { // subclasses need to implement toData } public static void writeObjectArray(Object[] array, DataOutput out, boolean ensureCompatibility) throws IOException { InternalDataSerializer.checkOut(out); int length; if (array == null) { length = -1; } else { length = array.length; } InternalDataSerializer.writeArrayLength(length, out); if (DEBUG) { InternalDataSerializer.logger.info( LocalizedStrings.DEBUG, "Writing Object array of length " + length); } if (length >= 0) { writeClass(array.getClass().getComponentType(), out); for (int i = 0; i < length; i++) { basicWriteObject(array[i], out, ensureCompatibility); } } } private static final byte INT_VL = 126; // Variable Length long encoded as int // in next 4 bytes private static final byte LONG_VL = 127; // Variable Length long encoded as // long in next 8 bytes private static final int MAX_BYTE_VL = 125; /** * Write a variable length long the old way (pre 7.0). Use this * only in contexts where you might need to communicate with pre 7.0 * members or files. */ public static void writeVLOld(long data, DataOutput out) throws IOException { if(data < 0) { Assert.fail("Data expected to be >=0 is " + data); } if (data <= MAX_BYTE_VL) { out.writeByte((byte) data); } else if (data <= 0x7FFF) { // set the sign bit to indicate a short out.write((((int) data >>> 8) | 0x80) & 0xFF); out.write(((int) data >>> 0) & 0xFF); } else if (data <= Integer.MAX_VALUE) { out.writeByte(INT_VL); out.writeInt((int) data); } else { out.writeByte(LONG_VL); out.writeLong(data); } } /** * Write a variable length long the old way (pre 7.0). Use this * only in contexts where you might need to communicate with pre 7.0 * members or files. */ public static long readVLOld(DataInput in) throws IOException { byte code = in.readByte(); long result; if (code < 0) { // mask off sign bit result = code & 0x7F; result <<= 8; result |= in.readByte() & 0xFF; } else if (code <= MAX_BYTE_VL) { result = code; } else if (code == INT_VL) { result = in.readInt(); } else if (code == LONG_VL) { result = in.readLong(); } else { throw new IllegalStateException("unexpected variable length code=" + code); } return result; } /** * Encode a long as a variable length array. * * This method is appropriate for unsigned integers. For signed integers, * negative values will always consume 10 bytes, so it is recommended to * use writeSignedVL instead. * * This is taken from the varint encoding in protobufs (BSD licensed). * See https://developers.google.com/protocol-buffers/docs/encoding */ public static void writeUnsignedVL(long data, DataOutput out) throws IOException { while (true) { if ((data & ~0x7FL) == 0) { out.writeByte((int)data); return; } else { out.writeByte(((int)data & 0x7F) | 0x80); data >>>= 7; } } } /** * Encode a long as a variable length array. * * This method is appropriate for unsigned integers. For signed integers, * negative values will always consume 10 bytes, so it is recommended to * use writeSignedVL instead. * * This is taken from the varint encoding in protobufs (BSD licensed). * See https://developers.google.com/protocol-buffers/docs/encoding */ public static void writeUnsignedVL(long data, ByteBuffer buf) throws IOException { while (true) { if ((data & ~0x7FL) == 0) { buf.put((byte)(data & 0x7F)); return; } else { buf.put((byte)(((int)data & 0x7F) | 0x80)); data >>>= 7; } } } /** * Number of bytes required to encode a long as a variable length array. */ public static int getUnsignedVLSize(long data) { int size = 0; while (true) { if ((data & ~0x7FL) == 0) { return (++size); } else { size++; data >>>= 7; } } } /** * Decode a long as a variable length array. * * This is taken from the varint encoding in protobufs (BSD licensed). * See https://developers.google.com/protocol-buffers/docs/encoding */ public static long readUnsignedVL(DataInput in) throws IOException { int shift = 0; long result = 0; while (shift < 64) { final byte b = in.readByte(); result |= (long)(b & 0x7F) << shift; if ((b & 0x80) == 0) { return result; } shift += 7; } throw new GemFireIOException("Malformed variable length integer"); } /** * Encode a signed long as a variable length array. * * This method is appropriate for signed integers. It uses * zig zag encoding to so that negative numbers will be respresented more * compactly. For unsigned values, writeUnsignedVL will be more efficient. * */ public static void writeSignedVL(long data, DataOutput out) throws IOException { writeUnsignedVL(encodeZigZag64(data), out); } /** * Decode a signed long as a variable length array. * * This method is appropriate for signed integers. It uses * zig zag encoding to so that negative numbers will be respresented more * compactly. For unsigned values, writeUnsignedVL will be more efficient. * */ public static long readSignedVL(DataInput in) throws IOException { return decodeZigZag64(readUnsignedVL(in)); } /** * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers * into values that can be efficiently encoded with varint. (Otherwise, * negative values must be sign-extended to 64 bits to be varint encoded, * thus always taking 10 bytes on the wire.) * * @param n An unsigned 64-bit integer, stored in a signed int because * Java has no explicit unsigned support. * @return A signed 64-bit integer. * * This is taken from the varint encoding in protobufs (BSD licensed). * See https://developers.google.com/protocol-buffers/docs/encoding */ public static long decodeZigZag64(final long n) { return (n >>> 1) ^ -(n & 1); } /** * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers * into values that can be efficiently encoded with varint. (Otherwise, * negative values must be sign-extended to 64 bits to be varint encoded, * thus always taking 10 bytes on the wire.) * * @param n A signed 64-bit integer. * @return An unsigned 64-bit integer, stored in a signed int because * Java has no explicit unsigned support. * * This is taken from the varint encoding in protobufs (BSD licensed). * See https://developers.google.com/protocol-buffers/docs/encoding */ public static long encodeZigZag64(final long n) { // Note: the right-shift must be arithmetic return (n << 1) ^ (n >> 63); } /* test only method */ public static int calculateBytesForTSandDSID(int dsid) { HeapDataOutputStream out = new HeapDataOutputStream(4 + 8, Version.CURRENT); long now = System.currentTimeMillis(); try { writeUnsignedVL(now, out); writeUnsignedVL(InternalDataSerializer.encodeZigZag64(dsid), out); } catch (IOException e) { return 0; } return out.size(); } public static final boolean LOAD_CLASS_EACH_TIME = Boolean.getBoolean("gemfire.loadClassOnEveryDeserialization"); private static final CopyOnWriteHashMap>> classCache = LOAD_CLASS_EACH_TIME ? null : new CopyOnWriteHashMap>>(); private static final Object cacheAccessLock = new Object(); public static Class getCachedClass(String className) throws ClassNotFoundException { if (LOAD_CLASS_EACH_TIME) { return ClassPathLoader.getLatest().forName(className); } else { Class result = getExistingCachedClass(className); if (result == null) { // Do the forName call outside the sync to fix bug 46172 result = ClassPathLoader.getLatest().forName(className); synchronized (cacheAccessLock) { Class cachedClass = getExistingCachedClass(className); if (cachedClass == null) { classCache.put(className, new WeakReference>(result)); } else { result = cachedClass; } } } return result; } } private static Class getExistingCachedClass(String className) { WeakReference> wr = classCache.get(className); Class result = null; if (wr != null) { result = wr.get(); } return result; } public static void flushClassCache() { if (classCache != null) { // Not locking classCache during clear as doing so causes a deadlock in the JarClassLoader classCache.clear(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy