http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java new file mode 100644 index 0000000..83dd01d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java @@ -0,0 +1,1089 @@ +/* + * 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.portable; + +import org.apache.ignite.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.processors.cache.portable.*; +import org.apache.ignite.internal.util.*; +import org.apache.ignite.internal.util.lang.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.marshaller.*; +import org.apache.ignite.marshaller.optimized.*; +import org.apache.ignite.marshaller.portable.*; +import org.apache.ignite.portable.*; + +import org.jetbrains.annotations.*; +import org.jsr166.*; + +import java.io.*; +import java.math.*; +import java.net.*; +import java.sql.*; +import java.util.*; +import java.util.Date; +import java.util.concurrent.*; +import java.util.jar.*; + +/** + * Portable context. + */ +public class PortableContext implements Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + static final PortableIdMapper DFLT_ID_MAPPER = new IdMapperWrapper(null); + + /** */ + static final PortableIdMapper BASIC_CLS_ID_MAPPER = new BasicClassIdMapper(); + + /** */ + static final char[] LOWER_CASE_CHARS; + + /** */ + static final char MAX_LOWER_CASE_CHAR = 0x7e; + + /** + * + */ + static { + LOWER_CASE_CHARS = new char[MAX_LOWER_CASE_CHAR + 1]; + + for (char c = 0; c <= MAX_LOWER_CASE_CHAR; c++) + LOWER_CASE_CHARS[c] = Character.toLowerCase(c); + } + + /** */ + private final ConcurrentMap<Integer, Collection<Integer>> metaDataCache = new ConcurrentHashMap8<>(); + + /** */ + private final ConcurrentMap<Class<?>, PortableClassDescriptor> descByCls = new ConcurrentHashMap8<>(); + + /** */ + private final ConcurrentMap<Integer, PortableClassDescriptor> userTypes = new ConcurrentHashMap8<>(0); + + /** */ + private final Map<Integer, PortableClassDescriptor> predefinedTypes = new HashMap<>(); + + /** */ + private final Set<Class> predefinedClasses = new HashSet<>(); + + /** */ + private final Map<Class<? extends Collection>, Byte> colTypes = new HashMap<>(); + + /** */ + private final Map<Class<? extends Map>, Byte> mapTypes = new HashMap<>(); + + /** */ + private final Map<Integer, PortableIdMapper> mappers = new ConcurrentHashMap8<>(0); + + /** */ + private final Map<String, PortableIdMapper> typeMappers = new ConcurrentHashMap8<>(0); + + /** */ + private Map<Integer, Boolean> metaEnabled = new HashMap<>(0); + + /** */ + private Set<Integer> usingTs = new HashSet<>(); + + /** */ + private PortableMetaDataHandler metaHnd; + + /** */ + private MarshallerContext marshCtx; + + /** */ + private String gridName; + + /** */ + private PortableMarshaller marsh; + + /** */ + private final OptimizedMarshaller optmMarsh = new OptimizedMarshaller(); + + /** + * For {@link Externalizable}. + */ + public PortableContext() { + // No-op. + } + + /** + * @param metaHnd Meta data handler. + * @param gridName Grid name. + */ + public PortableContext(PortableMetaDataHandler metaHnd, @Nullable String gridName) { + assert metaHnd != null; + + this.metaHnd = metaHnd; + this.gridName = gridName; + + colTypes.put(ArrayList.class, GridPortableMarshaller.ARR_LIST); + colTypes.put(LinkedList.class, GridPortableMarshaller.LINKED_LIST); + colTypes.put(HashSet.class, GridPortableMarshaller.HASH_SET); + colTypes.put(LinkedHashSet.class, GridPortableMarshaller.LINKED_HASH_SET); + colTypes.put(TreeSet.class, GridPortableMarshaller.TREE_SET); + colTypes.put(ConcurrentSkipListSet.class, GridPortableMarshaller.CONC_SKIP_LIST_SET); + + mapTypes.put(HashMap.class, GridPortableMarshaller.HASH_MAP); + mapTypes.put(LinkedHashMap.class, GridPortableMarshaller.LINKED_HASH_MAP); + mapTypes.put(TreeMap.class, GridPortableMarshaller.TREE_MAP); + mapTypes.put(ConcurrentHashMap.class, GridPortableMarshaller.CONC_HASH_MAP); + mapTypes.put(ConcurrentHashMap8.class, GridPortableMarshaller.CONC_HASH_MAP); + mapTypes.put(Properties.class, GridPortableMarshaller.PROPERTIES_MAP); + + registerPredefinedType(Byte.class, GridPortableMarshaller.BYTE); + registerPredefinedType(Boolean.class, GridPortableMarshaller.BOOLEAN); + registerPredefinedType(Short.class, GridPortableMarshaller.SHORT); + registerPredefinedType(Character.class, GridPortableMarshaller.CHAR); + registerPredefinedType(Integer.class, GridPortableMarshaller.INT); + registerPredefinedType(Long.class, GridPortableMarshaller.LONG); + registerPredefinedType(Float.class, GridPortableMarshaller.FLOAT); + registerPredefinedType(Double.class, GridPortableMarshaller.DOUBLE); + registerPredefinedType(String.class, GridPortableMarshaller.STRING); + registerPredefinedType(BigDecimal.class, GridPortableMarshaller.DECIMAL); + registerPredefinedType(Date.class, GridPortableMarshaller.DATE); + registerPredefinedType(UUID.class, GridPortableMarshaller.UUID); + // TODO: How to handle timestamp? It has the same ID in .Net. + registerPredefinedType(Timestamp.class, GridPortableMarshaller.DATE); + + registerPredefinedType(byte[].class, GridPortableMarshaller.BYTE_ARR); + registerPredefinedType(short[].class, GridPortableMarshaller.SHORT_ARR); + registerPredefinedType(int[].class, GridPortableMarshaller.INT_ARR); + registerPredefinedType(long[].class, GridPortableMarshaller.LONG_ARR); + registerPredefinedType(float[].class, GridPortableMarshaller.FLOAT_ARR); + registerPredefinedType(double[].class, GridPortableMarshaller.DOUBLE_ARR); + registerPredefinedType(char[].class, GridPortableMarshaller.CHAR_ARR); + registerPredefinedType(boolean[].class, GridPortableMarshaller.BOOLEAN_ARR); + registerPredefinedType(BigDecimal[].class, GridPortableMarshaller.DECIMAL_ARR); + registerPredefinedType(String[].class, GridPortableMarshaller.STRING_ARR); + registerPredefinedType(UUID[].class, GridPortableMarshaller.UUID_ARR); + registerPredefinedType(Date[].class, GridPortableMarshaller.DATE_ARR); + registerPredefinedType(Object[].class, GridPortableMarshaller.OBJ_ARR); + + registerPredefinedType(ArrayList.class, 0); + registerPredefinedType(LinkedList.class, 0); + registerPredefinedType(HashSet.class, 0); + registerPredefinedType(LinkedHashSet.class, 0); + registerPredefinedType(TreeSet.class, 0); + registerPredefinedType(ConcurrentSkipListSet.class, 0); + + registerPredefinedType(HashMap.class, 0); + registerPredefinedType(LinkedHashMap.class, 0); + registerPredefinedType(TreeMap.class, 0); + registerPredefinedType(ConcurrentHashMap.class, 0); + registerPredefinedType(ConcurrentHashMap8.class, 0); + + registerPredefinedType(GridMapEntry.class, 60); + registerPredefinedType(IgniteBiTuple.class, 61); + registerPredefinedType(T2.class, 62); + + registerPredefinedType(PortableObjectImpl.class, 63); + + registerPredefinedType(PortableMetaDataImpl.class, 64); + +// TODO: IGNITE-1258 +// registerPredefinedType(DrSenderAttributes.class, 65); +// registerPredefinedType(DrSenderRemoteAttributes.class, 66); +// +// registerPredefinedType(InteropClusterNode.class, 67); +// registerPredefinedType(InteropClusterMetrics.class, 68); +// registerPredefinedType(InteropTransactionMetrics.class, 69); +// registerPredefinedType(InteropMetadata.class, 70); +// +// registerPredefinedType(InteropDotNetConfiguration.class, 71); +// registerPredefinedType(InteropDotNetPortableConfiguration.class, 72); +// registerPredefinedType(InteropDotNetPortableTypeConfiguration.class, 73); +// registerPredefinedType(InteropIgniteProxy.class, 74); +// registerPredefinedType(InteropCacheMetrics.class, 75); +// registerPredefinedType(InteropProductLicence.class, 78); + } + + /** + * @param marsh Portable marshaller. + * @throws PortableException In case of error. + */ + public void configure(PortableMarshaller marsh) throws PortableException { + if (marsh == null) + return; + + this.marsh = marsh; + marshCtx = marsh.getContext(); + + assert marshCtx != null; + + optmMarsh.setContext(marshCtx); + + PortableIdMapper globalIdMapper = marsh.getIdMapper(); + PortableSerializer globalSerializer = marsh.getSerializer(); + boolean globalUseTs = marsh.isUseTimestamp(); + boolean globalMetaDataEnabled = marsh.isMetaDataEnabled(); + boolean globalKeepDeserialized = marsh.isKeepDeserialized(); + + TypeDescriptors descs = new TypeDescriptors(); + + if (marsh.getClassNames() != null) { + PortableIdMapper idMapper = new IdMapperWrapper(globalIdMapper); + + for (String clsName : marsh.getClassNames()) { + if (clsName.endsWith(".*")) { // Package wildcard + String pkgName = clsName.substring(0, clsName.length() - 2); + + for (String clsName0 : classesInPackage(pkgName)) + descs.add(clsName0, idMapper, null, null, globalUseTs, globalMetaDataEnabled, + globalKeepDeserialized, true); + } + else // Regular single class + descs.add(clsName, idMapper, null, null, globalUseTs, globalMetaDataEnabled, + globalKeepDeserialized, true); + } + } + + if (marsh.getTypeConfigurations() != null) { + for (PortableTypeConfiguration typeCfg : marsh.getTypeConfigurations()) { + String clsName = typeCfg.getClassName(); + + if (clsName == null) + throw new PortableException("Class name is required for portable type configuration."); + + PortableIdMapper idMapper = globalIdMapper; + + if (typeCfg.getIdMapper() != null) + idMapper = typeCfg.getIdMapper(); + + idMapper = new IdMapperWrapper(idMapper); + + PortableSerializer serializer = globalSerializer; + + if (typeCfg.getSerializer() != null) + serializer = typeCfg.getSerializer(); + + boolean useTs = typeCfg.isUseTimestamp() != null ? typeCfg.isUseTimestamp() : globalUseTs; + boolean metaDataEnabled = typeCfg.isMetaDataEnabled() != null ? typeCfg.isMetaDataEnabled() : + globalMetaDataEnabled; + boolean keepDeserialized = typeCfg.isKeepDeserialized() != null ? typeCfg.isKeepDeserialized() : + globalKeepDeserialized; + + if (clsName.endsWith(".*")) { + String pkgName = clsName.substring(0, clsName.length() - 2); + + for (String clsName0 : classesInPackage(pkgName)) + descs.add(clsName0, idMapper, serializer, typeCfg.getAffinityKeyFieldName(), useTs, + metaDataEnabled, keepDeserialized, true); + } + else + descs.add(clsName, idMapper, serializer, typeCfg.getAffinityKeyFieldName(), useTs, + metaDataEnabled, keepDeserialized, false); + } + } + + for (TypeDescriptor desc : descs.descriptors()) + registerUserType(desc.clsName, desc.idMapper, desc.serializer, desc.affKeyFieldName, desc.useTs, + desc.metadataEnabled, desc.keepDeserialized); + } + + /** + * @param pkgName Package name. + * @return Class names. + */ + @SuppressWarnings("ConstantConditions") + private static Iterable<String> classesInPackage(String pkgName) { + assert pkgName != null; + + Collection<String> clsNames = new ArrayList<>(); + + ClassLoader ldr = U.gridClassLoader(); + + if (ldr instanceof URLClassLoader) { + String pkgPath = pkgName.replaceAll("\\.", "/"); + + URL[] urls = ((URLClassLoader)ldr).getURLs(); + + for (URL url : urls) { + String proto = url.getProtocol().toLowerCase(); + + if ("file".equals(proto)) { + try { + File cpElement = new File(url.toURI()); + + if (cpElement.isDirectory()) { + File pkgDir = new File(cpElement, pkgPath); + + if (pkgDir.isDirectory()) { + for (File file : pkgDir.listFiles()) { + String fileName = file.getName(); + + if (file.isFile() && fileName.toLowerCase().endsWith(".class")) + clsNames.add(pkgName + '.' + fileName.substring(0, fileName.length() - 6)); + } + } + } + else if (cpElement.isFile()) { + try { + JarFile jar = new JarFile(cpElement); + + Enumeration<JarEntry> entries = jar.entries(); + + while (entries.hasMoreElements()) { + String entry = entries.nextElement().getName(); + + if (entry.startsWith(pkgPath) && entry.endsWith(".class")) { + String clsName = entry.substring(pkgPath.length() + 1, entry.length() - 6); + + if (!clsName.contains("/") && !clsName.contains("\\")) + clsNames.add(pkgName + '.' + clsName); + } + } + } + catch (IOException ignored) { + // No-op. + } + } + } + catch (URISyntaxException ignored) { + // No-op. + } + } + } + } + + return clsNames; + } + + /** + * @param cls Class. + * @return Class descriptor. + * @throws PortableException In case of error. + */ + public PortableClassDescriptor descriptorForClass(Class<?> cls) + throws PortableException { + assert cls != null; + + PortableClassDescriptor desc = descByCls.get(cls); + + if (desc == null || !desc.isRegistered()) + desc = registerClassDescriptor(cls); + + return desc; + } + + /** + * @param userType User type or not. + * @param typeId Type ID. + * @param ldr Class loader. + * @return Class descriptor. + */ + public PortableClassDescriptor descriptorForTypeId(boolean userType, int typeId, ClassLoader ldr) { + assert typeId != GridPortableMarshaller.UNREGISTERED_TYPE_ID; + + PortableClassDescriptor desc = userType ? userTypes.get(typeId) : predefinedTypes.get(typeId); + + if (desc != null) + return desc; + + Class cls; + + try { + cls = marshCtx.getClass(typeId, ldr); + + desc = descByCls.get(cls); + } + catch (ClassNotFoundException e) { + throw new PortableInvalidClassException(e); + } + catch (IgniteCheckedException e) { + throw new PortableException("Failed resolve class for ID: " + typeId, e); + } + + if (desc == null) { + desc = registerClassDescriptor(cls); + + assert desc.typeId() == typeId; + } + + return desc; + } + + /** + * Creates and registers {@link PortableClassDescriptor} for the given {@code class}. + * + * @param cls Class. + * @return Class descriptor. + */ + private PortableClassDescriptor registerClassDescriptor(Class<?> cls) { + PortableClassDescriptor desc; + + String clsName = cls.getName(); + + if (marshCtx.isSystemType(clsName)) { + desc = new PortableClassDescriptor(this, + cls, + false, + clsName.hashCode(), + clsName, + BASIC_CLS_ID_MAPPER, + null, + marsh.isUseTimestamp(), + marsh.isMetaDataEnabled(), + marsh.isKeepDeserialized()); + + PortableClassDescriptor old = descByCls.putIfAbsent(cls, desc); + + if (old != null) + desc = old; + } + else + desc = registerUserClassDescriptor(cls); + + return desc; + } + + /** + * Creates and registers {@link PortableClassDescriptor} for the given user {@code class}. + * + * @param cls Class. + * @return Class descriptor. + */ + private PortableClassDescriptor registerUserClassDescriptor(Class<?> cls) { + PortableClassDescriptor desc; + + boolean registered; + + String typeName = typeName(cls.getName()); + + PortableIdMapper idMapper = idMapper(typeName); + + int typeId = idMapper.typeId(typeName); + + try { + registered = marshCtx.registerClass(typeId, cls); + + } catch (IgniteCheckedException e) { + throw new PortableException("Failed to register class.", e); + } + + desc = new PortableClassDescriptor(this, + cls, + true, + typeId, + typeName, + idMapper, + null, + marsh.isUseTimestamp(), + marsh.isMetaDataEnabled(), + marsh.isKeepDeserialized(), + registered); + + // perform put() instead of putIfAbsent() because "registered" flag may have been changed. + userTypes.put(typeId, desc); + descByCls.put(cls, desc); + + return desc; + } + + /** + * @param cls Collection class. + * @return Collection type ID. + */ + public byte collectionType(Class<? extends Collection> cls) { + assert cls != null; + + Byte type = colTypes.get(cls); + + if (type != null) + return type; + + return Set.class.isAssignableFrom(cls) ? GridPortableMarshaller.USER_SET : GridPortableMarshaller.USER_COL; + } + + /** + * @param cls Map class. + * @return Map type ID. + */ + public byte mapType(Class<? extends Map> cls) { + assert cls != null; + + Byte type = mapTypes.get(cls); + + return type != null ? type : GridPortableMarshaller.USER_COL; + } + + /** + * @param typeName Type name. + * @return Type ID. + */ + public int typeId(String typeName) { + int id; + + if (marshCtx.isSystemType(typeName)) + id = typeName.hashCode(); + + else { + typeName = typeName(typeName); + + id = idMapper(typeName).typeId(typeName); + } + + return id; + } + + /** + * @param cls Class. + * @return Type ID. + * @throws PortableException In case of error. + */ + public Type typeId(Class cls) throws PortableException { + String clsName = cls.getName(); + + if (marshCtx.isSystemType(clsName)) + return new Type(clsName.hashCode(), true); + + if (predefinedClasses.contains(cls)) + return new Type(DFLT_ID_MAPPER.typeId(typeName(clsName)), true); + + PortableClassDescriptor desc = descByCls.get(cls); + + boolean registered = desc != null && desc.isRegistered(); + + if (!registered) + // forces to register the class and fill up all required data structures + desc = registerUserClassDescriptor(cls); + + return new Type(desc.typeId(), desc.isRegistered()); + } + + /** + * @param typeId Type ID. + * @param fieldName Field name. + * @return Field ID. + */ + public int fieldId(int typeId, String fieldName) { + return idMapper(typeId).fieldId(typeId, fieldName); + } + + /** + * @param typeId Type ID. + * @return Instance of ID mapper. + */ + public PortableIdMapper idMapper(int typeId) { + PortableIdMapper idMapper = mappers.get(typeId); + + if (idMapper != null) + return idMapper; + + if (userTypes.containsKey(typeId) || predefinedTypes.containsKey(typeId)) + return DFLT_ID_MAPPER; + + return BASIC_CLS_ID_MAPPER; + } + + /** + * @param typeName Type name. + * @return Instance of ID mapper. + */ + private PortableIdMapper idMapper(String typeName) { + PortableIdMapper idMapper = typeMappers.get(typeName); + + return idMapper != null ? idMapper : DFLT_ID_MAPPER; + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + U.writeString(out, gridName); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + gridName = U.readString(in); + } + + /** + * @return Portable context. + * @throws ObjectStreamException In case of error. + */ + protected Object readResolve() throws ObjectStreamException { + try { + IgniteKernal g = IgnitionEx.gridx(gridName); + + if (g == null) + throw new IllegalStateException("Failed to find grid for name: " + gridName); + + return ((CacheObjectPortableProcessorImpl)g.context().cacheObjects()).portableContext(); + } + catch (IllegalStateException e) { + throw U.withCause(new InvalidObjectException(e.getMessage()), e); + } + } + + /** + * @param cls Class. + * @param id Type ID. + * @return PortableClassDescriptor. + */ + private PortableClassDescriptor registerPredefinedType(Class<?> cls, int id) { + PortableClassDescriptor desc = new PortableClassDescriptor( + this, + cls, + false, + id, + typeName(cls.getName()), + DFLT_ID_MAPPER, + null, + false, + false, + false + ); + + predefinedClasses.add(cls); + + predefinedTypes.put(id, desc); + descByCls.put(cls, desc); + + return desc; + } + + /** + * @param clsName Class name. + * @param idMapper ID mapper. + * @param serializer Serializer. + * @param affKeyFieldName Affinity key field name. + * @param useTs Use timestamp flag. + * @param metaDataEnabled Metadata enabled flag. + * @param keepDeserialized Keep deserialized flag. + * @throws PortableException In case of error. + */ + @SuppressWarnings("ErrorNotRethrown") + public void registerUserType(String clsName, + PortableIdMapper idMapper, + @Nullable PortableSerializer serializer, + @Nullable String affKeyFieldName, + boolean useTs, + boolean metaDataEnabled, + boolean keepDeserialized) + throws PortableException { + assert idMapper != null; + + Class<?> cls = null; + + try { + cls = Class.forName(clsName); + } + catch (ClassNotFoundException | NoClassDefFoundError ignored) { + // No-op. + } + + int id = idMapper.typeId(clsName); + + if (mappers.put(id, idMapper) != null) + throw new PortableException("Duplicate type ID [clsName=" + clsName + ", id=" + id + ']'); + + if (useTs) + usingTs.add(id); + + String typeName = typeName(clsName); + + typeMappers.put(typeName, idMapper); + + metaEnabled.put(id, metaDataEnabled); + + Map<String, String> fieldsMeta = null; + + if (cls != null) { + PortableClassDescriptor desc = new PortableClassDescriptor( + this, + cls, + true, + id, + typeName, + idMapper, + serializer, + useTs, + metaDataEnabled, + keepDeserialized); + + fieldsMeta = desc.fieldsMeta(); + + userTypes.put(id, desc); + descByCls.put(cls, desc); + } + + metaHnd.addMeta(id, new PortableMetaDataImpl(typeName, fieldsMeta, affKeyFieldName)); + } + + /** + * @param typeId Type ID. + * @return Meta data. + * @throws PortableException In case of error. + */ + @Nullable public PortableMetadata metaData(int typeId) throws PortableException { + return metaHnd != null ? metaHnd.metadata(typeId) : null; + } + + /** + * @return Whether meta data is globally enabled. + */ + boolean isMetaDataEnabled() { + return marsh.isMetaDataEnabled(); + } + + /** + * @param typeId Type ID. + * @return Whether meta data is enabled. + */ + boolean isMetaDataEnabled(int typeId) { + Boolean enabled = metaEnabled.get(typeId); + + return enabled != null ? enabled : true; + } + + /** + * @param typeId Type ID. + * @param metaHashSum Meta data hash sum. + * @return Whether meta is changed. + */ + boolean isMetaDataChanged(int typeId, @Nullable Integer metaHashSum) { + if (metaHashSum == null) + return false; + + Collection<Integer> hist = metaDataCache.get(typeId); + + if (hist == null) { + Collection<Integer> old = metaDataCache.putIfAbsent(typeId, hist = new GridConcurrentHashSet<>()); + + if (old != null) + hist = old; + } + + return hist.add(metaHashSum); + } + + /** + * @param typeId Type ID. + * @param typeName Type name. + * @param fields Fields map. + * @throws PortableException In case of error. + */ + void updateMetaData(int typeId, String typeName, Map<String, String> fields) throws PortableException { + updateMetaData(typeId, new PortableMetaDataImpl(typeName, fields, null)); + } + + /** + * @param typeId Type ID. + * @param meta Meta data. + * @throws PortableException In case of error. + */ + public void updateMetaData(int typeId, PortableMetaDataImpl meta) throws PortableException { + metaHnd.addMeta(typeId, meta); + } + + /** + * @return Use timestamp flag. + */ + public boolean isUseTimestamp() { + return marsh.isUseTimestamp(); + } + + /** + * @param typeId Type ID. + * @return If timestamp used. + */ + public boolean isUseTimestamp(int typeId) { + return usingTs.contains(typeId); + } + + /** + * @return Whether to convert string to UTF8 bytes. + */ + public boolean isConvertString() { + return marsh.isConvertStringToBytes(); + } + + /** + * Returns whether {@code cls} is predefined in the context or not. + * + * @param cls Class. + * @return {@code true} if predefined, {@code false} otherwise. + */ + public boolean isPredefinedClass(Class<?> cls) { + return predefinedClasses.contains(cls); + } + + /** + * Returns instance of {@link OptimizedMarshaller}. + * + * @return Optimized marshaller. + */ + OptimizedMarshaller optimizedMarsh() { + return optmMarsh; + } + + /** + * @param clsName Class name. + * @return Type name. + */ + public static String typeName(String clsName) { + assert clsName != null; + + int idx = clsName.lastIndexOf('$'); + + String typeName; + + if (idx >= 0) { + typeName = clsName.substring(idx + 1); + + try { + Integer.parseInt(typeName); + + // This is an anonymous class. Don't cut off enclosing class name for it. + idx = -1; + } + catch (NumberFormatException e) { + return typeName; + } + } + + if (idx < 0) + idx = clsName.lastIndexOf('.'); + + return idx >= 0 ? clsName.substring(idx + 1) : clsName; + } + + /** + * @param str String. + * @return Hash code for given string converted to lower case. + */ + private static int lowerCaseHashCode(String str) { + int len = str.length(); + + int h = 0; + + for (int i = 0; i < len; i++) { + int c = str.charAt(i); + + c = c <= MAX_LOWER_CASE_CHAR ? LOWER_CASE_CHARS[c] : Character.toLowerCase(c); + + h = 31 * h + c; + } + + return h; + } + + /** + */ + private static class IdMapperWrapper implements PortableIdMapper { + /** */ + private final PortableIdMapper mapper; + + /** + * @param mapper Custom ID mapper. + */ + private IdMapperWrapper(@Nullable PortableIdMapper mapper) { + this.mapper = mapper; + } + + /** {@inheritDoc} */ + @Override public int typeId(String clsName) { + int id = 0; + + if (mapper != null) + id = mapper.typeId(clsName); + + return id != 0 ? id : lowerCaseHashCode(typeName(clsName)); + } + + /** {@inheritDoc} */ + @Override public int fieldId(int typeId, String fieldName) { + int id = 0; + + if (mapper != null) + id = mapper.fieldId(typeId, fieldName); + + return id != 0 ? id : lowerCaseHashCode(fieldName); + } + } + + private static class BasicClassIdMapper implements PortableIdMapper { + /** {@inheritDoc} */ + @Override public int typeId(String clsName) { + return clsName.hashCode(); + } + + /** {@inheritDoc} */ + @Override public int fieldId(int typeId, String fieldName) { + return lowerCaseHashCode(fieldName); + } + } + /** + * Type descriptors. + */ + private static class TypeDescriptors { + /** Descriptors map. */ + private final Map<String, TypeDescriptor> descs = new HashMap<>(); + + /** + * Add type descriptor. + * + * @param clsName Class name. + * @param idMapper ID mapper. + * @param serializer Serializer. + * @param affKeyFieldName Affinity key field name. + * @param useTs Use timestamp flag. + * @param metadataEnabled Metadata enabled flag. + * @param keepDeserialized Keep deserialized flag. + * @param canOverride Whether this descriptor can be override. + * @throws PortableException If failed. + */ + private void add(String clsName, + PortableIdMapper idMapper, + PortableSerializer serializer, + String affKeyFieldName, + boolean useTs, + boolean metadataEnabled, + boolean keepDeserialized, + boolean canOverride) + throws PortableException { + TypeDescriptor desc = new TypeDescriptor(clsName, + idMapper, + serializer, + affKeyFieldName, + useTs, + metadataEnabled, + keepDeserialized, + canOverride); + + TypeDescriptor oldDesc = descs.get(clsName); + + if (oldDesc == null) + descs.put(clsName, desc); + else + oldDesc.override(desc); + } + + /** + * Get all collected descriptors. + * + * @return Descriptors. + */ + private Iterable<TypeDescriptor> descriptors() { + return descs.values(); + } + } + + /** + * Type descriptor. + */ + private static class TypeDescriptor { + /** Class name. */ + private final String clsName; + + /** ID mapper. */ + private PortableIdMapper idMapper; + + /** Serializer. */ + private PortableSerializer serializer; + + /** Affinity key field name. */ + private String affKeyFieldName; + + /** Use timestamp flag. */ + private boolean useTs; + + /** Metadata enabled flag. */ + private boolean metadataEnabled; + + /** Keep deserialized flag. */ + private boolean keepDeserialized; + + /** Whether this descriptor can be override. */ + private boolean canOverride; + + /** + * Constructor. + * + * @param clsName Class name. + * @param idMapper ID mapper. + * @param serializer Serializer. + * @param affKeyFieldName Affinity key field name. + * @param useTs Use timestamp flag. + * @param metadataEnabled Metadata enabled flag. + * @param keepDeserialized Keep deserialized flag. + * @param canOverride Whether this descriptor can be override. + */ + private TypeDescriptor(String clsName, PortableIdMapper idMapper, PortableSerializer serializer, + String affKeyFieldName, boolean useTs, boolean metadataEnabled, boolean keepDeserialized, + boolean canOverride) { + this.clsName = clsName; + this.idMapper = idMapper; + this.serializer = serializer; + this.affKeyFieldName = affKeyFieldName; + this.useTs = useTs; + this.metadataEnabled = metadataEnabled; + this.keepDeserialized = keepDeserialized; + this.canOverride = canOverride; + } + + /** + * Override portable class descriptor. + * + * @param other Other descriptor. + * @throws PortableException If failed. + */ + private void override(TypeDescriptor other) throws PortableException { + assert clsName.equals(other.clsName); + + if (canOverride) { + idMapper = other.idMapper; + serializer = other.serializer; + affKeyFieldName = other.affKeyFieldName; + useTs = other.useTs; + metadataEnabled = other.metadataEnabled; + keepDeserialized = other.keepDeserialized; + canOverride = other.canOverride; + } + else if (!other.canOverride) + throw new PortableException("Duplicate explicit class definition in configuration: " + clsName); + } + } + + /** + * Type id wrapper. + */ + static class Type { + /** Type id*/ + private int id; + + /** Whether the following type is registered in a cache or not */ + private boolean registered; + + public Type(int id, boolean registered) { + this.id = id; + this.registered = registered; + } + + public int id() { + return id; + } + + public boolean registered() { + return registered; + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableEnumArrayLazyValue.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableEnumArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableEnumArrayLazyValue.java new file mode 100644 index 0000000..8d4c80a --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableEnumArrayLazyValue.java @@ -0,0 +1,111 @@ +/* + * 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.portable; + +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.portable.*; + +/** + * + */ +class PortableEnumArrayLazyValue extends PortableAbstractLazyValue { + /** */ + private final int len; + + /** */ + private final int compTypeId; + + /** */ + private final String clsName; + + /** + * @param reader Reader. + */ + protected PortableEnumArrayLazyValue(PortableBuilderReader reader) { + super(reader, reader.position() - 1); + + int typeId = reader.readInt(); + + if (typeId == GridPortableMarshaller.UNREGISTERED_TYPE_ID) { + clsName = reader.readString(); + + Class cls; + + try { + // TODO: GG-10396 - Is class loader needed here? + cls = U.forName(reader.readString(), null); + } + catch (ClassNotFoundException e) { + throw new PortableInvalidClassException("Failed to load the class: " + clsName, e); + } + + compTypeId = reader.portableContext().descriptorForClass(cls).typeId(); + } + else { + compTypeId = typeId; + clsName = null; + } + + int size = reader.readInt(); + + for (int i = 0; i < size; i++) + reader.skipValue(); + + len = reader.position() - valOff; + } + + /** {@inheritDoc} */ + @Override protected Object init() { + reader.position(valOff + 1); + + //skipping component type id + reader.readInt(); + + int size = reader.readInt(); + + PortableBuilderEnum[] res = new PortableBuilderEnum[size]; + + for (int i = 0; i < size; i++) { + byte flag = reader.readByte(); + + if (flag == GridPortableMarshaller.NULL) + continue; + + if (flag != GridPortableMarshaller.ENUM) + throw new PortableException("Invalid flag value: " + flag); + + res[i] = new PortableBuilderEnum(reader); + } + + return res; + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + if (val != null) { + if (clsName != null) + ctx.writeArray(writer, GridPortableMarshaller.ENUM_ARR, (Object[])val, clsName); + else + ctx.writeArray(writer, GridPortableMarshaller.ENUM_ARR, (Object[])val, compTypeId); + + return; + } + + writer.write(reader.array(), valOff, len); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyArrayList.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyArrayList.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyArrayList.java new file mode 100644 index 0000000..56dfba9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyArrayList.java @@ -0,0 +1,156 @@ +/* + * 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.portable; + +import java.util.*; + +/** + * + */ +class PortableLazyArrayList extends AbstractList<Object> implements PortableBuilderSerializationAware { + /** */ + private final PortableBuilderReader reader; + + /** */ + private final int off; + + /** */ + private List<Object> delegate; + + /** + * @param reader Reader. + * @param size Size, + */ + PortableLazyArrayList(PortableBuilderReader reader, int size) { + this.reader = reader; + off = reader.position() - 1/* flag */ - 4/* size */ - 1/* col type */; + + assert size >= 0; + + for (int i = 0; i < size; i++) + reader.skipValue(); + } + + /** + * + */ + private void ensureDelegateInit() { + if (delegate == null) { + int size = reader.readIntAbsolute(off + 1); + + reader.position(off + 1/* flag */ + 4/* size */ + 1/* col type */); + + delegate = new ArrayList<>(size); + + for (int i = 0; i < size; i++) + delegate.add(reader.parseValue()); + } + } + + /** {@inheritDoc} */ + @Override public Object get(int idx) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.get(idx)); + } + + /** {@inheritDoc} */ + @Override public boolean add(Object o) { + ensureDelegateInit(); + + return delegate.add(o); + } + + /** {@inheritDoc} */ + @Override public void add(int idx, Object element) { + ensureDelegateInit(); + + delegate.add(idx, element); + } + + /** {@inheritDoc} */ + @Override public Object set(int idx, Object element) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.set(idx, element)); + } + + /** {@inheritDoc} */ + @Override public Object remove(int idx) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.remove(idx)); + } + + /** {@inheritDoc} */ + @Override public void clear() { + if (delegate == null) + delegate = new ArrayList<>(); + else + delegate.clear(); + } + + /** {@inheritDoc} */ + @Override public boolean addAll(int idx, Collection<?> c) { + return delegate.addAll(idx, c); + } + + /** {@inheritDoc} */ + @Override protected void removeRange(int fromIdx, int toIdx) { + ensureDelegateInit(); + + delegate.subList(fromIdx, toIdx).clear(); + } + + /** {@inheritDoc} */ + @Override public int size() { + if (delegate == null) + return reader.readIntAbsolute(off + 1); + + return delegate.size(); + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + if (delegate == null) { + int size = reader.readIntAbsolute(off + 1); + + int hdrSize = 1 /* flag */ + 4 /* size */ + 1 /* col type */; + + writer.write(reader.array(), off, hdrSize); + + reader.position(off + hdrSize); + + for (int i = 0; i < size; i++) { + Object o = reader.parseValue(); + + ctx.writeValue(writer, o); + } + } + else { + writer.writeByte(GridPortableMarshaller.COL); + writer.writeInt(delegate.size()); + + byte colType = reader.array()[off + 1 /* flag */ + 4 /* size */]; + writer.writeByte(colType); + + for (Object o : delegate) + ctx.writeValue(writer, o); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyLinkedList.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyLinkedList.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyLinkedList.java new file mode 100644 index 0000000..9395aeb --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyLinkedList.java @@ -0,0 +1,210 @@ +/* + * 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.portable; + +import java.util.*; + +/** + * + */ +class PortableLazyLinkedList extends AbstractList<Object> implements PortableBuilderSerializationAware { + /** */ + private final PortableBuilderReader reader; + + /** */ + private final int off; + + /** */ + private List<Object> delegate; + + /** + * @param reader Reader. + * @param size Size, + */ + PortableLazyLinkedList(PortableBuilderReader reader, int size) { + this.reader = reader; + off = reader.position() - 1/* flag */ - 4/* size */ - 1/* col type */; + + assert size >= 0; + + for (int i = 0; i < size; i++) + reader.skipValue(); + } + + /** + * + */ + private void ensureDelegateInit() { + if (delegate == null) { + int size = reader.readIntAbsolute(off + 1); + + reader.position(off + 1/* flag */ + 4/* size */ + 1/* col type */); + + delegate = new LinkedList<>(); + + for (int i = 0; i < size; i++) + delegate.add(reader.parseValue()); + } + } + + /** {@inheritDoc} */ + @Override public Object get(int idx) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.get(idx)); + } + + /** {@inheritDoc} */ + @Override public boolean add(Object o) { + ensureDelegateInit(); + + return delegate.add(o); + } + + /** {@inheritDoc} */ + @Override public void add(int idx, Object element) { + ensureDelegateInit(); + + delegate.add(idx, element); + } + + /** {@inheritDoc} */ + @Override public Object set(int idx, Object element) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.set(idx, element)); + } + + /** {@inheritDoc} */ + @Override public Object remove(int idx) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.remove(idx)); + } + + /** {@inheritDoc} */ + @Override public void clear() { + if (delegate == null) + delegate = new LinkedList<>(); + else + delegate.clear(); + } + + /** {@inheritDoc} */ + @Override public boolean addAll(int idx, Collection<?> c) { + ensureDelegateInit(); + + return delegate.addAll(idx, c); + } + + /** {@inheritDoc} */ + @Override protected void removeRange(int fromIdx, int toIdx) { + ensureDelegateInit(); + + delegate.subList(fromIdx, toIdx).clear(); + } + + /** {@inheritDoc} */ + @Override public int size() { + if (delegate == null) + return reader.readIntAbsolute(off + 1); + + return delegate.size(); + } + + /** {@inheritDoc} */ + @Override public ListIterator<Object> listIterator(final int idx) { + ensureDelegateInit(); + + return new ListIterator<Object>() { + /** */ + private final ListIterator<Object> delegate = PortableLazyLinkedList.super.listIterator(idx); + + @Override public boolean hasNext() { + return delegate.hasNext(); + } + + @Override public Object next() { + return PortableUtils.unwrapLazy(delegate.next()); + } + + @Override public boolean hasPrevious() { + return delegate.hasPrevious(); + } + + @Override public Object previous() { + return PortableUtils.unwrapLazy(delegate.previous()); + } + + @Override public int nextIndex() { + return delegate.nextIndex(); + } + + @Override public int previousIndex() { + return delegate.previousIndex(); + } + + @Override public void remove() { + delegate.remove(); + } + + @Override public void set(Object o) { + delegate.set(o); + } + + @Override public void add(Object o) { + delegate.add(o); + } + }; + } + + /** {@inheritDoc} */ + @Override public Iterator<Object> iterator() { + ensureDelegateInit(); + + return PortableUtils.unwrapLazyIterator(super.iterator()); + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + if (delegate == null) { + int size = reader.readIntAbsolute(off + 1); + + int hdrSize = 1 /* flag */ + 4 /* size */ + 1 /* col type */; + writer.write(reader.array(), off, hdrSize); + + reader.position(off + hdrSize); + + for (int i = 0; i < size; i++) { + Object o = reader.parseValue(); + + ctx.writeValue(writer, o); + } + } + else { + writer.writeByte(GridPortableMarshaller.COL); + writer.writeInt(delegate.size()); + + byte colType = reader.array()[off + 1 /* flag */ + 4 /* size */]; + writer.writeByte(colType); + + for (Object o : delegate) + ctx.writeValue(writer, o); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMap.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMap.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMap.java new file mode 100644 index 0000000..e7f7727 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMap.java @@ -0,0 +1,214 @@ +/* + * 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.portable; + +import org.jetbrains.annotations.*; + +import java.util.*; + +/** + * + */ +class PortableLazyMap extends AbstractMap<Object, Object> implements PortableBuilderSerializationAware { + /** */ + private final PortableBuilderReader reader; + + /** */ + private final int off; + + /** */ + private Map<Object, Object> delegate; + + /** + * @param reader Reader. + * @param off Offset. + */ + private PortableLazyMap(PortableBuilderReader reader, int off) { + this.reader = reader; + this.off = off; + } + + /** + * @param reader Reader. + * @return PortableLazyMap. + */ + @Nullable public static PortableLazyMap parseMap(PortableBuilderReader reader) { + int off = reader.position() - 1; + + int size = reader.readInt(); + + reader.skip(1); // map type. + + for (int i = 0; i < size; i++) { + reader.skipValue(); // skip key + reader.skipValue(); // skip value + } + + return new PortableLazyMap(reader, off); + } + + /** + * + */ + private void ensureDelegateInit() { + if (delegate == null) { + int size = reader.readIntAbsolute(off + 1); + + reader.position(off + 1/* flag */ + 4/* size */ + 1/* col type */); + + delegate = new LinkedHashMap<>(); + + for (int i = 0; i < size; i++) + delegate.put(PortableUtils.unwrapLazy(reader.parseValue()), reader.parseValue()); + } + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + if (delegate == null) { + int size = reader.readIntAbsolute(off + 1); + + int hdrSize = 1 /* flag */ + 4 /* size */ + 1 /* col type */; + writer.write(reader.array(), off, hdrSize); + + reader.position(off + hdrSize); + + for (int i = 0; i < size; i++) { + ctx.writeValue(writer, reader.parseValue()); // key + ctx.writeValue(writer, reader.parseValue()); // value + } + } + else { + writer.writeByte(GridPortableMarshaller.MAP); + writer.writeInt(delegate.size()); + + byte colType = reader.array()[off + 1 /* flag */ + 4 /* size */]; + + writer.writeByte(colType); + + for (Entry<Object, Object> entry : delegate.entrySet()) { + ctx.writeValue(writer, entry.getKey()); + ctx.writeValue(writer, entry.getValue()); + } + } + } + + /** {@inheritDoc} */ + @Override public int size() { + if (delegate == null) + return reader.readIntAbsolute(off + 1); + + return delegate.size(); + } + + /** {@inheritDoc} */ + @Override public boolean containsKey(Object key) { + ensureDelegateInit(); + + return delegate.containsKey(key); + } + + /** {@inheritDoc} */ + @Override public boolean containsValue(Object val) { + return values().contains(val); + } + + /** {@inheritDoc} */ + @Override public Set<Object> keySet() { + ensureDelegateInit(); + + return delegate.keySet(); + } + + /** {@inheritDoc} */ + @Override public void clear() { + if (delegate == null) + delegate = new LinkedHashMap<>(); + else + delegate.clear(); + } + + /** {@inheritDoc} */ + @Override public Object get(Object key) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.get(key)); + } + + /** {@inheritDoc} */ + @Override public Object put(Object key, Object val) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.put(key, val)); + } + + /** {@inheritDoc} */ + @Override public Object remove(Object key) { + ensureDelegateInit(); + + return PortableUtils.unwrapLazy(delegate.remove(key)); + } + + /** {@inheritDoc} */ + @Override public Set<Entry<Object, Object>> entrySet() { + ensureDelegateInit(); + + return new AbstractSet<Entry<Object, Object>>() { + @Override public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + @Override public Iterator<Entry<Object, Object>> iterator() { + return new Iterator<Entry<Object, Object>>() { + /** */ + private final Iterator<Entry<Object, Object>> itr = delegate.entrySet().iterator(); + + @Override public boolean hasNext() { + return itr.hasNext(); + } + + @Override public Entry<Object, Object> next() { + Entry<Object, Object> res = itr.next(); + + final Object val = res.getValue(); + + if (val instanceof PortableLazyValue) { + return new SimpleEntry<Object, Object>(res.getKey(), val) { + private static final long serialVersionUID = 0L; + + @Override public Object getValue() { + return ((PortableLazyValue)val).value(); + } + }; + } + + return res; + } + + @Override public void remove() { + itr.remove(); + } + }; + } + + @Override public int size() { + return delegate.size(); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMapEntry.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMapEntry.java new file mode 100644 index 0000000..389ab33 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyMapEntry.java @@ -0,0 +1,66 @@ +/* + * 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.portable; + +import java.util.*; + +/** + * + */ +class PortableLazyMapEntry implements Map.Entry<Object, Object>, PortableBuilderSerializationAware { + /** */ + private final Object key; + + /** */ + private Object val; + + /** + * @param reader GridMutablePortableReader + */ + PortableLazyMapEntry(PortableBuilderReader reader) { + key = reader.parseValue(); + val = reader.parseValue(); + } + + /** {@inheritDoc} */ + @Override public Object getKey() { + return PortableUtils.unwrapLazy(key); + } + + /** {@inheritDoc} */ + @Override public Object getValue() { + return PortableUtils.unwrapLazy(val); + } + + /** {@inheritDoc} */ + @Override public Object setValue(Object val) { + Object res = getValue(); + + this.val = val; + + return res; + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + writer.writeByte(GridPortableMarshaller.MAP_ENTRY); + + ctx.writeValue(writer, key); + ctx.writeValue(writer, val); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazySet.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazySet.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazySet.java new file mode 100644 index 0000000..d5a59a0 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazySet.java @@ -0,0 +1,89 @@ +/* + * 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.portable; + +import org.apache.ignite.internal.util.typedef.internal.*; + +import java.util.*; + +/** + * + */ +class PortableLazySet extends PortableAbstractLazyValue { + /** */ + private final int off; + + /** + * @param reader Reader. + * @param size Size. + */ + PortableLazySet(PortableBuilderReader reader, int size) { + super(reader, reader.position() - 1); + + off = reader.position() - 1/* flag */ - 4/* size */ - 1/* col type */; + + assert size >= 0; + + for (int i = 0; i < size; i++) + reader.skipValue(); + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + if (val == null) { + int size = reader.readIntAbsolute(off + 1); + + int hdrSize = 1 /* flag */ + 4 /* size */ + 1 /* col type */; + writer.write(reader.array(), off, hdrSize); + + reader.position(off + hdrSize); + + for (int i = 0; i < size; i++) { + Object o = reader.parseValue(); + + ctx.writeValue(writer, o); + } + } + else { + Collection<Object> c = (Collection<Object>)val; + + writer.writeByte(GridPortableMarshaller.COL); + writer.writeInt(c.size()); + + byte colType = reader.array()[off + 1 /* flag */ + 4 /* size */]; + writer.writeByte(colType); + + for (Object o : c) + ctx.writeValue(writer, o); + } + } + + /** {@inheritDoc} */ + @Override protected Object init() { + int size = reader.readIntAbsolute(off + 1); + + reader.position(off + 1/* flag */ + 4/* size */ + 1/* col type */); + + Set<Object> res = U.newLinkedHashSet(size); + + for (int i = 0; i < size; i++) + res.add(PortableUtils.unwrapLazy(reader.parseValue())); + + return res; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyValue.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyValue.java new file mode 100644 index 0000000..fcce4a5 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableLazyValue.java @@ -0,0 +1,28 @@ +/* + * 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.portable; + +/** + * + */ +interface PortableLazyValue extends PortableBuilderSerializationAware { + /** + * @return Value. + */ + public Object value(); +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataCollector.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataCollector.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataCollector.java new file mode 100644 index 0000000..30978ad --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataCollector.java @@ -0,0 +1,253 @@ +/* + * 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.portable; + +import org.apache.ignite.portable.*; + +import org.jetbrains.annotations.*; + +import java.lang.reflect.*; +import java.math.*; +import java.sql.*; +import java.util.*; +import java.util.Date; + +/** + * Writer for meta data collection. + */ +class PortableMetaDataCollector implements PortableWriter { + /** */ + private final Map<String, String> meta = new HashMap<>(); + + /** */ + private final String typeName; + + /** + * @param typeName Type name. + */ + PortableMetaDataCollector(String typeName) { + this.typeName = typeName; + } + + /** + * @return Field meta data. + */ + Map<String, String> meta() { + return meta; + } + + /** {@inheritDoc} */ + @Override public void writeByte(String fieldName, byte val) throws PortableException { + add(fieldName, byte.class); + } + + /** {@inheritDoc} */ + @Override public void writeShort(String fieldName, short val) throws PortableException { + add(fieldName, short.class); + } + + /** {@inheritDoc} */ + @Override public void writeInt(String fieldName, int val) throws PortableException { + add(fieldName, int.class); + } + + /** {@inheritDoc} */ + @Override public void writeLong(String fieldName, long val) throws PortableException { + add(fieldName, long.class); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(String fieldName, float val) throws PortableException { + add(fieldName, float.class); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(String fieldName, double val) throws PortableException { + add(fieldName, double.class); + } + + /** {@inheritDoc} */ + @Override public void writeChar(String fieldName, char val) throws PortableException { + add(fieldName, char.class); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(String fieldName, boolean val) throws PortableException { + add(fieldName, boolean.class); + } + + /** {@inheritDoc} */ + @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws PortableException { + add(fieldName, PortableClassDescriptor.Mode.DECIMAL.typeName()); + } + + /** {@inheritDoc} */ + @Override public void writeString(String fieldName, @Nullable String val) throws PortableException { + add(fieldName, String.class); + } + + /** {@inheritDoc} */ + @Override public void writeUuid(String fieldName, @Nullable UUID val) throws PortableException { + add(fieldName, UUID.class); + } + + /** {@inheritDoc} */ + @Override public void writeDate(String fieldName, @Nullable Date val) throws PortableException { + add(fieldName, Date.class); + } + + /** {@inheritDoc} */ + @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws PortableException { + add(fieldName, Timestamp.class); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws PortableException { + add(fieldName, Enum.class); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws PortableException { + add(fieldName, Enum[].class); + } + + /** {@inheritDoc} */ + @Override public void writeObject(String fieldName, @Nullable Object obj) throws PortableException { + add(fieldName, Object.class); + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws PortableException { + add(fieldName, byte[].class); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws PortableException { + add(fieldName, short[].class); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws PortableException { + add(fieldName, int[].class); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws PortableException { + add(fieldName, long[].class); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws PortableException { + add(fieldName, float[].class); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) throws PortableException { + add(fieldName, double[].class); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws PortableException { + add(fieldName, char[].class); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) throws PortableException { + add(fieldName, boolean[].class); + } + + /** {@inheritDoc} */ + @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val) throws PortableException { + add(fieldName, PortableClassDescriptor.Mode.DECIMAL_ARR.typeName()); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(String fieldName, @Nullable String[] val) throws PortableException { + add(fieldName, String[].class); + } + + /** {@inheritDoc} */ + @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws PortableException { + add(fieldName, UUID[].class); + } + + /** {@inheritDoc} */ + @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws PortableException { + add(fieldName, Date[].class); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws PortableException { + add(fieldName, Object[].class); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) + throws PortableException { + add(fieldName, Collection.class); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) throws PortableException { + add(fieldName, Map.class); + } + + /** {@inheritDoc} */ + @Override public PortableRawWriter rawWriter() { + return (PortableRawWriter)Proxy.newProxyInstance(getClass().getClassLoader(), + new Class<?>[] { PortableRawWriterEx.class }, + new InvocationHandler() { + @Override public Object invoke(Object proxy, Method mtd, Object[] args) throws Throwable { + return null; + } + }); + } + + /** + * @param name Field name. + * @param fieldType Field type. + * @throws PortableException In case of error. + */ + private void add(String name, Class<?> fieldType) throws PortableException { + assert fieldType != null; + + add(name, fieldType.getSimpleName()); + } + + /** + * @param name Field name. + * @param fieldTypeName Field type name. + * @throws PortableException In case of error. + */ + private void add(String name, String fieldTypeName) throws PortableException { + assert name != null; + + String oldFieldTypeName = meta.put(name, fieldTypeName); + + if (oldFieldTypeName != null && !oldFieldTypeName.equals(fieldTypeName)) { + throw new PortableException( + "Field is written twice with different types [" + + "typeName=" + typeName + + ", fieldName=" + name + + ", fieldTypeName1=" + oldFieldTypeName + + ", fieldTypeName2=" + fieldTypeName + + ']' + ); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataHandler.java new file mode 100644 index 0000000..88c4ca1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataHandler.java @@ -0,0 +1,43 @@ +/* + * 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.portable; + +import org.apache.ignite.portable.*; + +/** + * Portable meta data handler. + */ +public interface PortableMetaDataHandler { + /** + * Adds meta data. + * + * @param typeId Type ID. + * @param meta Meta data. + * @throws PortableException In case of error. + */ + public void addMeta(int typeId, PortableMetaDataImpl meta) throws PortableException; + + /** + * Gets meta data for provided type ID. + * + * @param typeId Type ID. + * @return Meta data. + * @throws PortableException In case of error. + */ + public PortableMetadata metadata(int typeId) throws PortableException; +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataImpl.java new file mode 100644 index 0000000..697a981 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableMetaDataImpl.java @@ -0,0 +1,140 @@ +/* + * 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.portable; + +import org.apache.ignite.internal.util.tostring.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.portable.*; + +import org.jetbrains.annotations.*; + +import java.io.*; +import java.util.*; + +/** + * Portable meta data implementation. + */ +public class PortableMetaDataImpl implements PortableMetadata, PortableMarshalAware, Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private String typeName; + + /** */ + @GridToStringInclude + private Map<String, String> fields; + + /** */ + private volatile Map<Integer, String> fldIdToName; + + /** */ + private String affKeyFieldName; + + /** + * For {@link Externalizable}. + */ + public PortableMetaDataImpl() { + // No-op. + } + + /** + * @param typeName Type name. + * @param fields Fields map. + * @param affKeyFieldName Affinity key field name. + */ + public PortableMetaDataImpl(String typeName, @Nullable Map<String, String> fields, + @Nullable String affKeyFieldName) { + assert typeName != null; + + this.typeName = typeName; + this.fields = fields; + this.affKeyFieldName = affKeyFieldName; + } + + /** {@inheritDoc} */ + @Override public String typeName() { + return typeName; + } + + /** {@inheritDoc} */ + @Override public Collection<String> fields() { + return fields != null ? fields.keySet() : Collections.<String>emptyList(); + } + + /** + * @return Fields. + */ + public Map<String, String> fields0() { + return fields != null ? fields : Collections.<String, String>emptyMap(); + } + + /** {@inheritDoc} */ + @Nullable @Override public String fieldTypeName(String fieldName) { + return fields != null ? fields.get(fieldName) : null; + } + + /** {@inheritDoc} */ + @Nullable @Override public String affinityKeyFieldName() { + return affKeyFieldName; + } + + /** + * @return Fields meta data. + */ + public Map<String, String> fieldsMeta() { + return fields != null ? fields : Collections.<String, String>emptyMap(); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + U.writeString(out, typeName); + U.writeMap(out, fields); + U.writeString(out, affKeyFieldName); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + typeName = U.readString(in); + fields = U.readMap(in); + affKeyFieldName = U.readString(in); + } + + /** {@inheritDoc} */ + @Override public void writePortable(PortableWriter writer) throws PortableException { + PortableRawWriter raw = writer.rawWriter(); + + raw.writeString(typeName); + raw.writeString(affKeyFieldName); + raw.writeMap(fields); + } + + /** {@inheritDoc} */ + @Override public void readPortable(PortableReader reader) throws PortableException { + PortableRawReader raw = reader.rawReader(); + + typeName = raw.readString(); + affKeyFieldName = raw.readString(); + fields = raw.readMap(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(PortableMetaDataImpl.class, this); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/4662feca/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectArrayLazyValue.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectArrayLazyValue.java new file mode 100644 index 0000000..d32cbb1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectArrayLazyValue.java @@ -0,0 +1,89 @@ +/* + * 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.portable; + +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.portable.*; + +/** + * + */ +class PortableObjectArrayLazyValue extends PortableAbstractLazyValue { + /** */ + private Object[] lazyValsArr; + + /** */ + private int compTypeId; + + /** */ + private String clsName; + + /** + * @param reader Reader. + */ + protected PortableObjectArrayLazyValue(PortableBuilderReader reader) { + super(reader, reader.position() - 1); + + int typeId = reader.readInt(); + + if (typeId == GridPortableMarshaller.UNREGISTERED_TYPE_ID) { + clsName = reader.readString(); + + Class cls; + + try { + // TODO: GG-10396 - Is class loader needed here? + cls = U.forName(reader.readString(), null); + } + catch (ClassNotFoundException e) { + throw new PortableInvalidClassException("Failed to load the class: " + clsName, e); + } + + compTypeId = reader.portableContext().descriptorForClass(cls).typeId(); + } + else { + compTypeId = typeId; + clsName = null; + } + + int size = reader.readInt(); + + lazyValsArr = new Object[size]; + + for (int i = 0; i < size; i++) + lazyValsArr[i] = reader.parseValue(); + } + + /** {@inheritDoc} */ + @Override protected Object init() { + for (int i = 0; i < lazyValsArr.length; i++) { + if (lazyValsArr[i] instanceof PortableLazyValue) + lazyValsArr[i] = ((PortableLazyValue)lazyValsArr[i]).value(); + } + + return lazyValsArr; + } + + /** {@inheritDoc} */ + @Override public void writeTo(PortableWriterExImpl writer, PortableBuilderSerializer ctx) { + if (clsName == null) + ctx.writeArray(writer, GridPortableMarshaller.OBJ_ARR, lazyValsArr, compTypeId); + else + ctx.writeArray(writer, GridPortableMarshaller.OBJ_ARR, lazyValsArr, clsName); + } +}