You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ud...@apache.org on 2018/12/07 17:00:24 UTC
[geode] 01/02: Revert "GEODE-5705: Improve basicReadObject to use
switch statement rather than if statements."
This is an automated email from the ASF dual-hosted git repository.
udo pushed a commit to branch feature/GEODE-5705
in repository https://gitbox.apache.org/repos/asf/geode.git
commit 6b7827305df6db2701f105e7157dcb4b22434622
Author: Udo Kohlmeyer <uk...@gmail.com>
AuthorDate: Thu Dec 6 13:05:01 2018 -0800
Revert "GEODE-5705: Improve basicReadObject to use switch statement rather than if statements."
This reverts commit c699e46e
---
.../main/java/org/apache/geode/DataSerializer.java | 3 +-
.../geode/internal/InternalDataSerializer.java | 1620 ++++++++++----------
.../apache/geode/internal/util/DscodeHelper.java | 38 -
.../java/org/apache/geode/internal/DSCODETest.java | 18 -
4 files changed, 853 insertions(+), 826 deletions(-)
diff --git a/geode-core/src/main/java/org/apache/geode/DataSerializer.java b/geode-core/src/main/java/org/apache/geode/DataSerializer.java
index 430e2f9..45a757a 100644
--- a/geode-core/src/main/java/org/apache/geode/DataSerializer.java
+++ b/geode-core/src/main/java/org/apache/geode/DataSerializer.java
@@ -1481,7 +1481,8 @@ public abstract class DataSerializer {
* @since GemFire 5.7
*/
public static void writeCharArray(char[] array, DataOutput out) throws IOException {
- InternalDataSerializer.writeCharArray(array, out);
+
+ InternalDataSerializer.writeCharArray(array, array != null ? array.length : -1, out);
}
/**
diff --git a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
index 66a9754..72a1bc0 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/InternalDataSerializer.java
@@ -106,7 +106,6 @@ import org.apache.geode.internal.lang.ClassUtils;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.logging.log4j.LocalizedMessage;
import org.apache.geode.internal.logging.log4j.LogMarker;
-import org.apache.geode.internal.util.DscodeHelper;
import org.apache.geode.internal.util.concurrent.CopyOnWriteHashMap;
import org.apache.geode.pdx.NonPortableClassException;
import org.apache.geode.pdx.PdxInstance;
@@ -132,22 +131,15 @@ import org.apache.geode.pdx.internal.TypeRegistry;
* @since GemFire 3.5
*/
public abstract class InternalDataSerializer extends DataSerializer {
- // array is null
- public static final byte NULL_ARRAY = -1;
- /**
- * array len encoded as int in next 4 bytes
- *
- * @since GemFire 5.7
- */
- public static final byte INT_ARRAY_LEN = -3;
- public static final boolean LOAD_CLASS_EACH_TIME =
- Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "loadClassOnEveryDeserialization");
private static final Logger logger = LogService.getLogger();
+
/**
* Maps Class names to their DataSerializer. This is used to find a DataSerializer during
* serialization.
*/
private static final Map<String, DataSerializer> classesToSerializers = new ConcurrentHashMap<>();
+
+
/**
* This list contains classes that Geode's classes subclass, such as antlr AST classes which are
* used by our Object Query Language. It also contains certain classes that are DataSerializable
@@ -199,80 +191,22 @@ public abstract class InternalDataSerializer extends DataSerializer {
// geode-modules
+ ";org.apache.geode.modules.util.SessionCustomExpiry" + ";";
- private static final String serializationVersionTxt =
- System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "serializationVersion");
- /**
- * Change this constant to be the last one in SERIALIZATION_VERSION
- */
- private static final SERIALIZATION_VERSION latestVersion = SERIALIZATION_VERSION.v662;
- private static final SERIALIZATION_VERSION serializationVersion = calculateSerializationVersion();
- /**
- * Maps the id of a serializer to its {@code DataSerializer}.
- */
- private static final ConcurrentMap/* <Integer, DataSerializer|Marker> */ idsToSerializers =
- new ConcurrentHashMap();
- /**
- * 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<String, SerializerAttributesHolder> 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<Integer, SerializerAttributesHolder> 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<String, SerializerAttributesHolder> supportedClassesToHolders =
- new ConcurrentHashMap<>();
- private static final Object listenersSync = new Object();
- 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;
- private static final ConcurrentMap dsfidToClassMap =
- logger.isTraceEnabled(LogMarker.SERIALIZER_WRITE_DSFID_VERBOSE) ? new ConcurrentHashMap()
- : null;
- /**
- * array len encoded as unsigned short in next 2 bytes
- *
- * @since GemFire 5.7
- */
- private static final byte SHORT_ARRAY_LEN = -2;
- private static final int MAX_BYTE_ARRAY_LEN = (byte) -4 & 0xFF;
- private static final ThreadLocal<Boolean> pdxSerializationInProgress = new ThreadLocal<>();
- // Variable Length long encoded as int in next 4 bytes
- private static final byte INT_VL = 126;
- // Variable Length long encoded as long in next 8 bytes
- private static final byte LONG_VL = 127;
- private static final int MAX_BYTE_VL = 125;
- private static final CopyOnWriteHashMap<String, WeakReference<Class<?>>> classCache =
- LOAD_CLASS_EACH_TIME ? null : new CopyOnWriteHashMap<>();
- private static final Object cacheAccessLock = new Object();
+
+
private static InputStreamFilter defaultSerializationFilter = new EmptyInputStreamFilter();
+
/**
* A deserialization filter for ObjectInputStreams
*/
private static InputStreamFilter serializationFilter = defaultSerializationFilter;
+
+ private static final String serializationVersionTxt =
+ System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "serializationVersion");
+
/**
* support for old GemFire clients and WAN sites - needed to enable moving from GemFire to Geode
*/
private static OldClientSupportService oldClientSupportService;
- /**
- * {@code RegistrationListener}s that receive callbacks when {@code DataSerializer}s and {@code
- * Instantiator}s are registered. Note: copy-on-write access used for this set
- */
- private static volatile Set listeners = new HashSet();
- private static DataSerializer dvddeserializer;
-
- static {
- initializeWellKnownSerializers();
- }
/**
* For backward compatibility we must swizzle the package of some classes that had to be moved
@@ -347,6 +281,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
serializationFilter = defaultSerializationFilter;
}
+
/**
* {@link DistributedSystemService}s that need to acceptlist Serializable objects can use this to
* read them from a file and then return them via
@@ -376,6 +311,25 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
+
+ /**
+ * Any time new serialization format is added then a new enum needs to be added here.
+ *
+ * @since GemFire 6.6.2
+ */
+ private enum SERIALIZATION_VERSION {
+ vINVALID,
+ // includes 6.6.0.x and 6.6.1.x. Note that no serialization changes were made in 6.6 until 6.6.2
+ v660,
+ // 6.6.2.x or later NOTE if you add a new constant make sure and update "latestVersion".
+ v662
+ }
+
+ /**
+ * 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.isEmpty()) {
return latestVersion;
@@ -389,6 +343,8 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+ private static final SERIALIZATION_VERSION serializationVersion = calculateSerializationVersion();
+
public static boolean is662SerializationEnabled() {
return serializationVersion.ordinal() >= SERIALIZATION_VERSION.v662.ordinal();
}
@@ -402,6 +358,10 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+ 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
@@ -809,6 +769,42 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
/**
+ * Maps the id of a serializer to its {@code DataSerializer}.
+ */
+ private static final ConcurrentMap/* <Integer, DataSerializer|Marker> */ idsToSerializers =
+ new ConcurrentHashMap();
+
+ /**
+ * 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<String, SerializerAttributesHolder> 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<Integer, SerializerAttributesHolder> 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<String, SerializerAttributesHolder> supportedClassesToHolders =
+ new ConcurrentHashMap<>();
+
+ /**
+ * {@code RegistrationListener}s that receive callbacks when {@code DataSerializer}s and {@code
+ * Instantiator}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();
+
+ /**
* Convert the given unsigned byte to an int. The returned value will be in the range [0..255]
* inclusive
*/
@@ -816,14 +812,14 @@ public abstract class InternalDataSerializer extends DataSerializer {
return ub & 0xFF;
}
- public static OldClientSupportService getOldClientSupportService() {
- return oldClientSupportService;
- }
-
public static void setOldClientSupportService(final OldClientSupportService svc) {
oldClientSupportService = svc;
}
+ public static OldClientSupportService getOldClientSupportService() {
+ return oldClientSupportService;
+ }
+
/**
* Instantiates an instance of {@code DataSerializer}
*
@@ -1101,6 +1097,53 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+ /**
+ * A SerializerAttributesHolder holds information required to load a DataSerializer and exists to
+ * allow client/server connections to be created more quickly than they would if the
+ * DataSerializer information downloaded from the server were used to immediately load the
+ * corresponding classes.
+ */
+ public static class SerializerAttributesHolder {
+ private String className = "";
+ private EventID eventId = null;
+ private ClientProxyMembershipID proxyId = null;
+ private int id = 0;
+
+ SerializerAttributesHolder() {}
+
+ 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);
}
@@ -1641,6 +1684,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+
public static boolean autoSerialized(Object o, DataOutput out) throws IOException {
AutoSerializableManager asm = TypeRegistry.getAutoSerializableManager();
if (asm != null) {
@@ -1745,7 +1789,8 @@ public abstract class InternalDataSerializer extends DataSerializer {
*/
public static void checkOut(DataOutput out) {
if (out == null) {
- throw new NullPointerException("Null DataOutput");
+ String s = "Null DataOutput";
+ throw new NullPointerException(s);
}
}
@@ -1756,7 +1801,8 @@ public abstract class InternalDataSerializer extends DataSerializer {
*/
public static void checkIn(DataInput in) {
if (in == null) {
- throw new NullPointerException("Null DataInput");
+ String s = "Null DataInput";
+ throw new NullPointerException(s);
}
}
@@ -1773,22 +1819,20 @@ public abstract class InternalDataSerializer extends DataSerializer {
public static void writeSet(Collection<?> set, DataOutput out) throws IOException {
checkOut(out);
- if (set != null) {
- final int size = set.size();
- writeArrayLength(size, out);
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger
- .trace(LogMarker.SERIALIZER_VERBOSE, "Writing HashSet with {} elements: {}", size, set);
- }
+ int size;
+ if (set == null) {
+ size = -1;
+ } else {
+ size = set.size();
+ }
+ writeArrayLength(size, out);
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing HashSet with {} elements: {}", size, set);
+ }
+ if (size > 0) {
for (Object element : set) {
writeObject(element, out);
}
- } else {
- writeArrayLength(-1, out);
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger
- .trace(LogMarker.SERIALIZER_VERBOSE, "Writing HashSet with {} elements: {}", -1, set);
- }
}
}
@@ -1919,6 +1963,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+
/**
* Writes the type code for a primitive type Class to {@code DataOutput}.
*/
@@ -1950,37 +1995,46 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
- public static Class decodePrimitiveClass(byte typeCode) throws IOException {
- DSCODE dscode = DscodeHelper.toDSCODE(typeCode);
- switch (dscode) {
- 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(typeCode));
+ public static Class decodePrimitiveClass(byte typeCode) {
+ if (typeCode == DSCODE.BOOLEAN_TYPE.toByte()) {
+ return Boolean.TYPE;
}
-
+ if (typeCode == DSCODE.CHARACTER_TYPE.toByte()) {
+ return Character.TYPE;
+ }
+ if (typeCode == DSCODE.BYTE_TYPE.toByte()) {
+ return Byte.TYPE;
+ }
+ if (typeCode == DSCODE.SHORT_TYPE.toByte()) {
+ return Short.TYPE;
+ }
+ if (typeCode == DSCODE.INTEGER_TYPE.toByte()) {
+ return Integer.TYPE;
+ }
+ if (typeCode == DSCODE.LONG_TYPE.toByte()) {
+ return Long.TYPE;
+ }
+ if (typeCode == DSCODE.FLOAT_TYPE.toByte()) {
+ return Float.TYPE;
+ }
+ if (typeCode == DSCODE.DOUBLE_TYPE.toByte()) {
+ return Double.TYPE;
+ }
+ if (typeCode == DSCODE.VOID_TYPE.toByte()) {
+ return Void.TYPE;
+ }
+ if (typeCode == DSCODE.NULL.toByte()) {
+ return null;
+ }
+ throw new InternalGemFireError(
+ LocalizedStrings.InternalDataSerializer_UNEXPECTED_TYPECODE_0.toLocalizedString(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;
+
/**
* Reads a {@code TimeUnit} from a {@code DataInput}.
*
@@ -2092,6 +2146,10 @@ public abstract class InternalDataSerializer extends DataSerializer {
return result;
}
+ private static final ConcurrentMap dsfidToClassMap =
+ logger.isTraceEnabled(LogMarker.SERIALIZER_WRITE_DSFID_VERBOSE) ? new ConcurrentHashMap()
+ : null;
+
public static void writeUserDataSerializableHeader(int classId, DataOutput out)
throws IOException {
if (classId <= Byte.MAX_VALUE && classId >= Byte.MIN_VALUE) {
@@ -2113,19 +2171,19 @@ public abstract class InternalDataSerializer extends DataSerializer {
* @see DataSerializer#readCharArray
* @since GemFire 6.6
*/
- public static void writeCharArray(char[] array, DataOutput out) throws IOException {
+ public static void writeCharArray(char[] array, int length, DataOutput out) throws IOException {
checkOut(out);
if (array == null) {
- writeArrayLength(-1, out);
- } else {
- final int length = array.length;
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing char array of length {}", length);
- }
- writeArrayLength(length, out);
- for (char character : array) {
- out.writeChar(character);
+ length = -1;
+ }
+ writeArrayLength(length, out);
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "Writing char array of length {}", length);
+ }
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ out.writeChar(array[i]);
}
}
}
@@ -2364,7 +2422,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
boolean invoked = false;
Version v = InternalDataSerializer.getVersionForDataStreamOrNull(out);
- if (Version.CURRENT != v && v != null) {
+ if (v != null && v != Version.CURRENT) {
// get versions where DataOutput was upgraded
Version[] versions = null;
if (ds instanceof SerializationVersions) {
@@ -2373,7 +2431,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
// check if the version of the peer or diskstore is different and
// there has been a change in the message
- if (versions != null) {
+ if (versions != null && versions.length > 0) {
for (Version version : versions) {
// if peer version is less than the greatest upgraded version
if (v.compareTo(version) < 0) {
@@ -2437,7 +2495,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
try {
boolean invoked = false;
Version v = InternalDataSerializer.getVersionForDataStreamOrNull(in);
- if (Version.CURRENT != v && v != null) {
+ if (v != null && v != Version.CURRENT) {
// get versions where DataOutput was upgraded
Version[] versions = null;
if (ds instanceof SerializationVersions) {
@@ -2446,7 +2504,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
// check if the version of the peer or diskstore is different and
// there has been a change in the message
- if (versions != null) {
+ if (versions != null && versions.length > 0) {
for (Version version : versions) {
// if peer version is less than the greatest upgraded version
if (v.compareTo(version) < 0) {
@@ -2476,6 +2534,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+
private static Object readDataSerializable(final DataInput in)
throws IOException, ClassNotFoundException {
Class c = readClass(in);
@@ -2583,19 +2642,38 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
- 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);
- }
- }
+ // array is null
+ public static final byte NULL_ARRAY = -1;
+
+ /**
+ * array len encoded as unsigned short in next 2 bytes
+ *
+ * @since GemFire 5.7
+ */
+ private static final byte SHORT_ARRAY_LEN = -2;
+
+ /**
+ * array len encoded as int in next 4 bytes
+ *
+ * @since GemFire 5.7
+ */
+ public static final byte INT_ARRAY_LEN = -3;
+
+ private static final int MAX_BYTE_ARRAY_LEN = (byte) -4 & 0xFF;
+
+ 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();
@@ -2605,9 +2683,9 @@ public abstract class InternalDataSerializer extends DataSerializer {
int result = ubyteToInt(code);
if (result > MAX_BYTE_ARRAY_LEN) {
if (code == SHORT_ARRAY_LEN) {
- return in.readUnsignedShort();
+ result = in.readUnsignedShort();
} else if (code == INT_ARRAY_LEN) {
- return in.readInt();
+ result = in.readInt();
} else {
throw new IllegalStateException("unexpected array length code=" + code);
}
@@ -2616,46 +2694,61 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
- private static Object readDSFID(final DataInput in, DSCODE dscode)
- throws IOException, ClassNotFoundException {
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "readDSFID: header={}", dscode);
- }
- switch (dscode) {
- case DS_FIXED_ID_BYTE:
- return DSFIDFactory.create(in.readByte(), in);
- case DS_FIXED_ID_SHORT:
- return DSFIDFactory.create(in.readShort(), in);
- case DS_NO_FIXED_ID:
- return readDataSerializableFixedID(in);
- case DS_FIXED_ID_INT:
- return DSFIDFactory.create(in.readInt(), in);
- default:
- throw new IllegalStateException("unexpected byte: " + dscode + " while reading dsfid");
+ /**
+ * Serializes a list of Integers. The argument may be null. Deserialize with
+ * readListOfIntegers().
+ *
+ * TODO: writeListOfIntegers is unused
+ */
+ public void writeListOfIntegers(List<Integer> list, DataOutput out) throws IOException {
+ int size;
+ if (list == null) {
+ size = -1;
+ } else {
+ size = list.size();
+ }
+ InternalDataSerializer.writeArrayLength(size, out);
+ if (size > 0) {
+ for (int i = 0; i < size; i++) {
+ out.writeInt(list.get(i));
+ }
}
}
public static Object readDSFID(final DataInput in) throws IOException, ClassNotFoundException {
checkIn(in);
- return readDSFID(in, DscodeHelper.toDSCODE(in.readByte()));
- }
-
- private static int readDSFIDHeader(final DataInput in, DSCODE dscode) throws IOException {
- switch (dscode) {
- case DS_FIXED_ID_BYTE:
- return in.readByte();
- case DS_FIXED_ID_SHORT:
- return in.readShort();
- case DS_FIXED_ID_INT:
- return in.readInt();
- default:
- throw new IllegalStateException("unexpected byte: " + dscode + " while reading dsfid");
+ byte header = in.readByte();
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "readDSFID: header={}", header);
+ }
+ if (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) {
+ return DSFIDFactory.create(in.readByte(), in);
+ } else if (header == DSCODE.DS_FIXED_ID_SHORT.toByte()) {
+ return DSFIDFactory.create(in.readShort(), in);
+ } else if (header == DSCODE.DS_NO_FIXED_ID.toByte()) {
+ return readDataSerializableFixedID(in);
+ } else if (header == DSCODE.DS_FIXED_ID_INT.toByte()) {
+ return DSFIDFactory.create(in.readInt(), in);
+ } else {
+ throw new IllegalStateException("unexpected byte: " + header + " while reading dsfid");
}
}
public static int readDSFIDHeader(final DataInput in) throws IOException {
checkIn(in);
- return readDSFIDHeader(in, DscodeHelper.toDSCODE(in.readByte()));
+ byte header = in.readByte();
+ if (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) {
+ return in.readByte();
+ } else if (header == DSCODE.DS_FIXED_ID_SHORT.toByte()) {
+ return in.readShort();
+ } else if (header == DSCODE.DS_NO_FIXED_ID.toByte()) {
+ // is that correct??
+ return Integer.MAX_VALUE;
+ } else if (header == DSCODE.DS_FIXED_ID_INT.toByte()) {
+ return in.readInt();
+ } else {
+ throw new IllegalStateException("unexpected byte: " + header + " while reading dsfid");
+ }
}
/**
@@ -2665,59 +2758,50 @@ public abstract class InternalDataSerializer extends DataSerializer {
* @throws IOException A problem occurs while reading from {@code in}
* @since GemFire 5.7
*/
- private static String readString(DataInput in, DSCODE dscode) throws IOException {
- switch (dscode) {
- case STRING_BYTES:
- return readStringBytesFromDataInput(in, in.readUnsignedShort());
- case STRING:
- return readStringUTFFromDataInput(in);
- case NULL_STRING: {
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading NULL_STRING");
- }
- return null;
+ public static String readString(DataInput in, byte header) throws IOException {
+ if (header == DSCODE.STRING_BYTES.toByte()) {
+ int len = in.readUnsignedShort();
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading STRING_BYTES of len={}", len);
}
- case HUGE_STRING_BYTES:
- return readStringBytesFromDataInput(in, in.readInt());
- case HUGE_STRING:
- return readHugeStringFromDataInput(in);
- default:
- throw new IOException("Unknown String header " + dscode);
- }
- }
-
- private static String readHugeStringFromDataInput(DataInput in) throws IOException {
- int len = in.readInt();
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "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);
- }
-
- private static String readStringUTFFromDataInput(DataInput in) throws IOException {
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading utf STRING");
- }
- return in.readUTF();
- }
-
- private static String readStringBytesFromDataInput(DataInput dataInput, int len)
- throws IOException {
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "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.toByte()) {
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading utf STRING");
+ }
+ return in.readUTF();
+ } else if (header == DSCODE.NULL_STRING.toByte()) {
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "Reading NULL_STRING");
+ }
+ return null;
+ } else if (header == DSCODE.HUGE_STRING_BYTES.toByte()) {
+ int len = in.readInt();
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "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.toByte()) {
+ int len = in.readInt();
+ if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "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);
}
- byte[] buf = new byte[len];
- dataInput.readFully(buf, 0, len);
- return new String(buf, 0); // intentionally using deprecated constructor
}
- public static String readString(DataInput in, byte header) throws IOException {
- return readString(in, DscodeHelper.toDSCODE(header));
- }
+ private static DataSerializer dvddeserializer;
// TODO: registerDVDDeserializer is unused
public static void registerDVDDeserializer(DataSerializer dvddeslzr) {
@@ -2750,212 +2834,260 @@ public abstract class InternalDataSerializer extends DataSerializer {
// Read the header byte
byte header = in.readByte();
- DSCODE headerDSCode = DscodeHelper.toDSCODE(header);
-
if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
logger.trace(LogMarker.SERIALIZER_VERBOSE, "basicReadObject: header={}", header);
}
-
- if (headerDSCode == null) {
- throw new IOException("Unknown header byte: " + header);
- }
-
- switch (headerDSCode) {
- 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 NULL:
- return null;
- case NULL_STRING:
- return null;
- case STRING:
- return readStringUTFFromDataInput(in);
- case HUGE_STRING:
- return readHugeStringFromDataInput(in);
- case STRING_BYTES:
- return readStringBytesFromDataInput(in, in.readUnsignedShort());
- case HUGE_STRING_BYTES:
- return readStringBytesFromDataInput(in, in.readInt());
- 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:
- return readSerializable(in);
- 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:
- throw new IOException("Unknown header byte: " + header);
+ if (header == DSCODE.DS_FIXED_ID_BYTE.toByte()) {
+ return DSFIDFactory.create(in.readByte(), in);
}
-
- }
-
- private static Serializable readSerializable(DataInput in)
- throws IOException, ClassNotFoundException {
- final boolean isDebugEnabled_SERIALIZER = logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE);
- Serializable serializableResult;
- if (in instanceof DSObjectInputStream) {
- serializableResult = (Serializable) ((DSObjectInputStream) in).readObject();
- } else {
- InputStream stream;
- if (in instanceof InputStream) {
- stream = (InputStream) in;
+ if (header == DSCODE.DS_FIXED_ID_SHORT.toByte()) {
+ return DSFIDFactory.create(in.readShort(), in);
+ }
+ if (header == DSCODE.DS_FIXED_ID_INT.toByte()) {
+ return DSFIDFactory.create(in.readInt(), in);
+ }
+ if (header == DSCODE.DS_NO_FIXED_ID.toByte()) {
+ return readDataSerializableFixedID(in);
+ }
+ if (header == DSCODE.NULL.toByte()) {
+ return null;
+ }
+ if (header == DSCODE.NULL_STRING.toByte() || header == DSCODE.STRING.toByte()
+ || header == DSCODE.HUGE_STRING.toByte() || header == DSCODE.STRING_BYTES.toByte()
+ || header == DSCODE.HUGE_STRING_BYTES.toByte()) {
+ return readString(in, header);
+ }
+ if (header == DSCODE.CLASS.toByte()) {
+ return readClass(in);
+ }
+ if (header == DSCODE.DATE.toByte()) {
+ return readDate(in);
+ }
+ if (header == DSCODE.FILE.toByte()) {
+ return readFile(in);
+ }
+ if (header == DSCODE.INET_ADDRESS.toByte()) {
+ return readInetAddress(in);
+ }
+ if (header == DSCODE.BOOLEAN.toByte()) {
+ return readBoolean(in);
+ }
+ if (header == DSCODE.CHARACTER.toByte()) {
+ return readCharacter(in);
+ }
+ if (header == DSCODE.BYTE.toByte()) {
+ return readByte(in);
+ }
+ if (header == DSCODE.SHORT.toByte()) {
+ return readShort(in);
+ }
+ if (header == DSCODE.INTEGER.toByte()) {
+ return readInteger(in);
+ }
+ if (header == DSCODE.LONG.toByte()) {
+ return readLong(in);
+ }
+ if (header == DSCODE.FLOAT.toByte()) {
+ return readFloat(in);
+ }
+ if (header == DSCODE.DOUBLE.toByte()) {
+ return readDouble(in);
+ }
+ if (header == DSCODE.BYTE_ARRAY.toByte()) {
+ return readByteArray(in);
+ }
+ if (header == DSCODE.ARRAY_OF_BYTE_ARRAYS.toByte()) {
+ return readArrayOfByteArrays(in);
+ }
+ if (header == DSCODE.SHORT_ARRAY.toByte()) {
+ return readShortArray(in);
+ }
+ if (header == DSCODE.STRING_ARRAY.toByte()) {
+ return readStringArray(in);
+ }
+ if (header == DSCODE.INT_ARRAY.toByte()) {
+ return readIntArray(in);
+ }
+ if (header == DSCODE.LONG_ARRAY.toByte()) {
+ return readLongArray(in);
+ }
+ if (header == DSCODE.FLOAT_ARRAY.toByte()) {
+ return readFloatArray(in);
+ }
+ if (header == DSCODE.DOUBLE_ARRAY.toByte()) {
+ return readDoubleArray(in);
+ }
+ if (header == DSCODE.BOOLEAN_ARRAY.toByte()) {
+ return readBooleanArray(in);
+ }
+ if (header == DSCODE.CHAR_ARRAY.toByte()) {
+ return readCharArray(in);
+ }
+ if (header == DSCODE.OBJECT_ARRAY.toByte()) {
+ return readObjectArray(in);
+ }
+ if (header == DSCODE.ARRAY_LIST.toByte()) {
+ return readArrayList(in);
+ }
+ if (header == DSCODE.LINKED_LIST.toByte()) {
+ return readLinkedList(in);
+ }
+ if (header == DSCODE.HASH_SET.toByte()) {
+ return readHashSet(in);
+ }
+ if (header == DSCODE.LINKED_HASH_SET.toByte()) {
+ return readLinkedHashSet(in);
+ }
+ if (header == DSCODE.HASH_MAP.toByte()) {
+ return readHashMap(in);
+ }
+ if (header == DSCODE.IDENTITY_HASH_MAP.toByte()) {
+ return readIdentityHashMap(in);
+ }
+ if (header == DSCODE.HASH_TABLE.toByte()) {
+ return readHashtable(in);
+ }
+ if (header == DSCODE.CONCURRENT_HASH_MAP.toByte()) {
+ return readConcurrentHashMap(in);
+ }
+ if (header == DSCODE.PROPERTIES.toByte()) {
+ return readProperties(in);
+ }
+ if (header == DSCODE.TIME_UNIT.toByte()) {
+ return readTimeUnit(in);
+ }
+ if (header == DSCODE.USER_CLASS.toByte()) {
+ return readUserObject(in, in.readByte());
+ }
+ if (header == DSCODE.USER_CLASS_2.toByte()) {
+ return readUserObject(in, in.readShort());
+ }
+ if (header == DSCODE.USER_CLASS_4.toByte()) {
+ return readUserObject(in, in.readInt());
+ }
+ if (header == DSCODE.VECTOR.toByte()) {
+ return readVector(in);
+ }
+ if (header == DSCODE.STACK.toByte()) {
+ return readStack(in);
+ }
+ if (header == DSCODE.TREE_MAP.toByte()) {
+ return readTreeMap(in);
+ }
+ if (header == DSCODE.TREE_SET.toByte()) {
+ return readTreeSet(in);
+ }
+ if (header == DSCODE.BOOLEAN_TYPE.toByte()) {
+ return Boolean.TYPE;
+ }
+ if (header == DSCODE.CHARACTER_TYPE.toByte()) {
+ return Character.TYPE;
+ }
+ if (header == DSCODE.BYTE_TYPE.toByte()) {
+ return Byte.TYPE;
+ }
+ if (header == DSCODE.SHORT_TYPE.toByte()) {
+ return Short.TYPE;
+ }
+ if (header == DSCODE.INTEGER_TYPE.toByte()) {
+ return Integer.TYPE;
+ }
+ if (header == DSCODE.LONG_TYPE.toByte()) {
+ return Long.TYPE;
+ }
+ if (header == DSCODE.FLOAT_TYPE.toByte()) {
+ return Float.TYPE;
+ }
+ if (header == DSCODE.DOUBLE_TYPE.toByte()) {
+ return Double.TYPE;
+ }
+ if (header == DSCODE.VOID_TYPE.toByte()) {
+ return Void.TYPE;
+ }
+ if (header == DSCODE.USER_DATA_SERIALIZABLE.toByte()) {
+ return readUserDataSerializable(in, in.readByte());
+ }
+ if (header == DSCODE.USER_DATA_SERIALIZABLE_2.toByte()) {
+ return readUserDataSerializable(in, in.readShort());
+ }
+ if (header == DSCODE.USER_DATA_SERIALIZABLE_4.toByte()) {
+ return readUserDataSerializable(in, in.readInt());
+ }
+ if (header == DSCODE.DATA_SERIALIZABLE.toByte()) {
+ return readDataSerializable(in);
+ }
+ if (header == DSCODE.SERIALIZABLE.toByte()) {
+ final boolean isDebugEnabled_SERIALIZER = logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE);
+ Object serializableResult;
+ if (in instanceof DSObjectInputStream) {
+ serializableResult = ((DSObjectInputStream) in).readObject();
} else {
- stream = new InputStream() {
- @Override
- public int read() throws IOException {
- try {
- return in.readUnsignedByte(); // fix for bug 47249
- } catch (EOFException ignored) {
- return -1;
+ 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 ignored) {
+ return -1;
+ }
}
- }
- };
- }
+ };
+ }
- ObjectInput ois = new DSObjectInputStream(stream);
- serializationFilter.setFilterOn((ObjectInputStream) ois);
- if (stream instanceof VersionedDataStream) {
- Version v = ((VersionedDataStream) stream).getVersion();
- if (Version.CURRENT != v && v != null) {
- ois = new VersionedObjectInput(ois, v);
+ ObjectInput ois = new DSObjectInputStream(stream);
+ serializationFilter.setFilterOn((ObjectInputStream) ois);
+ if (stream instanceof VersionedDataStream) {
+ Version v = ((VersionedDataStream) stream).getVersion();
+ if (v != null && v != Version.CURRENT) {
+ ois = new VersionedObjectInput(ois, v);
+ }
}
- }
- serializableResult = (Serializable) ois.readObject();
+ serializableResult = ois.readObject();
+ if (isDebugEnabled_SERIALIZER) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Serializable object: {}",
+ serializableResult);
+ }
+ }
if (isDebugEnabled_SERIALIZER) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Serializable object: {}",
- serializableResult);
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "deserialized instanceof {}",
+ serializableResult.getClass());
}
+ return serializableResult;
}
- if (isDebugEnabled_SERIALIZER) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "deserialized instanceof {}",
- serializableResult.getClass());
+ if (header == DSCODE.PDX.toByte()) {
+ return readPdxSerializable(in);
+ }
+ if (header == DSCODE.PDX_ENUM.toByte()) {
+ return readPdxEnum(in);
+ }
+ if (header == DSCODE.GEMFIRE_ENUM.toByte()) {
+ return readGemFireEnum(in);
}
- return serializableResult;
+ if (header == DSCODE.PDX_INLINE_ENUM.toByte()) {
+ return readPdxInlineEnum(in);
+ }
+ if (header == DSCODE.BIG_INTEGER.toByte()) {
+ return readBigInteger(in);
+ }
+ if (header == DSCODE.BIG_DECIMAL.toByte()) {
+ return readBigDecimal(in);
+ }
+ if (header == DSCODE.UUID.toByte()) {
+ return readUUID(in);
+ }
+ if (header == DSCODE.TIMESTAMP.toByte()) {
+ return readTimestamp(in);
+ }
+
+ String s = "Unknown header byte: " + header;
+ throw new IOException(s);
}
private static Object readUserDataSerializable(final DataInput in, int classId)
@@ -2991,13 +3123,19 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
}
+ private static final ThreadLocal<Boolean> pdxSerializationInProgress = new ThreadLocal<>();
+
public static boolean isPdxSerializationInProgress() {
Boolean v = pdxSerializationInProgress.get();
return v != null && v;
}
- public static void setPdxSerializationInProgress(boolean inProgress) {
- pdxSerializationInProgress.set(inProgress);
+ public static void setPdxSerializationInProgress(boolean v) {
+ if (v) {
+ pdxSerializationInProgress.set(true);
+ } else {
+ pdxSerializationInProgress.set(false);
+ }
}
public static boolean writePdx(DataOutput out, InternalCache internalCache, Object pdx,
@@ -3189,347 +3327,35 @@ public abstract class InternalDataSerializer extends DataSerializer {
return supportedClassesToHolders;
}
- public static void writeObjectArray(Object[] array, DataOutput out, boolean ensureCompatibility)
- throws IOException {
- InternalDataSerializer.checkOut(out);
- int length = -1;
- if (array != null) {
- length = array.length;
- }
- InternalDataSerializer.writeArrayLength(length, out);
- if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
- logger.trace(LogMarker.SERIALIZER_VERBOSE, "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);
- }
- }
- }
-
/**
- * 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.
+ * A marker object for {@code DataSerializer}s that have not been registered. Using this marker
+ * object allows us to asynchronously send {@code DataSerializer} registration updates. If the
+ * serialized bytes arrive at a VM before the registration message does, the deserializer will
+ * wait an amount of time for the registration message to arrive.
*/
- 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;
- }
- }
- }
-
- /**
- * 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 represented 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 represented 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
- */
- private 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
- */
- private 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 ignored) {
- return 0;
- }
- return out.size();
- }
-
- public static Class<?> getCachedClass(String p_className) throws ClassNotFoundException {
- String className = processIncomingClassName(p_className);
- 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<Class<?>> 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 DeployedJar
- classCache.clear();
- }
- }
-
- /**
- * Serializes a list of Integers. The argument may be null. Deserialize with
- * readListOfIntegers().
- *
- * TODO: writeListOfIntegers is unused
- */
- public void writeListOfIntegers(List<Integer> list, DataOutput out) throws IOException {
- if (list != null) {
- InternalDataSerializer.writeArrayLength(list.size(), out);
- for (Integer entry : list) {
- out.writeInt(entry);
- }
- } else {
- InternalDataSerializer.writeArrayLength(-1, out);
- }
- }
-
- /**
- * Any time new serialization format is added then a new enum needs to be added here.
- *
- * @since GemFire 6.6.2
- */
- private enum SERIALIZATION_VERSION {
- vINVALID,
- // includes 6.6.0.x and 6.6.1.x. Note that no serialization changes were made in 6.6 until 6.6.2
- v660,
- // 6.6.2.x or later NOTE if you add a new constant make sure and update "latestVersion".
- v662
- }
-
- /**
- * A listener whose listener methods are invoked when {@link DataSerializer}s and {@link
- * Instantiator}s are registered. This is part of the fix for bug 31422.
- *
- * @see InternalDataSerializer#addRegistrationListener
- * @see InternalDataSerializer#removeRegistrationListener
- */
- public interface RegistrationListener {
-
- /**
- * Invoked when a new {@code Instantiator} is {@linkplain Instantiator#register(Instantiator)
- * registered}.
- */
- void newInstantiator(Instantiator instantiator);
-
- /**
- * Invoked when a new {@code DataSerializer} is {@linkplain DataSerializer#register(Class)
- * registered}.
- */
- void newDataSerializer(DataSerializer ds);
- }
-
- /**
- * A SerializerAttributesHolder holds information required to load a DataSerializer and exists to
- * allow client/server connections to be created more quickly than they would if the
- * DataSerializer information downloaded from the server were used to immediately load the
- * corresponding classes.
- */
- public static class SerializerAttributesHolder {
- private String className = "";
- private EventID eventId = null;
- private ClientProxyMembershipID proxyId = null;
- private int id = 0;
-
- SerializerAttributesHolder() {}
-
- 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 + ']';
- }
- }
-
- /**
- * A marker object for {@code DataSerializer}s that have not been registered. Using this marker
- * object allows us to asynchronously send {@code DataSerializer} registration updates. If the
- * serialized bytes arrive at a VM before the registration message does, the deserializer will
- * wait an amount of time for the registration message to arrive.
- */
- abstract static class Marker {
- /**
- * The DataSerializer that is filled in upon registration
- */
- protected DataSerializer serializer = null;
-
- /**
- * set to true once setSerializer is called.
- */
- 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();
- }
+ abstract static class Marker {
+ /**
+ * The DataSerializer that is filled in upon registration
+ */
+ protected DataSerializer serializer = null;
+
+ /**
+ * set to true once setSerializer is called.
+ */
+ 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();
+ }
}
}
@@ -3626,23 +3452,26 @@ public abstract class InternalDataSerializer extends DataSerializer {
*/
public static class RegistrationMessage extends SerialDistributionMessage {
/**
- * The versions in which this message was modified
+ * The id of the {@code DataSerializer} that was registered since 5.7 an int instead of a byte
*/
- private static final Version[] dsfidVersions = new Version[] {};
+ private int id;
+
/**
* The eventId of the {@code DataSerializer} that was registered
*/
protected EventID eventId;
- /**
- * The id of the {@code DataSerializer} that was registered since 5.7 an int instead of a byte
- */
- private int id;
+
/**
* The name of the {@code DataSerializer} class
*/
private String className;
/**
+ * The versions in which this message was modified
+ */
+ private static final Version[] dsfidVersions = new Version[] {};
+
+ /**
* Constructor for {@code DataSerializable}
*/
public RegistrationMessage() {}
@@ -3763,6 +3592,28 @@ public abstract class InternalDataSerializer extends DataSerializer {
}
/**
+ * A listener whose listener methods are invoked when {@link DataSerializer}s and {@link
+ * Instantiator}s are registered. This is part of the fix for bug 31422.
+ *
+ * @see InternalDataSerializer#addRegistrationListener
+ * @see InternalDataSerializer#removeRegistrationListener
+ */
+ public interface RegistrationListener {
+
+ /**
+ * Invoked when a new {@code Instantiator} is {@linkplain Instantiator#register(Instantiator)
+ * registered}.
+ */
+ void newInstantiator(Instantiator instantiator);
+
+ /**
+ * Invoked when a new {@code DataSerializer} is {@linkplain DataSerializer#register(Class)
+ * registered}.
+ */
+ void newDataSerializer(DataSerializer ds);
+ }
+
+ /**
* An {@code ObjectInputStream} whose {@link #resolveClass} method loads classes from the current
* context class loader.
*/
@@ -3865,4 +3716,235 @@ public abstract class InternalDataSerializer extends DataSerializer {
protected abstract static 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 (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
+ logger.trace(LogMarker.SERIALIZER_VERBOSE, "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);
+ }
+ }
+ }
+
+ // Variable Length long encoded as int in next 4 bytes
+ private static final byte INT_VL = 126;
+
+ // Variable Length long encoded as long in next 8 bytes
+ private static final byte LONG_VL = 127;
+
+ 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;
+ }
+ }
+ }
+
+ /**
+ * 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 represented 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 represented 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
+ */
+ private 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
+ */
+ private 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 ignored) {
+ return 0;
+ }
+ return out.size();
+ }
+
+ public static final boolean LOAD_CLASS_EACH_TIME =
+ Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "loadClassOnEveryDeserialization");
+
+ private static final CopyOnWriteHashMap<String, WeakReference<Class<?>>> classCache =
+ LOAD_CLASS_EACH_TIME ? null : new CopyOnWriteHashMap<>();
+
+ private static final Object cacheAccessLock = new Object();
+
+ public static Class<?> getCachedClass(String p_className) throws ClassNotFoundException {
+ String className = processIncomingClassName(p_className);
+ 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<Class<?>> 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 DeployedJar
+ classCache.clear();
+ }
+ }
}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java b/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java
deleted file mode 100644
index 30a9f9b..0000000
--- a/geode-core/src/main/java/org/apache/geode/internal/util/DscodeHelper.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.util;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-import org.apache.geode.internal.DSCODE;
-
-public class DscodeHelper {
-
- private static final DSCODE[] dscodes = new DSCODE[128];
-
- static {
- Arrays.stream(DSCODE.values()).filter(dscode -> dscode.toByte() >= 0)
- .forEach(dscode -> dscodes[dscode.toByte()] = dscode);
- }
-
- public static DSCODE toDSCODE(final byte value) throws IOException {
- try {
- return dscodes[value];
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new IOException("Unknown header byte: " + value);
- }
- }
-}
diff --git a/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java b/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java
index 7240825..7bc7684 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/DSCODETest.java
@@ -15,18 +15,13 @@
package org.apache.geode.internal;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import java.io.IOException;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.apache.geode.internal.util.DscodeHelper;
import org.apache.geode.test.junit.categories.SerializationTest;
@Category({SerializationTest.class})
@@ -41,17 +36,4 @@ public class DSCODETest {
previouslySeen.add(integerValue);
}
}
-
- @Test
- public void testGetEnumFromByte() {
- Arrays.stream(DSCODE.values())
- .filter(dscode -> dscode != DSCODE.RESERVED_FOR_FUTURE_USE && dscode != DSCODE.ILLEGAL)
- .forEach(dscode -> {
- try {
- Assert.assertEquals(dscode, DscodeHelper.toDSCODE(dscode.toByte()));
- } catch (IOException e) {
- fail("No exception should have been caught, as the \"error\" codes are filtered out.");
- }
- });
- }
}