You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2017/04/14 15:27:34 UTC
[09/44] ignite git commit: IGNITE-4938: Moved OptimizedMarshaller to
private package. This closes #1793.
http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b5b8c3/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
new file mode 100644
index 0000000..f9a6df9
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
@@ -0,0 +1,551 @@
+/*
+ * 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.ignite.internal.marshaller.optimized;
+
+import java.io.IOException;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.marshaller.MarshallerContext;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
+
+import static org.apache.ignite.internal.MarshallerPlatformIds.JAVA_ID;
+
+/**
+ * Miscellaneous utility methods to facilitate {@link OptimizedMarshaller}.
+ */
+class OptimizedMarshallerUtils {
+ /** */
+ static final long HASH_SET_MAP_OFF;
+
+ /** */
+ static final byte JDK = -2;
+
+ /** */
+ static final byte HANDLE = -1;
+
+ /** */
+ static final byte NULL = 0;
+
+ /** */
+ static final byte BYTE = 1;
+
+ /** */
+ static final byte SHORT = 2;
+
+ /** */
+ static final byte INT = 3;
+
+ /** */
+ static final byte LONG = 4;
+
+ /** */
+ static final byte FLOAT = 5;
+
+ /** */
+ static final byte DOUBLE = 6;
+
+ /** */
+ static final byte CHAR = 7;
+
+ /** */
+ static final byte BOOLEAN = 8;
+
+ /** */
+ static final byte BYTE_ARR = 9;
+
+ /** */
+ static final byte SHORT_ARR = 10;
+
+ /** */
+ static final byte INT_ARR = 11;
+
+ /** */
+ static final byte LONG_ARR = 12;
+
+ /** */
+ static final byte FLOAT_ARR = 13;
+
+ /** */
+ static final byte DOUBLE_ARR = 14;
+
+ /** */
+ static final byte CHAR_ARR = 15;
+
+ /** */
+ static final byte BOOLEAN_ARR = 16;
+
+ /** */
+ static final byte OBJ_ARR = 17;
+
+ /** */
+ static final byte STR = 18;
+
+ /** */
+ static final byte UUID = 19;
+
+ /** */
+ static final byte PROPS = 20;
+
+ /** */
+ static final byte ARRAY_LIST = 21;
+
+ /** */
+ static final byte HASH_MAP = 22;
+
+ /** */
+ static final byte HASH_SET = 23;
+
+ /** */
+ static final byte LINKED_LIST = 24;
+
+ /** */
+ static final byte LINKED_HASH_MAP = 25;
+
+ /** */
+ static final byte LINKED_HASH_SET = 26;
+
+ /** */
+ static final byte DATE = 27;
+
+ /** */
+ static final byte CLS = 28;
+
+ /** */
+ static final byte PROXY = 29;
+
+ /** */
+ static final byte ENUM = 100;
+
+ /** */
+ static final byte EXTERNALIZABLE = 101;
+
+ /** */
+ static final byte SERIALIZABLE = 102;
+
+ /** UTF-8 character name. */
+ static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ /** JDK marshaller. */
+ static final JdkMarshaller JDK_MARSH = new JdkMarshaller();
+
+ static {
+ long mapOff;
+
+ try {
+ mapOff = GridUnsafe.objectFieldOffset(HashSet.class.getDeclaredField("map"));
+ }
+ catch (NoSuchFieldException ignored) {
+ try {
+ // Workaround for legacy IBM JRE.
+ mapOff = GridUnsafe.objectFieldOffset(HashSet.class.getDeclaredField("backingMap"));
+ }
+ catch (NoSuchFieldException e2) {
+ throw new IgniteException("Initialization failure.", e2);
+ }
+ }
+
+ HASH_SET_MAP_OFF = mapOff;
+ }
+
+ /**
+ */
+ private OptimizedMarshallerUtils() {
+ // No-op.
+ }
+
+ /**
+ * Gets descriptor for provided class.
+ *
+ * @param clsMap Class descriptors by class map.
+ * @param cls Class.
+ * @param ctx Context.
+ * @param mapper ID mapper.
+ * @return Descriptor.
+ * @throws IOException In case of error.
+ */
+ static OptimizedClassDescriptor classDescriptor(
+ ConcurrentMap<Class, OptimizedClassDescriptor> clsMap,
+ Class cls,
+ MarshallerContext ctx,
+ OptimizedMarshallerIdMapper mapper)
+ throws IOException
+ {
+ OptimizedClassDescriptor desc = clsMap.get(cls);
+
+ if (desc == null) {
+ int typeId = resolveTypeId(cls.getName(), mapper);
+
+ boolean registered;
+
+ try {
+ registered = ctx.registerClassName(JAVA_ID, typeId, cls.getName());
+ }
+ catch (IgniteCheckedException e) {
+ throw new IOException("Failed to register class: " + cls.getName(), e);
+ }
+
+ desc = new OptimizedClassDescriptor(cls, registered ? typeId : 0, clsMap, ctx, mapper);
+
+ if (registered) {
+ OptimizedClassDescriptor old = clsMap.putIfAbsent(cls, desc);
+
+ if (old != null)
+ desc = old;
+ }
+ }
+
+ return desc;
+ }
+
+ /**
+ * @param clsName Class name.
+ * @param mapper Mapper.
+ * @return Type ID.
+ */
+ private static int resolveTypeId(String clsName, OptimizedMarshallerIdMapper mapper) {
+ int typeId;
+
+ if (mapper != null) {
+ typeId = mapper.typeId(clsName);
+
+ if (typeId == 0)
+ typeId = clsName.hashCode();
+ }
+ else
+ typeId = clsName.hashCode();
+
+ return typeId;
+ }
+
+ /**
+ * Gets descriptor for provided ID.
+ *
+ * @param clsMap Class descriptors by class map.
+ * @param typeId ID.
+ * @param ldr Class loader.
+ * @param ctx Context.
+ * @param mapper ID mapper.
+ * @return Descriptor.
+ * @throws IOException In case of error.
+ * @throws ClassNotFoundException If class was not found.
+ */
+ static OptimizedClassDescriptor classDescriptor(
+ ConcurrentMap<Class, OptimizedClassDescriptor> clsMap,
+ int typeId,
+ ClassLoader ldr,
+ MarshallerContext ctx,
+ OptimizedMarshallerIdMapper mapper) throws IOException, ClassNotFoundException {
+ Class cls;
+
+ try {
+ cls = ctx.getClass(typeId, ldr);
+ }
+ catch (IgniteCheckedException e) {
+ throw new IOException("Failed to resolve class for ID: " + typeId, e);
+ }
+
+ OptimizedClassDescriptor desc = clsMap.get(cls);
+
+ if (desc == null) {
+ OptimizedClassDescriptor old = clsMap.putIfAbsent(cls, desc =
+ new OptimizedClassDescriptor(cls, resolveTypeId(cls.getName(), mapper), clsMap, ctx, mapper));
+
+ if (old != null)
+ desc = old;
+ }
+
+ return desc;
+ }
+
+ /**
+ * Computes the serial version UID value for the given class. The code is taken from {@link
+ * ObjectStreamClass#computeDefaultSUID(Class)}.
+ *
+ * @param cls A class.
+ * @param fields Fields.
+ * @return A serial version UID.
+ * @throws IOException If failed.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ static short computeSerialVersionUid(Class cls, List<Field> fields) throws IOException {
+ if (Serializable.class.isAssignableFrom(cls) && !Enum.class.isAssignableFrom(cls)) {
+ try {
+ Field field = cls.getDeclaredField("serialVersionUID");
+
+ if (field.getType() == long.class) {
+ int mod = field.getModifiers();
+
+ if (Modifier.isStatic(mod) && Modifier.isFinal(mod)) {
+ field.setAccessible(true);
+
+ return (short)field.getLong(null);
+ }
+ }
+ }
+ catch (NoSuchFieldException ignored) {
+ // No-op.
+ }
+ catch (IllegalAccessException e) {
+ throw new IOException(e);
+ }
+
+ if (OptimizedMarshaller.USE_DFLT_SUID)
+ return (short)ObjectStreamClass.lookup(cls).getSerialVersionUID();
+ }
+
+ MessageDigest md;
+
+ try {
+ md = MessageDigest.getInstance("SHA");
+ }
+ catch (NoSuchAlgorithmException e) {
+ throw new IOException("Failed to get digest for SHA.", e);
+ }
+
+ md.update(cls.getName().getBytes(UTF_8));
+
+ if (!F.isEmpty(fields)) {
+ for (int i = 0; i < fields.size(); i++) {
+ Field f = fields.get(i);
+
+ md.update(f.getName().getBytes(UTF_8));
+ md.update(f.getType().getName().getBytes(UTF_8));
+ }
+ }
+
+ byte[] hashBytes = md.digest();
+
+ long hash = 0;
+
+ // Composes a single-long hash from the byte[] hash.
+ for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--)
+ hash = (hash << 8) | (hashBytes[i] & 0xFF);
+
+ return (short)hash;
+ }
+
+ /**
+ * Gets byte field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Byte value.
+ */
+ static byte getByte(Object obj, long off) {
+ return GridUnsafe.getByteField(obj, off);
+ }
+
+ /**
+ * Sets byte field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setByte(Object obj, long off, byte val) {
+ GridUnsafe.putByteField(obj, off, val);
+ }
+
+ /**
+ * Gets short field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Short value.
+ */
+ static short getShort(Object obj, long off) {
+ return GridUnsafe.getShortField(obj, off);
+ }
+
+ /**
+ * Sets short field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setShort(Object obj, long off, short val) {
+ GridUnsafe.putShortField(obj, off, val);
+ }
+
+ /**
+ * Gets integer field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Integer value.
+ */
+ static int getInt(Object obj, long off) {
+ return GridUnsafe.getIntField(obj, off);
+ }
+
+ /**
+ * Sets integer field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setInt(Object obj, long off, int val) {
+ GridUnsafe.putIntField(obj, off, val);
+ }
+
+ /**
+ * Gets long field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Long value.
+ */
+ static long getLong(Object obj, long off) {
+ return GridUnsafe.getLongField(obj, off);
+ }
+
+ /**
+ * Sets long field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setLong(Object obj, long off, long val) {
+ GridUnsafe.putLongField(obj, off, val);
+ }
+
+ /**
+ * Gets float field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Float value.
+ */
+ static float getFloat(Object obj, long off) {
+ return GridUnsafe.getFloatField(obj, off);
+ }
+
+ /**
+ * Sets float field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setFloat(Object obj, long off, float val) {
+ GridUnsafe.putFloatField(obj, off, val);
+ }
+
+ /**
+ * Gets double field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Double value.
+ */
+ static double getDouble(Object obj, long off) {
+ return GridUnsafe.getDoubleField(obj, off);
+ }
+
+ /**
+ * Sets double field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setDouble(Object obj, long off, double val) {
+ GridUnsafe.putDoubleField(obj, off, val);
+ }
+
+ /**
+ * Gets char field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Char value.
+ */
+ static char getChar(Object obj, long off) {
+ return GridUnsafe.getCharField(obj, off);
+ }
+
+ /**
+ * Sets char field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setChar(Object obj, long off, char val) {
+ GridUnsafe.putCharField(obj, off, val);
+ }
+
+ /**
+ * Gets boolean field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Boolean value.
+ */
+ static boolean getBoolean(Object obj, long off) {
+ return GridUnsafe.getBooleanField(obj, off);
+ }
+
+ /**
+ * Sets boolean field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setBoolean(Object obj, long off, boolean val) {
+ GridUnsafe.putBooleanField(obj, off, val);
+ }
+
+ /**
+ * Gets field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @return Value.
+ */
+ static Object getObject(Object obj, long off) {
+ return GridUnsafe.getObjectField(obj, off);
+ }
+
+ /**
+ * Sets field value.
+ *
+ * @param obj Object.
+ * @param off Field offset.
+ * @param val Value.
+ */
+ static void setObject(Object obj, long off, Object val) {
+ GridUnsafe.putObjectField(obj, off, val);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b5b8c3/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java
new file mode 100644
index 0000000..be0e115
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java
@@ -0,0 +1,1231 @@
+/*
+ * 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.ignite.internal.marshaller.optimized;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.NotActiveException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputValidation;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.io.GridDataInput;
+import org.apache.ignite.internal.util.typedef.internal.SB;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.marshaller.MarshallerContext;
+
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.ARRAY_LIST;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.BOOLEAN;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.BOOLEAN_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.BYTE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.BYTE_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.CHAR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.CHAR_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.CLS;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.DATE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.DOUBLE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.DOUBLE_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.ENUM;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.EXTERNALIZABLE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.FLOAT;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.FLOAT_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.HANDLE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.HASH_MAP;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.HASH_SET;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.HASH_SET_MAP_OFF;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.INT;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.INT_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.JDK;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.JDK_MARSH;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.LINKED_HASH_MAP;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.LINKED_HASH_SET;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.LINKED_LIST;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.LONG;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.LONG_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.NULL;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.OBJ_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.PROPS;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.PROXY;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.SERIALIZABLE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.SHORT;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.SHORT_ARR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.STR;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.UUID;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.classDescriptor;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setBoolean;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setByte;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setChar;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setDouble;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setFloat;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setInt;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setLong;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setObject;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.setShort;
+
+/**
+ * Optimized object input stream.
+ */
+class OptimizedObjectInputStream extends ObjectInputStream {
+ /** Dummy object for HashSet. */
+ private static final Object DUMMY = new Object();
+
+ /** */
+ private final HandleTable handles = new HandleTable(10);
+
+ /** */
+ private MarshallerContext ctx;
+
+ /** */
+ private OptimizedMarshallerIdMapper mapper;
+
+ /** */
+ private ClassLoader clsLdr;
+
+ /** */
+ private GridDataInput in;
+
+ /** */
+ private Object curObj;
+
+ /** */
+ private OptimizedClassDescriptor.ClassFields curFields;
+
+ /** */
+ private Class<?> curCls;
+
+ /** */
+ private ConcurrentMap<Class, OptimizedClassDescriptor> clsMap;
+
+ /**
+ * @param in Input.
+ * @throws IOException In case of error.
+ */
+ OptimizedObjectInputStream(GridDataInput in) throws IOException {
+ this.in = in;
+ }
+
+ /**
+ * @param clsMap Class descriptors by class map.
+ * @param ctx Context.
+ * @param mapper ID mapper.
+ * @param clsLdr Class loader.
+ */
+ void context(
+ ConcurrentMap<Class, OptimizedClassDescriptor> clsMap,
+ MarshallerContext ctx,
+ OptimizedMarshallerIdMapper mapper,
+ ClassLoader clsLdr)
+ {
+ this.clsMap = clsMap;
+ this.ctx = ctx;
+ this.mapper = mapper;
+ this.clsLdr = clsLdr;
+ }
+
+ /**
+ * @return Input.
+ */
+ public GridDataInput in() {
+ return in;
+ }
+
+ /**
+ * @param in Input.
+ */
+ public void in(GridDataInput in) {
+ this.in = in;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() throws IOException {
+ reset();
+
+ ctx = null;
+ clsLdr = null;
+ clsMap = null;
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod")
+ @Override public void reset() throws IOException {
+ in.reset();
+ handles.clear();
+
+ curObj = null;
+ curFields = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object readObjectOverride() throws ClassNotFoundException, IOException {
+ curObj = null;
+ curFields = null;
+
+ byte ref = in.readByte();
+
+ switch (ref) {
+ case NULL:
+ return null;
+
+ case HANDLE:
+ return handles.lookup(readInt());
+
+ case JDK:
+ try {
+ return JDK_MARSH.unmarshal(this, clsLdr);
+ }
+ catch (IgniteCheckedException e) {
+ IOException ioEx = e.getCause(IOException.class);
+
+ if (ioEx != null)
+ throw ioEx;
+ else
+ throw new IOException("Failed to deserialize object with JDK marshaller.", e);
+ }
+
+ case BYTE:
+ return readByte();
+
+ case SHORT:
+ return readShort();
+
+ case INT:
+ return readInt();
+
+ case LONG:
+ return readLong();
+
+ case FLOAT:
+ return readFloat();
+
+ case DOUBLE:
+ return readDouble();
+
+ case CHAR:
+ return readChar();
+
+ case BOOLEAN:
+ return readBoolean();
+
+ case BYTE_ARR:
+ return readByteArray();
+
+ case SHORT_ARR:
+ return readShortArray();
+
+ case INT_ARR:
+ return readIntArray();
+
+ case LONG_ARR:
+ return readLongArray();
+
+ case FLOAT_ARR:
+ return readFloatArray();
+
+ case DOUBLE_ARR:
+ return readDoubleArray();
+
+ case CHAR_ARR:
+ return readCharArray();
+
+ case BOOLEAN_ARR:
+ return readBooleanArray();
+
+ case OBJ_ARR:
+ return readArray(readClass());
+
+ case STR:
+ return readString();
+
+ case UUID:
+ return readUuid();
+
+ case PROPS:
+ return readProperties();
+
+ case ARRAY_LIST:
+ return readArrayList();
+
+ case HASH_MAP:
+ return readHashMap(false);
+
+ case HASH_SET:
+ return readHashSet(HASH_SET_MAP_OFF);
+
+ case LINKED_LIST:
+ return readLinkedList();
+
+ case LINKED_HASH_MAP:
+ return readLinkedHashMap(false);
+
+ case LINKED_HASH_SET:
+ return readLinkedHashSet(HASH_SET_MAP_OFF);
+
+ case DATE:
+ return readDate();
+
+ case CLS:
+ return readClass();
+
+ case PROXY:
+ Class<?>[] intfs = new Class<?>[readInt()];
+
+ for (int i = 0; i < intfs.length; i++)
+ intfs[i] = readClass();
+
+ InvocationHandler ih = (InvocationHandler)readObject();
+
+ return Proxy.newProxyInstance(clsLdr != null ? clsLdr : U.gridClassLoader(), intfs, ih);
+
+ case ENUM:
+ case EXTERNALIZABLE:
+ case SERIALIZABLE:
+ int typeId = readInt();
+
+ OptimizedClassDescriptor desc = typeId == 0 ?
+ classDescriptor(clsMap, U.forName(readUTF(), clsLdr), ctx, mapper):
+ classDescriptor(clsMap, typeId, clsLdr, ctx, mapper);
+
+ curCls = desc.describedClass();
+
+ return desc.read(this);
+
+ default:
+ SB msg = new SB("Unexpected error occurred during unmarshalling");
+
+ if (curCls != null)
+ msg.a(" of an instance of the class: ").a(curCls.getName());
+
+ msg.a(". Check that all nodes are running the same version of Ignite and that all nodes have " +
+ "GridOptimizedMarshaller configured with identical optimized classes lists, if any " +
+ "(see setClassNames and setClassNamesPath methods). If your serialized classes implement " +
+ "java.io.Externalizable interface, verify that serialization logic is correct.");
+
+ throw new IOException(msg.toString());
+ }
+ }
+
+ /**
+ * @return Class.
+ * @throws ClassNotFoundException If class was not found.
+ * @throws IOException In case of other error.
+ */
+ private Class<?> readClass() throws ClassNotFoundException, IOException {
+ int compTypeId = readInt();
+
+ return compTypeId == 0 ? U.forName(readUTF(), clsLdr) :
+ classDescriptor(clsMap, compTypeId, clsLdr, ctx, mapper).describedClass();
+ }
+
+ /**
+ * Reads array from this stream.
+ *
+ * @param compType Array component type.
+ * @return Array.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("unchecked")
+ <T> T[] readArray(Class<T> compType) throws ClassNotFoundException, IOException {
+ int len = in.readInt();
+
+ T[] arr = (T[])Array.newInstance(compType, len);
+
+ handles.assign(arr);
+
+ for (int i = 0; i < len; i++)
+ arr[i] = (T)readObject();
+
+ return arr;
+ }
+
+ /**
+ * Reads {@link UUID} from this stream.
+ *
+ * @return UUID.
+ * @throws IOException In case of error.
+ */
+ UUID readUuid() throws IOException {
+ UUID uuid = new UUID(readLong(), readLong());
+
+ handles.assign(uuid);
+
+ return uuid;
+ }
+
+ /**
+ * Reads {@link Properties} from this stream.
+ *
+ * @return Properties.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ Properties readProperties() throws ClassNotFoundException, IOException {
+ Properties dflts = readBoolean() ? null : (Properties)readObject();
+
+ Properties props = new Properties(dflts);
+
+ int size = in.readInt();
+
+ for (int i = 0; i < size; i++)
+ props.setProperty(readUTF(), readUTF());
+
+ handles.assign(props);
+
+ return props;
+ }
+
+ /**
+ * Reads and sets all non-static and non-transient field values from this stream.
+ *
+ * @param obj Object.
+ * @param fieldOffs Field offsets.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ void readFields(Object obj, OptimizedClassDescriptor.ClassFields fieldOffs) throws ClassNotFoundException,
+ IOException {
+ for (int i = 0; i < fieldOffs.size(); i++) {
+ OptimizedClassDescriptor.FieldInfo t = fieldOffs.get(i);
+
+ switch ((t.type())) {
+ case BYTE:
+ byte resByte = readByte();
+
+ if (t.field() != null)
+ setByte(obj, t.offset(), resByte);
+
+ break;
+
+ case SHORT:
+ short resShort = readShort();
+
+ if (t.field() != null)
+ setShort(obj, t.offset(), resShort);
+
+ break;
+
+ case INT:
+ int resInt = readInt();
+
+ if (t.field() != null)
+ setInt(obj, t.offset(), resInt);
+
+ break;
+
+ case LONG:
+ long resLong = readLong();
+
+ if (t.field() != null)
+ setLong(obj, t.offset(), resLong);
+
+ break;
+
+ case FLOAT:
+ float resFloat = readFloat();
+
+ if (t.field() != null)
+ setFloat(obj, t.offset(), resFloat);
+
+ break;
+
+ case DOUBLE:
+ double resDouble = readDouble();
+
+ if (t.field() != null)
+ setDouble(obj, t.offset(), resDouble);
+
+ break;
+
+ case CHAR:
+ char resChar = readChar();
+
+ if (t.field() != null)
+ setChar(obj, t.offset(), resChar);
+
+ break;
+
+ case BOOLEAN:
+ boolean resBoolean = readBoolean();
+
+ if (t.field() != null)
+ setBoolean(obj, t.offset(), resBoolean);
+
+ break;
+
+ case OTHER:
+ Object resObject = readObject();
+
+ if (t.field() != null)
+ setObject(obj, t.offset(), resObject);
+ }
+ }
+ }
+
+ /**
+ * Reads {@link Externalizable} object.
+ *
+ * @param constructor Constructor.
+ * @param readResolveMtd {@code readResolve} method.
+ * @return Object.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ Object readExternalizable(Constructor<?> constructor, Method readResolveMtd)
+ throws ClassNotFoundException, IOException {
+ Object obj;
+
+ try {
+ obj = constructor.newInstance();
+ }
+ catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
+ throw new IOException(e);
+ }
+
+ int handle = handles.assign(obj);
+
+ Externalizable extObj = ((Externalizable)obj);
+
+ extObj.readExternal(this);
+
+ if (readResolveMtd != null) {
+ try {
+ obj = readResolveMtd.invoke(obj);
+
+ handles.set(handle, obj);
+ }
+ catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IOException(e);
+ }
+ }
+
+ return obj;
+ }
+
+ /**
+ * Reads serializable object.
+ *
+ * @param cls Class.
+ * @param mtds {@code readObject} methods.
+ * @param readResolveMtd {@code readResolve} method.
+ * @param fields class fields details.
+ * @return Object.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ Object readSerializable(Class<?> cls, List<Method> mtds, Method readResolveMtd,
+ OptimizedClassDescriptor.Fields fields) throws ClassNotFoundException, IOException {
+ Object obj;
+
+ try {
+ obj = GridUnsafe.allocateInstance(cls);
+ }
+ catch (InstantiationException e) {
+ throw new IOException(e);
+ }
+
+ int handle = handles.assign(obj);
+
+ for (int i = 0; i < mtds.size(); i++) {
+ Method mtd = mtds.get(i);
+
+ if (mtd != null) {
+ curObj = obj;
+ curFields = fields.fields(i);
+
+ try {
+ mtd.invoke(obj, this);
+ }
+ catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IOException(e);
+ }
+ }
+ else
+ readFields(obj, fields.fields(i));
+ }
+
+ if (readResolveMtd != null) {
+ try {
+ obj = readResolveMtd.invoke(obj);
+
+ handles.set(handle, obj);
+ }
+ catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IOException(e);
+ }
+ }
+
+ return obj;
+ }
+
+ /**
+ * Reads {@link ArrayList}.
+ *
+ * @return List.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ ArrayList<?> readArrayList() throws ClassNotFoundException, IOException {
+ int size = readInt();
+
+ ArrayList<Object> list = new ArrayList<>(size);
+
+ handles.assign(list);
+
+ for (int i = 0; i < size; i++)
+ list.add(readObject());
+
+ return list;
+ }
+
+ /**
+ * Reads {@link HashMap}.
+ *
+ * @param set Whether reading underlying map from {@link HashSet}.
+ * @return Map.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ HashMap<?, ?> readHashMap(boolean set) throws ClassNotFoundException, IOException {
+ int size = readInt();
+ float loadFactor = readFloat();
+
+ HashMap<Object, Object> map = new HashMap<>(size, loadFactor);
+
+ if (!set)
+ handles.assign(map);
+
+ for (int i = 0; i < size; i++) {
+ Object key = readObject();
+ Object val = !set ? readObject() : DUMMY;
+
+ map.put(key, val);
+ }
+
+ return map;
+ }
+
+ /**
+ * Reads {@link HashSet}.
+ *
+ * @param mapFieldOff Map field offset.
+ * @return Set.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("unchecked")
+ HashSet<?> readHashSet(long mapFieldOff) throws ClassNotFoundException, IOException {
+ try {
+ HashSet<Object> set = (HashSet<Object>)GridUnsafe.allocateInstance(HashSet.class);
+
+ handles.assign(set);
+
+ setObject(set, mapFieldOff, readHashMap(true));
+
+ return set;
+ }
+ catch (InstantiationException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * Reads {@link LinkedList}.
+ *
+ * @return List.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ LinkedList<?> readLinkedList() throws ClassNotFoundException, IOException {
+ int size = readInt();
+
+ LinkedList<Object> list = new LinkedList<>();
+
+ handles.assign(list);
+
+ for (int i = 0; i < size; i++)
+ list.add(readObject());
+
+ return list;
+ }
+
+ /**
+ * Reads {@link LinkedHashMap}.
+ *
+ * @param set Whether reading underlying map from {@link LinkedHashSet}.
+ * @return Map.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ LinkedHashMap<?, ?> readLinkedHashMap(boolean set) throws ClassNotFoundException, IOException {
+ int size = readInt();
+ float loadFactor = readFloat();
+ boolean accessOrder = readBoolean();
+
+ LinkedHashMap<Object, Object> map = new LinkedHashMap<>(size, loadFactor, accessOrder);
+
+ if (!set)
+ handles.assign(map);
+
+ for (int i = 0; i < size; i++) {
+ Object key = readObject();
+ Object val = !set ? readObject() : DUMMY;
+
+ map.put(key, val);
+ }
+
+ return map;
+ }
+
+ /**
+ * Reads {@link LinkedHashSet}.
+ *
+ * @param mapFieldOff Map field offset.
+ * @return Set.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("unchecked")
+ LinkedHashSet<?> readLinkedHashSet(long mapFieldOff) throws ClassNotFoundException, IOException {
+ try {
+ LinkedHashSet<Object> set = (LinkedHashSet<Object>)GridUnsafe.allocateInstance(LinkedHashSet.class);
+
+ handles.assign(set);
+
+ setObject(set, mapFieldOff, readLinkedHashMap(true));
+
+ return set;
+ }
+ catch (InstantiationException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * Reads {@link Date}.
+ *
+ * @return Date.
+ * @throws ClassNotFoundException If class not found.
+ * @throws IOException In case of error.
+ */
+ Date readDate() throws ClassNotFoundException, IOException {
+ Date date = new Date(readLong());
+
+ handles.assign(date);
+
+ return date;
+ }
+
+ /**
+ * Reads array of {@code byte}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ byte[] readByteArray() throws IOException {
+ byte[] arr = in.readByteArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code short}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ short[] readShortArray() throws IOException {
+ short[] arr = in.readShortArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code int}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ int[] readIntArray() throws IOException {
+ int[] arr = in.readIntArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code long}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ long[] readLongArray() throws IOException {
+ long[] arr = in.readLongArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code float}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ float[] readFloatArray() throws IOException {
+ float[] arr = in.readFloatArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code double}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ double[] readDoubleArray() throws IOException {
+ double[] arr = in.readDoubleArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code char}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ char[] readCharArray() throws IOException {
+ char[] arr = in.readCharArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads array of {@code boolean}s.
+ *
+ * @return Array.
+ * @throws IOException In case of error.
+ */
+ boolean[] readBooleanArray() throws IOException {
+ boolean[] arr = in.readBooleanArray();
+
+ handles.assign(arr);
+
+ return arr;
+ }
+
+ /**
+ * Reads {@link String}.
+ *
+ * @return String.
+ * @throws IOException In case of error.
+ */
+ public String readString() throws IOException {
+ String str = in.readUTF();
+
+ handles.assign(str);
+
+ return str;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readFully(byte[] b) throws IOException {
+ in.readFully(b);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readFully(byte[] b, int off, int len) throws IOException {
+ in.readFully(b, off, len);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int skipBytes(int n) throws IOException {
+ return in.skipBytes(n);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean readBoolean() throws IOException {
+ return in.readBoolean();
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte readByte() throws IOException {
+ return in.readByte();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int readUnsignedByte() throws IOException {
+ return in.readUnsignedByte();
+ }
+
+ /** {@inheritDoc} */
+ @Override public short readShort() throws IOException {
+ return in.readShort();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int readUnsignedShort() throws IOException {
+ return in.readUnsignedShort();
+ }
+
+ /** {@inheritDoc} */
+ @Override public char readChar() throws IOException {
+ return in.readChar();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int readInt() throws IOException {
+ return in.readInt();
+ }
+
+ /** {@inheritDoc} */
+ @Override public long readLong() throws IOException {
+ return in.readLong();
+ }
+
+ /** {@inheritDoc} */
+ @Override public float readFloat() throws IOException {
+ return in.readFloat();
+ }
+
+ /** {@inheritDoc} */
+ @Override public double readDouble() throws IOException {
+ return in.readDouble();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int read() throws IOException {
+ return in.read();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int read(byte[] b) throws IOException {
+ return in.read(b);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ return in.read(b, off, len);
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("deprecation")
+ @Override public String readLine() throws IOException {
+ return in.readLine();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String readUTF() throws IOException {
+ return in.readUTF();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object readUnshared() throws IOException, ClassNotFoundException {
+ return readObject();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void defaultReadObject() throws IOException, ClassNotFoundException {
+ if (curObj == null)
+ throw new NotActiveException("Not in readObject() call.");
+
+ readFields(curObj, curFields);
+ }
+
+ /** {@inheritDoc} */
+ @Override public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException {
+ if (curObj == null)
+ throw new NotActiveException("Not in readObject() call.");
+
+ return new GetFieldImpl(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void registerValidation(ObjectInputValidation obj, int pri) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public int available() throws IOException {
+ return -1;
+ }
+
+ /**
+ * Returns objects that were added to handles table.
+ * Used ONLY for test purposes.
+ *
+ * @return Handled objects.
+ */
+ Object[] handledObjects() {
+ return handles.entries;
+ }
+
+ /**
+ * Lightweight identity hash table which maps objects to integer handles,
+ * assigned in ascending order.
+ */
+ private static class HandleTable {
+ /** Array mapping handle -> object/exception (depending on status). */
+ private Object[] entries;
+
+ /** Number of handles in table. */
+ private int size;
+
+ /**
+ * Creates handle table with the given initial capacity.
+ *
+ * @param initCap Initial capacity.
+ */
+ HandleTable(int initCap) {
+ entries = new Object[initCap];
+ }
+
+ /**
+ * Assigns next available handle to given object, and returns assigned
+ * handle.
+ *
+ * @param obj Object.
+ * @return Handle.
+ */
+ int assign(Object obj) {
+ if (size >= entries.length)
+ grow();
+
+ entries[size] = obj;
+
+ return size++;
+ }
+
+ /**
+ * Assigns new object to existing handle. Old object is forgotten.
+ *
+ * @param handle Handle.
+ * @param obj Object.
+ */
+ void set(int handle, Object obj) {
+ entries[handle] = obj;
+ }
+
+ /**
+ * Looks up and returns object associated with the given handle.
+ *
+ * @param handle Handle.
+ * @return Object.
+ */
+ Object lookup(int handle) {
+ return entries[handle];
+ }
+
+ /**
+ * Resets table to its initial state.
+ */
+ void clear() {
+ Arrays.fill(entries, 0, size, null);
+
+ size = 0;
+ }
+
+ /**
+ * Expands capacity of internal arrays.
+ */
+ private void grow() {
+ int newCap = (entries.length << 1) + 1;
+
+ Object[] newEntries = new Object[newCap];
+
+ System.arraycopy(entries, 0, newEntries, 0, size);
+
+ entries = newEntries;
+ }
+ }
+
+ /**
+ * {@link GetField} implementation.
+ */
+ private static class GetFieldImpl extends GetField {
+ /** Field info. */
+ private final OptimizedClassDescriptor.ClassFields fieldInfo;
+
+ /** Values. */
+ private final Object[] objs;
+
+ /**
+ * @param in Stream.
+ * @throws IOException In case of error.
+ * @throws ClassNotFoundException If class not found.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ private GetFieldImpl(OptimizedObjectInputStream in) throws IOException, ClassNotFoundException {
+ fieldInfo = in.curFields;
+
+ objs = new Object[fieldInfo.size()];
+
+ for (int i = 0; i < fieldInfo.size(); i++) {
+ OptimizedClassDescriptor.FieldInfo t = fieldInfo.get(i);
+
+ Object obj = null;
+
+ switch (t.type()) {
+ case BYTE:
+ obj = in.readByte();
+
+ break;
+
+ case SHORT:
+ obj = in.readShort();
+
+ break;
+
+ case INT:
+ obj = in.readInt();
+
+ break;
+
+ case LONG:
+ obj = in.readLong();
+
+ break;
+
+ case FLOAT:
+ obj = in.readFloat();
+
+ break;
+
+ case DOUBLE:
+ obj = in.readDouble();
+
+ break;
+
+ case CHAR:
+ obj = in.readChar();
+
+ break;
+
+ case BOOLEAN:
+ obj = in.readBoolean();
+
+ break;
+
+ case OTHER:
+ obj = in.readObject();
+ }
+
+ objs[i] = obj;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public ObjectStreamClass getObjectStreamClass() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean defaulted(String name) throws IOException {
+ return objs[fieldInfo.getIndex(name)] == null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean get(String name, boolean dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte get(String name, byte dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public char get(String name, char dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public short get(String name, short dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int get(String name, int dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public long get(String name, long dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public float get(String name, float dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public double get(String name, double dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object get(String name, Object dflt) throws IOException {
+ return value(name, dflt);
+ }
+
+ /**
+ * @param name Field name.
+ * @param dflt Default value.
+ * @return Value.
+ */
+ @SuppressWarnings("unchecked")
+ private <T> T value(String name, T dflt) {
+ return objs[fieldInfo.getIndex(name)] != null ? (T)objs[fieldInfo.getIndex(name)] : dflt;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b5b8c3/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectOutputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectOutputStream.java
new file mode 100644
index 0000000..bdb1b2f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectOutputStream.java
@@ -0,0 +1,875 @@
+/*
+ * 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.ignite.internal.marshaller.optimized;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.NotActiveException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.util.GridHandleTable;
+import org.apache.ignite.internal.util.io.GridDataOutput;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.marshaller.MarshallerContext;
+
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.HANDLE;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.JDK;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.JDK_MARSH;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.NULL;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.classDescriptor;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getBoolean;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getByte;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getChar;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getDouble;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getFloat;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getInt;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getLong;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getObject;
+import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.getShort;
+
+/**
+ * Optimized object output stream.
+ */
+class OptimizedObjectOutputStream extends ObjectOutputStream {
+ /** */
+ private final GridHandleTable handles = new GridHandleTable(10, 3.00f);
+
+ /** */
+ private final GridDataOutput out;
+
+ /** */
+ private MarshallerContext ctx;
+
+ /** */
+ private OptimizedMarshallerIdMapper mapper;
+
+ /** */
+ private boolean requireSer;
+
+ /** */
+ private Object curObj;
+
+ /** */
+ private OptimizedClassDescriptor.ClassFields curFields;
+
+ /** */
+ private PutFieldImpl curPut;
+
+ /** */
+ private ConcurrentMap<Class, OptimizedClassDescriptor> clsMap;
+
+ /**
+ * @param out Output.
+ * @throws IOException In case of error.
+ */
+ OptimizedObjectOutputStream(GridDataOutput out) throws IOException {
+ this.out = out;
+ }
+
+ /**
+ * @param clsMap Class descriptors by class map.
+ * @param ctx Context.
+ * @param mapper ID mapper.
+ * @param requireSer Require {@link Serializable} flag.
+ */
+ void context(ConcurrentMap<Class, OptimizedClassDescriptor> clsMap,
+ MarshallerContext ctx,
+ OptimizedMarshallerIdMapper mapper,
+ boolean requireSer) {
+ this.clsMap = clsMap;
+ this.ctx = ctx;
+ this.mapper = mapper;
+ this.requireSer = requireSer;
+ }
+
+ /**
+ * @return Require {@link Serializable} flag.
+ */
+ boolean requireSerializable() {
+ return requireSer;
+ }
+
+ /**
+ * @return Output.
+ */
+ public GridDataOutput out() {
+ return out;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() throws IOException {
+ reset();
+
+ ctx = null;
+ clsMap = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void write(byte[] b) throws IOException {
+ out.write(b);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void write(byte[] b, int off, int len) throws IOException {
+ out.write(b, off, len);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeObjectOverride(Object obj) throws IOException {
+ writeObject0(obj);
+ }
+
+ /**
+ * Writes object to stream.
+ *
+ * @param obj Object.
+ * @throws IOException In case of error.
+ */
+ private void writeObject0(Object obj) throws IOException {
+ curObj = null;
+ curFields = null;
+ curPut = null;
+
+ if (obj == null)
+ writeByte(NULL);
+ else {
+ if (obj instanceof Throwable && !(obj instanceof Externalizable)) {
+ writeByte(JDK);
+
+ try {
+ JDK_MARSH.marshal(obj, this);
+ }
+ catch (IgniteCheckedException e) {
+ IOException ioEx = e.getCause(IOException.class);
+
+ if (ioEx != null)
+ throw ioEx;
+ else
+ throw new IOException("Failed to serialize object with JDK marshaller: " + obj, e);
+ }
+ }
+ else {
+ OptimizedClassDescriptor desc = classDescriptor(
+ clsMap,
+ obj instanceof Object[] ? Object[].class : obj.getClass(),
+ ctx,
+ mapper);
+
+ if (desc.excluded()) {
+ writeByte(NULL);
+
+ return;
+ }
+
+ Object obj0 = desc.replace(obj);
+
+ if (obj0 == null) {
+ writeByte(NULL);
+
+ return;
+ }
+
+ int handle = -1;
+
+ if (!desc.isPrimitive() && !desc.isEnum() && !desc.isClass() && !desc.isProxy())
+ handle = handles.lookup(obj);
+
+ if (obj0 != obj) {
+ obj = obj0;
+
+ desc = classDescriptor(clsMap,
+ obj instanceof Object[] ? Object[].class : obj.getClass(),
+ ctx,
+ mapper);
+ }
+
+ if (handle >= 0) {
+ writeByte(HANDLE);
+ writeInt(handle);
+ }
+ else
+ desc.write(this, obj);
+ }
+ }
+ }
+
+ /**
+ * Writes array to this stream.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ void writeArray(Object[] arr) throws IOException {
+ int len = arr.length;
+
+ writeInt(len);
+
+ for (int i = 0; i < len; i++) {
+ Object obj = arr[i];
+
+ writeObject0(obj);
+ }
+ }
+
+ /**
+ * Writes {@link UUID} to this stream.
+ *
+ * @param uuid UUID.
+ * @throws IOException In case of error.
+ */
+ void writeUuid(UUID uuid) throws IOException {
+ writeLong(uuid.getMostSignificantBits());
+ writeLong(uuid.getLeastSignificantBits());
+ }
+
+ /**
+ * Writes {@link Properties} to this stream.
+ *
+ * @param props Properties.
+ * @param dfltsFieldOff Defaults field offset.
+ * @throws IOException In case of error.
+ */
+ void writeProperties(Properties props, long dfltsFieldOff) throws IOException {
+ Properties dflts = (Properties)getObject(props, dfltsFieldOff);
+
+ if (dflts == null)
+ writeBoolean(true);
+ else {
+ writeBoolean(false);
+
+ writeObject0(dflts);
+ }
+
+ Set<String> names = props.stringPropertyNames();
+
+ writeInt(names.size());
+
+ for (String name : names) {
+ writeUTF(name);
+ writeUTF(props.getProperty(name));
+ }
+ }
+
+ /**
+ * Writes externalizable object.
+ *
+ * @param obj Object.
+ * @throws IOException In case of error.
+ */
+ void writeExternalizable(Object obj) throws IOException {
+ Externalizable extObj = (Externalizable)obj;
+
+ extObj.writeExternal(this);
+ }
+
+ /**
+ * Writes serializable object.
+ *
+ * @param obj Object.
+ * @param mtds {@code writeObject} methods.
+ * @param fields class fields details.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ void writeSerializable(Object obj, List<Method> mtds, OptimizedClassDescriptor.Fields fields)
+ throws IOException {
+ for (int i = 0; i < mtds.size(); i++) {
+ Method mtd = mtds.get(i);
+
+ if (mtd != null) {
+ curObj = obj;
+ curFields = fields.fields(i);
+
+ try {
+ mtd.invoke(obj, this);
+ }
+ catch (IllegalAccessException e) {
+ throw new IOException(e);
+ }
+ catch (InvocationTargetException e) {
+ throw new IOException(e.getCause());
+ }
+ }
+ else
+ writeFields(obj, fields.fields(i));
+ }
+ }
+
+ /**
+ * Writes {@link ArrayList}.
+ *
+ * @param list List.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings({"ForLoopReplaceableByForEach", "TypeMayBeWeakened"})
+ void writeArrayList(ArrayList<?> list) throws IOException {
+ int size = list.size();
+
+ writeInt(size);
+
+ for (int i = 0; i < size; i++)
+ writeObject0(list.get(i));
+ }
+
+ /**
+ * Writes {@link HashMap}.
+ *
+ * @param map Map.
+ * @param loadFactorFieldOff Load factor field offset.
+ * @param set Whether writing underlying map from {@link HashSet}.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("TypeMayBeWeakened")
+ void writeHashMap(HashMap<?, ?> map, long loadFactorFieldOff, boolean set) throws IOException {
+ int size = map.size();
+
+ writeInt(size);
+ writeFloat(getFloat(map, loadFactorFieldOff));
+
+ for (Map.Entry<?, ?> e : map.entrySet()) {
+ writeObject0(e.getKey());
+
+ if (!set)
+ writeObject0(e.getValue());
+ }
+ }
+
+ /**
+ * Writes {@link HashSet}.
+ *
+ * @param set Set.
+ * @param mapFieldOff Map field offset.
+ * @param loadFactorFieldOff Load factor field offset.
+ * @throws IOException In case of error.
+ */
+ void writeHashSet(HashSet<?> set, long mapFieldOff, long loadFactorFieldOff) throws IOException {
+ writeHashMap((HashMap<?, ?>)getObject(set, mapFieldOff), loadFactorFieldOff, true);
+ }
+
+ /**
+ * Writes {@link LinkedList}.
+ *
+ * @param list List.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("TypeMayBeWeakened")
+ void writeLinkedList(LinkedList<?> list) throws IOException {
+ int size = list.size();
+
+ writeInt(size);
+
+ for (Object obj : list)
+ writeObject0(obj);
+ }
+
+ /**
+ * Writes {@link LinkedHashMap}.
+ *
+ * @param map Map.
+ * @param loadFactorFieldOff Load factor field offset.
+ * @param accessOrderFieldOff access order field offset.
+ * @param set Whether writing underlying map from {@link LinkedHashSet}.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("TypeMayBeWeakened")
+ void writeLinkedHashMap(LinkedHashMap<?, ?> map, long loadFactorFieldOff, long accessOrderFieldOff, boolean set)
+ throws IOException {
+ int size = map.size();
+
+ writeInt(size);
+ writeFloat(getFloat(map, loadFactorFieldOff));
+
+ if (accessOrderFieldOff >= 0)
+ writeBoolean(getBoolean(map, accessOrderFieldOff));
+ else
+ writeBoolean(false);
+
+ for (Map.Entry<?, ?> e : map.entrySet()) {
+ writeObject0(e.getKey());
+
+ if (!set)
+ writeObject0(e.getValue());
+ }
+ }
+
+ /**
+ * Writes {@link LinkedHashSet}.
+ *
+ * @param set Set.
+ * @param mapFieldOff Map field offset.
+ * @param loadFactorFieldOff Load factor field offset.
+ * @throws IOException In case of error.
+ */
+ void writeLinkedHashSet(LinkedHashSet<?> set, long mapFieldOff, long loadFactorFieldOff) throws IOException {
+ LinkedHashMap<?, ?> map = (LinkedHashMap<?, ?>)getObject(set, mapFieldOff);
+
+ writeLinkedHashMap(map, loadFactorFieldOff, -1, true);
+ }
+
+ /**
+ * Writes {@link Date}.
+ *
+ * @param date Date.
+ * @throws IOException In case of error.
+ */
+ void writeDate(Date date) throws IOException {
+ writeLong(date.getTime());
+ }
+
+ /**
+ * Writes all non-static and non-transient field values to this stream.
+ *
+ * @param obj Object.
+ * @param fields Fields.
+ * @throws IOException In case of error.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ private void writeFields(Object obj, OptimizedClassDescriptor.ClassFields fields) throws IOException {
+ for (int i = 0; i < fields.size(); i++) {
+ OptimizedClassDescriptor.FieldInfo t = fields.get(i);
+
+ switch (t.type()) {
+ case BYTE:
+ if (t.field() != null)
+ writeByte(getByte(obj, t.offset()));
+
+ break;
+
+ case SHORT:
+ if (t.field() != null)
+ writeShort(getShort(obj, t.offset()));
+
+ break;
+
+ case INT:
+ if (t.field() != null)
+ writeInt(getInt(obj, t.offset()));
+
+ break;
+
+ case LONG:
+ if (t.field() != null)
+ writeLong(getLong(obj, t.offset()));
+
+ break;
+
+ case FLOAT:
+ if (t.field() != null)
+ writeFloat(getFloat(obj, t.offset()));
+
+ break;
+
+ case DOUBLE:
+ if (t.field() != null)
+ writeDouble(getDouble(obj, t.offset()));
+
+ break;
+
+ case CHAR:
+ if (t.field() != null)
+ writeChar(getChar(obj, t.offset()));
+
+ break;
+
+ case BOOLEAN:
+ if (t.field() != null)
+ writeBoolean(getBoolean(obj, t.offset()));
+
+ break;
+
+ case OTHER:
+ if (t.field() != null)
+ writeObject0(getObject(obj, t.offset()));
+ }
+ }
+ }
+
+ /**
+ * Writes array of {@code byte}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeByteArray(byte[] arr) throws IOException {
+ out.writeByteArray(arr);
+ }
+
+ /**
+ * Writes array of {@code short}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeShortArray(short[] arr) throws IOException {
+ out.writeShortArray(arr);
+ }
+
+ /**
+ * Writes array of {@code int}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeIntArray(int[] arr) throws IOException {
+ out.writeIntArray(arr);
+ }
+
+ /**
+ * Writes array of {@code long}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeLongArray(long[] arr) throws IOException {
+ out.writeLongArray(arr);
+ }
+
+ /**
+ * Writes array of {@code float}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeFloatArray(float[] arr) throws IOException {
+ out.writeFloatArray(arr);
+ }
+
+ /**
+ * Writes array of {@code double}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeDoubleArray(double[] arr) throws IOException {
+ out.writeDoubleArray(arr);
+ }
+
+ /**
+ * Writes array of {@code char}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeCharArray(char[] arr) throws IOException {
+ out.writeCharArray(arr);
+ }
+
+ /**
+ * Writes array of {@code boolean}s.
+ *
+ * @param arr Array.
+ * @throws IOException In case of error.
+ */
+ void writeBooleanArray(boolean[] arr) throws IOException {
+ out.writeBooleanArray(arr);
+ }
+
+ /**
+ * Writes {@link String}.
+ *
+ * @param str String.
+ * @throws IOException In case of error.
+ */
+ void writeString(String str) throws IOException {
+ out.writeUTF(str);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBoolean(boolean v) throws IOException {
+ out.writeBoolean(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeByte(int v) throws IOException {
+ out.writeByte(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeShort(int v) throws IOException {
+ out.writeShort(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeChar(int v) throws IOException {
+ out.writeChar(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeInt(int v) throws IOException {
+ out.writeInt(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeLong(long v) throws IOException {
+ out.writeLong(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeFloat(float v) throws IOException {
+ out.writeFloat(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeDouble(double v) throws IOException {
+ out.writeDouble(v);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void write(int b) throws IOException {
+ writeByte(b);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBytes(String s) throws IOException {
+ out.writeBytes(s);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeChars(String s) throws IOException {
+ out.writeChars(s);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeUTF(String s) throws IOException {
+ out.writeUTF(s);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void useProtocolVersion(int ver) throws IOException {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeUnshared(Object obj) throws IOException {
+ writeObject0(obj);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void defaultWriteObject() throws IOException {
+ if (curObj == null)
+ throw new NotActiveException("Not in writeObject() call.");
+
+ writeFields(curObj, curFields);
+ }
+
+ /** {@inheritDoc} */
+ @Override public ObjectOutputStream.PutField putFields() throws IOException {
+ if (curObj == null)
+ throw new NotActiveException("Not in writeObject() call or fields already written.");
+
+ if (curPut == null)
+ curPut = new PutFieldImpl(this);
+
+ return curPut;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeFields() throws IOException {
+ if (curObj == null)
+ throw new NotActiveException("Not in writeObject() call.");
+
+ if (curPut == null)
+ throw new NotActiveException("putFields() was not called.");
+
+ for (IgniteBiTuple<OptimizedFieldType, Object> t : curPut.objs) {
+ switch (t.get1()) {
+ case BYTE:
+ writeByte((Byte)t.get2());
+
+ break;
+
+ case SHORT:
+ writeShort((Short)t.get2());
+
+ break;
+
+ case INT:
+ writeInt((Integer)t.get2());
+
+ break;
+
+ case LONG:
+ writeLong((Long)t.get2());
+
+ break;
+
+ case FLOAT:
+ writeFloat((Float)t.get2());
+
+ break;
+
+ case DOUBLE:
+ writeDouble((Double)t.get2());
+
+ break;
+
+ case CHAR:
+ writeChar((Character)t.get2());
+
+ break;
+
+ case BOOLEAN:
+ writeBoolean((Boolean)t.get2());
+
+ break;
+
+ case OTHER:
+ writeObject0(t.get2());
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void reset() throws IOException {
+ out.reset();
+ handles.clear();
+
+ curObj = null;
+ curFields = null;
+ curPut = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void flush() throws IOException {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void drain() throws IOException {
+ // No-op.
+ }
+
+ /**
+ * Returns objects that were added to handles table.
+ * Used ONLY for test purposes.
+ *
+ * @return Handled objects.
+ */
+ Object[] handledObjects() {
+ return handles.objects();
+ }
+
+ /**
+ * {@link PutField} implementation.
+ */
+ private static class PutFieldImpl extends PutField {
+ /** Stream. */
+ private final OptimizedObjectOutputStream out;
+
+ /** Fields info. */
+ private final OptimizedClassDescriptor.ClassFields curFields;
+ /** Values. */
+ private final IgniteBiTuple<OptimizedFieldType, Object>[] objs;
+
+ /**
+ * @param out Output stream.
+ */
+ @SuppressWarnings("unchecked")
+ private PutFieldImpl(OptimizedObjectOutputStream out) {
+ this.out = out;
+
+ curFields = out.curFields;
+
+ objs = new IgniteBiTuple[curFields.size()];
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, boolean val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, byte val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, char val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, short val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, int val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, long val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, float val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, double val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(String name, Object val) {
+ value(name, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void write(ObjectOutput out) throws IOException {
+ if (out != this.out)
+ throw new IllegalArgumentException("Wrong stream.");
+
+ this.out.writeFields();
+ }
+
+ /**
+ * @param name Field name.
+ * @param val Value.
+ */
+ private void value(String name, Object val) {
+ int i = curFields.getIndex(name);
+
+ OptimizedClassDescriptor.FieldInfo info = curFields.get(i);
+
+ objs[i] = F.t(info.type(), val);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b5b8c3/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectStreamRegistry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectStreamRegistry.java b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectStreamRegistry.java
new file mode 100644
index 0000000..cc31a9f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectStreamRegistry.java
@@ -0,0 +1,244 @@
+/*
+ * 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.ignite.internal.marshaller.optimized;
+
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.util.io.GridUnsafeDataInput;
+import org.apache.ignite.internal.util.io.GridUnsafeDataOutput;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Storage for object streams.
+ */
+class OptimizedObjectStreamRegistry {
+ /** Holders. */
+ private static final ThreadLocal<StreamHolder> holders = new ThreadLocal<>();
+
+ /** Output streams pool. */
+ private static BlockingQueue<OptimizedObjectOutputStream> outPool;
+
+ /** Input streams pool. */
+ private static BlockingQueue<OptimizedObjectInputStream> inPool;
+
+ /**
+ * Ensures singleton.
+ */
+ private OptimizedObjectStreamRegistry() {
+ // No-op.
+ }
+
+ /**
+ * Sets streams pool size.
+ *
+ * @param size Streams pool size.
+ */
+ static void poolSize(int size) {
+ if (size > 0) {
+ outPool = new LinkedBlockingQueue<>(size);
+ inPool = new LinkedBlockingQueue<>(size);
+
+ for (int i = 0; i < size; i++) {
+ outPool.offer(createOut());
+ inPool.offer(createIn());
+ }
+ }
+ else {
+ outPool = null;
+ inPool = null;
+ }
+ }
+
+ /**
+ * Gets output stream.
+ *
+ * @return Object output stream.
+ * @throws org.apache.ignite.internal.IgniteInterruptedCheckedException If thread is interrupted while trying to take holder from pool.
+ */
+ static OptimizedObjectOutputStream out() throws IgniteInterruptedCheckedException {
+ if (outPool != null) {
+ try {
+ return outPool.take();
+ }
+ catch (InterruptedException e) {
+ throw new IgniteInterruptedCheckedException(
+ "Failed to take output object stream from pool (thread interrupted).", e);
+ }
+ }
+ else
+ return holder().acquireOut();
+ }
+
+ /**
+ * Gets input stream.
+ *
+ * @return Object input stream.
+ * @throws org.apache.ignite.internal.IgniteInterruptedCheckedException If thread is interrupted while trying to take holder from pool.
+ */
+ static OptimizedObjectInputStream in() throws IgniteInterruptedCheckedException {
+ if (inPool != null) {
+ try {
+ return inPool.take();
+ }
+ catch (InterruptedException e) {
+ throw new IgniteInterruptedCheckedException(
+ "Failed to take input object stream from pool (thread interrupted).", e);
+ }
+ }
+ else
+ return holder().acquireIn();
+ }
+
+ /**
+ * Closes and releases output stream.
+ *
+ * @param out Object output stream.
+ */
+ static void closeOut(OptimizedObjectOutputStream out) {
+ U.close(out, null);
+
+ if (outPool != null) {
+ boolean b = outPool.offer(out);
+
+ assert b;
+ }
+ else {
+ StreamHolder holder = holders.get();
+
+ if (holder != null)
+ holder.releaseOut();
+ }
+ }
+
+ /**
+ * Closes and releases input stream.
+ *
+ * @param in Object input stream.
+ */
+ @SuppressWarnings("TypeMayBeWeakened")
+ static void closeIn(OptimizedObjectInputStream in) {
+ U.close(in, null);
+
+ if (inPool != null) {
+ boolean b = inPool.offer(in);
+
+ assert b;
+ }
+ else {
+ StreamHolder holder = holders.get();
+
+ if (holder != null)
+ holder.releaseIn();
+ }
+ }
+
+ /**
+ * Gets holder from pool or thread local.
+ *
+ * @return Stream holder.
+ * @throws org.apache.ignite.internal.IgniteInterruptedCheckedException If thread is interrupted while trying to take holder from pool.
+ */
+ private static StreamHolder holder() throws IgniteInterruptedCheckedException {
+ StreamHolder holder = holders.get();
+
+ if (holder == null)
+ holders.set(holder = new StreamHolder());
+
+ return holder;
+ }
+
+ /**
+ * Creates output stream.
+ *
+ * @return Object output stream.
+ */
+ private static OptimizedObjectOutputStream createOut() {
+ try {
+ return new OptimizedObjectOutputStream(new GridUnsafeDataOutput(4 * 1024));
+ }
+ catch (IOException e) {
+ throw new IgniteException("Failed to create object output stream.", e);
+ }
+ }
+
+ /**
+ * Creates input stream.
+ *
+ * @return Object input stream.
+ */
+ private static OptimizedObjectInputStream createIn() {
+ try {
+ return new OptimizedObjectInputStream(new GridUnsafeDataInput());
+ }
+ catch (IOException e) {
+ throw new IgniteException("Failed to create object input stream.", e);
+ }
+ }
+
+ /**
+ * Streams holder.
+ */
+ private static class StreamHolder {
+ /** Output stream. */
+ private final OptimizedObjectOutputStream out = createOut();
+
+ /** Input stream. */
+ private final OptimizedObjectInputStream in = createIn();
+
+ /** Output streams counter. */
+ private int outAcquireCnt;
+
+ /** Input streams counter. */
+ private int inAcquireCnt;
+
+ /**
+ * Gets output stream.
+ *
+ * @return Object output stream.
+ */
+ OptimizedObjectOutputStream acquireOut() {
+ return outAcquireCnt++ > 0 ? createOut() : out;
+ }
+
+ /**
+ * Gets input stream.
+ *
+ * @return Object input stream.
+ */
+ OptimizedObjectInputStream acquireIn() {
+ return inAcquireCnt++ > 0 ? createIn() : in;
+ }
+
+ /**
+ * Releases output stream.
+ */
+ void releaseOut() {
+ outAcquireCnt--;
+ }
+
+ /**
+ * Releases input stream.
+ */
+ void releaseIn() {
+ inAcquireCnt--;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b5b8c3/modules/core/src/main/java/org/apache/ignite/marshaller/Marshaller.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/Marshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/Marshaller.java
index e99ca35..8ffeacd 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/Marshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/Marshaller.java
@@ -22,6 +22,7 @@ import java.io.OutputStream;
import org.apache.ignite.IgniteBinary;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
import org.jetbrains.annotations.Nullable;
/**
@@ -33,7 +34,7 @@ import org.jetbrains.annotations.Nullable;
* <ul>
* <li>Default binary marshaller. Will be used when no other marshaller is explicitly set to the
* configuration. For more information, see {@link IgniteBinary}.</li>
- * <li>{@link org.apache.ignite.marshaller.optimized.OptimizedMarshaller}</li>
+ * <li>{@link OptimizedMarshaller}</li>
* <li>{@link org.apache.ignite.marshaller.jdk.JdkMarshaller}</li>
* </ul>
* <p>
http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b5b8c3/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
index 2ecdc8e..8c27841 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
@@ -22,6 +22,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
import org.apache.ignite.internal.util.io.GridByteArrayInputStream;
import org.apache.ignite.internal.util.io.GridByteArrayOutputStream;
import org.apache.ignite.internal.util.typedef.internal.S;
@@ -36,7 +37,7 @@ import org.jetbrains.annotations.Nullable;
* <h2 class="header">Mandatory</h2>
* This marshaller has no mandatory configuration parameters.
* <h2 class="header">Java Example</h2>
- * {@code JdkMarshaller} needs to be explicitly configured to override default {@link org.apache.ignite.marshaller.optimized.OptimizedMarshaller}.
+ * {@code JdkMarshaller} needs to be explicitly configured to override default {@link OptimizedMarshaller}.
* <pre name="code" class="java">
* JdkMarshaller marshaller = new JdkMarshaller();
*