com.gemstone.gemfire.internal.InternalDataSerializer Maven / Gradle / Ivy
Show all versions of gemfire-core Show documentation
/* * 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
. */ 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 aclassesToSerializers = 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 (); /** RegistrationListener
s that receive callbacks when *DataSerializer
s andInstantiator
s 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 ofDataSerializer
* * @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 aDataSerializer
instance with the data * serialization framework. * * @param distribute * Should the registeredDataSerializer
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 aDataSerializer
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 aDataSerializer
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 theDataSerializer
for the given class. If * no class has been registered,null
is returned. * Remember that it is okay to returnnull
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 theDataSerializer
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 whenDataSerializer
s and *Instantiator
s are registered. */ public static void addRegistrationListener(RegistrationListener l) { synchronized (listenersSync) { Set newSet = new HashSet(listeners); newSet.add(l); listeners = newSet; } } /** * Removes aRegistrationListener
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 allRegistrationListener
s 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 allRegistrationListener
s 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
. * * @returntrue
ifo
was actually * written toout
*/ 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 registeredDataSerializer
) * to the givenDataOutput
. * * @returntrue
ifo
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 givenDataInput
. * * @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 aDataOutput
is not *null
. * * @throws NullPointerException * Ifout
isnull
*/ public static void checkOut(DataOutput out) { if (out == null) { String s = "Null DataOutput"; throw new NullPointerException(s); } } /** * Checks to make sure aDataInput
is not *null
. * * @throws NullPointerException * Ifin
isnull
*/ public static void checkIn(DataInput in) { if (in == null) { String s = "Null DataInput"; throw new NullPointerException(s); } } /** * Writes aSet
to aDataOutput
. * ** * This method is internal because its semantics (that is, its * ability to write any kind of
Set
) are different from * thewrite
XXX methods of the external *DataSerializer
. * * @throws IOException * A problem occurs while writing toout
* * @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 aSet
from aDataInput
. * * @throws IOException * A problem occurs while writing toout
* @throws ClassNotFoundException * The class of one of theHashSet
'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 aDataInput
given a * {@link CollectionCreator} for it. * * @throws IOException * A problem occurs while writing toout
* @throws ClassNotFoundException * The class of one of theSet
's elements cannot be * found. * * @see #writeSet * * @since 7.0 */ @SuppressWarnings({ "unchecked", "rawtypes" }) public staticC 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 aDataInput
into the given * non-null collection. Returns true if collection read is non-null else * returns false. * * @throws IOException * A problem occurs while reading fromin
* @throws ClassNotFoundException * The class of one of theSet
's elements cannot be * found. * * @see #writeSet */ public staticboolean 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; i DataOutput TimeUnit
to aDataOutput
. * * @throws IOException * A problem occurs while writing toout
* * @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 aTimeUnit
from aDataInput
. * * @throws IOException * A problem occurs while writing toout
* * @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 ofchar
s to a *DataOutput
. * * @throws IOException * A problem occurs while writing toout
* * @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 ofbyte
s from a *DataInput
. * * @throws IOException * A problem occurs while writing toout
* * @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 ofString
from a *DataInput
given the header byte already being read. * The return value may benull
. * * @throws IOException * A problem occurs while reading fromin
* * @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 finalT 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 DataSerializer
s that have not * been registered. Using this marker object allows us to * asynchronously sendDataSerializer
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 forDataSerializer
s that have not * been registered. Using this marker object allows us to * asynchronously sendDataSerializer
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, thennull
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 forDataSerializer
s that is in the process * of being registered. * It is possible for getSerializer to returnnull
* * @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, thennull
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 newDataSerializer
being * registered. */ public static final class RegistrationMessage extends PooledDistributionMessage { /** The id of theDataSerializer
that was * registered * since 5.7 an int instead of a byte */ private int id; /** The eventId of theDataSerializer
that was * registered */ protected EventID eventId; /** The name of theDataSerializer
class */ private String className; /** The versions in which this message was modified */ private static final Version[] dsfidVersions = new Version[]{}; /** * Constructor forDataSerializable
*/ public RegistrationMessage() { } /** * Creates a newRegistrationMessage
that broadcasts * that the givenDataSerializer
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 newInstantiator
is {@linkplain * Instantiator#register(Instantiator) registered}. */ public void newInstantiator(Instantiator instantiator); /** * Invoked when a newDataSerializer
is {@linkplain * DataSerializer#register(Class) registered}. */ public void newDataSerializer(DataSerializer ds); } /** * AnObjectInputStream
whose {@link #resolveClass} * method loads classes from the current context class loader. */ private static class DSObjectInputStream extends ObjectInputStream { /** * Creates a newDSObjectInputStream
that delegates * its behavior to a givenInputStream
. */ 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); } } } // /** // * ADataOutput
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 newDSDataOutput
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(); } } }