IGNITE-4575: Improved binary enums support. This closes #1968.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/b5c7b6f5 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/b5c7b6f5 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/b5c7b6f5 Branch: refs/heads/master Commit: b5c7b6f5ed81a9cee242e3abb052c29ec571a9a9 Parents: d38ca8b Author: Sergey Kalashnikov <skalashni...@gridgain.com> Authored: Fri May 26 14:07:06 2017 +0300 Committer: devozerov <voze...@gridgain.com> Committed: Fri May 26 14:07:06 2017 +0300 ---------------------------------------------------------------------- .../java/org/apache/ignite/IgniteBinary.java | 23 ++- .../org/apache/ignite/binary/BinaryObject.java | 8 + .../org/apache/ignite/binary/BinaryType.java | 5 + .../ignite/binary/BinaryTypeConfiguration.java | 26 +++ .../binary/BinaryCachingMetadataHandler.java | 5 + .../internal/binary/BinaryClassDescriptor.java | 4 +- .../ignite/internal/binary/BinaryContext.java | 60 +++++-- .../internal/binary/BinaryEnumObjectImpl.java | 30 +++- .../internal/binary/BinaryFieldAccessor.java | 10 ++ .../ignite/internal/binary/BinaryMetadata.java | 93 +++++++++- .../internal/binary/BinaryMetadataHandler.java | 9 + .../binary/BinaryNoopMetadataHandler.java | 5 + .../internal/binary/BinaryObjectExImpl.java | 5 + .../internal/binary/BinaryReaderExImpl.java | 18 ++ .../ignite/internal/binary/BinaryTypeImpl.java | 15 ++ .../ignite/internal/binary/BinaryTypeProxy.java | 6 + .../ignite/internal/binary/BinaryUtils.java | 104 ++++++++++- .../internal/binary/BinaryWriterExImpl.java | 18 +- .../internal/binary/GridBinaryMarshaller.java | 3 + .../binary/builder/BinaryBuilderSerializer.java | 10 +- .../binary/builder/BinaryObjectBuilderImpl.java | 2 +- .../binary/CacheObjectBinaryProcessor.java | 21 ++- .../binary/CacheObjectBinaryProcessorImpl.java | 72 +++++++- .../cache/binary/IgniteBinaryImpl.java | 26 +++ .../processors/cacheobject/NoOpBinary.java | 12 ++ .../platform/PlatformContextImpl.java | 29 ++- .../binary/PlatformBinaryProcessor.java | 25 +++ .../internal/binary/BinaryEnumsSelfTest.java | 146 ++++++++++++++- .../binary/TestCachingMetadataHandler.java | 5 + .../platform/PlatformComputeEchoTask.java | 13 ++ .../Binary/BinaryBuilderSelfTest.cs | 88 +++++++-- .../Compute/ComputeApiTest.cs | 25 +++ .../Binary/BinaryTypeConfiguration.cs | 3 +- .../dotnet/Apache.Ignite.Core/Binary/IBinary.cs | 24 +++ .../Apache.Ignite.Core/Binary/IBinaryObject.cs | 8 + .../Apache.Ignite.Core/Binary/IBinaryType.cs | 6 + .../Apache.Ignite.Core/Impl/Binary/Binary.cs | 67 ++++++- .../Impl/Binary/BinaryEnum.cs | 11 +- .../Impl/Binary/BinaryObject.cs | 13 +- .../Impl/Binary/BinaryProcessor.cs | 65 ++++++- .../Impl/Binary/BinaryReader.cs | 10 +- .../Impl/Binary/BinarySystemHandlers.cs | 25 +-- .../Impl/Binary/BinaryUtils.cs | 19 ++ .../Impl/Binary/BinaryWriter.cs | 4 +- .../Impl/Binary/Marshaller.cs | 88 ++++----- .../Impl/Binary/Metadata/BinaryType.cs | 179 ++++++++++++++++++- .../Impl/Binary/Metadata/BinaryTypeHolder.cs | 44 +++-- 47 files changed, 1338 insertions(+), 149 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java b/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java index 1d1c0c3..3550ff5 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.TreeMap; import java.util.UUID; import org.apache.ignite.binary.BinaryObjectBuilder; @@ -374,11 +375,29 @@ public interface IgniteBinary { public Collection<BinaryType> types() throws BinaryObjectException; /** - * Create enum object. + * Create enum object using value. * * @param typeName Type name. * @param ord Ordinal. * @return Enum object. */ - public BinaryObject buildEnum(String typeName, int ord); + public BinaryObject buildEnum(String typeName, int ord) throws BinaryObjectException; + + /** + * Create enum object using name. + * + * @param typeName Type name. + * @param name Name. + * @return Enum object. + */ + public BinaryObject buildEnum(String typeName, String name) throws BinaryObjectException; + + /** + * Register enum type. + * + * @param typeName Type name. + * @param vals Mapping of enum constant names to ordinals. + * @return Binary type for registered enum. + */ + public BinaryType registerEnum(String typeName, Map<String, Integer> vals) throws BinaryObjectException; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java index 3d99757..b9e653f 100644 --- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java +++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java @@ -162,4 +162,12 @@ public interface BinaryObject extends Serializable, Cloneable { * @throws BinaryObjectException If object is not enum. */ public int enumOrdinal() throws BinaryObjectException; + + /** + * Get name for this enum object. Use {@link BinaryType#isEnum()} to check if object is of enum type. + * + * @return Name. + * @throws BinaryObjectException If object is not enum. + */ + public String enumName() throws BinaryObjectException; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java index f184a8c..f4bc206 100644 --- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java +++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java @@ -79,4 +79,9 @@ public interface BinaryType { * @return {@code True} if type is enum. */ public boolean isEnum(); + + /** + * @return Collection of enum values. + */ + public Collection<BinaryObject> enumValues(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java index 54b853c..2d00bd2 100644 --- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java @@ -23,6 +23,9 @@ import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.Nullable; +import java.util.LinkedHashMap; +import java.util.Map; + /** * Defines configuration properties for a specific binary type. Providing per-type * configuration is optional, as it is generally enough, and also optional, to provide global binary @@ -46,6 +49,9 @@ public class BinaryTypeConfiguration { /** Enum flag. */ private boolean isEnum; + /** Enum names to ordinals mapping. */ + private Map<String, Integer> enumValues; + /** * Constructor. */ @@ -64,6 +70,7 @@ public class BinaryTypeConfiguration { idMapper = other.idMapper; isEnum = other.isEnum; serializer = other.serializer; + enumValues = other.enumValues != null ? new LinkedHashMap<>(other.enumValues) : null; typeName = other.typeName; } @@ -179,6 +186,25 @@ public class BinaryTypeConfiguration { return this; } + /** + * Set enum ordinal to names mapping. + * + * @param values Map of enum name to ordinal. + * @return {@code this} for chaining. + */ + public BinaryTypeConfiguration setEnumValues(@Nullable Map<String, Integer> values) { + this.enumValues = values; + + return this; + } + + /** + * @return Enum name to ordinal mapping + */ + @Nullable public Map<String, Integer> getEnumValues() { + return enumValues; + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(BinaryTypeConfiguration.class, this, super.toString()); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryCachingMetadataHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryCachingMetadataHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryCachingMetadataHandler.java index 24a393d..27cccaa 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryCachingMetadataHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryCachingMetadataHandler.java @@ -69,6 +69,11 @@ public class BinaryCachingMetadataHandler implements BinaryMetadataHandler { } /** {@inheritDoc} */ + @Override public synchronized BinaryMetadata metadata0(int typeId) throws BinaryObjectException { + return ((BinaryTypeImpl)metas.get(typeId)).metadata(); + } + + /** {@inheritDoc} */ @Override public synchronized BinaryType metadata(int typeId, int schemaId) throws BinaryObjectException { BinaryTypeImpl type = (BinaryTypeImpl) metas.get(typeId); return type.metadata().hasSchema(schemaId) ? type : null; http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java index 7194f49..adfdcfc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java @@ -758,7 +758,7 @@ public class BinaryClassDescriptor { BinarySchema newSchema = collector.schema(); BinaryMetadata meta = new BinaryMetadata(typeId, typeName, collector.meta(), - affKeyFieldName, Collections.singleton(newSchema), false); + affKeyFieldName, Collections.singleton(newSchema), false, null); ctx.updateMetadata(typeId, meta); @@ -779,7 +779,7 @@ public class BinaryClassDescriptor { if (userType && !stableSchemaPublished) { // Update meta before write object with new schema BinaryMetadata meta = new BinaryMetadata(typeId, typeName, stableFieldsMeta, - affKeyFieldName, Collections.singleton(stableSchema), false); + affKeyFieldName, Collections.singleton(stableSchema), false, null); ctx.updateMetadata(typeId, meta); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java index da46496..70bc2f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java @@ -461,17 +461,17 @@ public class BinaryContext { for (String clsName0 : classesInPackage(pkgName)) descs.add(clsName0, mapper, serializer, identity, affFields.get(clsName0), - typeCfg.isEnum(), true); + typeCfg.isEnum(), typeCfg.getEnumValues(), true); } else descs.add(clsName, mapper, serializer, identity, affFields.get(clsName), - typeCfg.isEnum(), false); + typeCfg.isEnum(), typeCfg.getEnumValues(), false); } } for (TypeDescriptor desc : descs.descriptors()) registerUserType(desc.clsName, desc.mapper, desc.serializer, desc.identity, desc.affKeyFieldName, - desc.isEnum); + desc.isEnum, desc.enumMap); BinaryInternalMapper globalMapper = resolveMapper(globalNameMapper, globalIdMapper); @@ -649,7 +649,8 @@ public class BinaryContext { desc0.typeName(), desc0.fieldsMeta(), desc0.affFieldKeyName(), - schemas, desc0.isEnum()); + schemas, desc0.isEnum(), + cls.isEnum() ? enumMap(cls) : null); metaHnd.addMeta(desc0.typeId(), meta.wrap(this)); @@ -799,8 +800,8 @@ public class BinaryContext { ); if (!deserialize) - metaHnd.addMeta(typeId, - new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), affFieldName, null, desc.isEnum()).wrap(this)); + metaHnd.addMeta(typeId, new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), affFieldName, null, + desc.isEnum(), cls.isEnum() ? enumMap(cls) : null).wrap(this)); descByCls.put(cls, desc); @@ -1095,6 +1096,7 @@ public class BinaryContext { * @param identity Type identity. * @param affKeyFieldName Affinity key field name. * @param isEnum If enum. + * @param enumMap Enum name to ordinal mapping. * @throws BinaryObjectException In case of error. */ @SuppressWarnings("ErrorNotRethrown") @@ -1103,8 +1105,8 @@ public class BinaryContext { @Nullable BinarySerializer serializer, @Nullable BinaryIdentityResolver identity, @Nullable String affKeyFieldName, - boolean isEnum) - throws BinaryObjectException { + boolean isEnum, + @Nullable Map<String, Integer> enumMap) throws BinaryObjectException { assert mapper != null; Class<?> cls = null; @@ -1172,7 +1174,8 @@ public class BinaryContext { predefinedTypes.put(id, desc); } - metaHnd.addMeta(id, new BinaryMetadata(id, typeName, fieldsMeta, affKeyFieldName, null, isEnum).wrap(this)); + metaHnd.addMeta(id, + new BinaryMetadata(id, typeName, fieldsMeta, affKeyFieldName, null, isEnum, enumMap).wrap(this)); } /** @@ -1222,6 +1225,16 @@ public class BinaryContext { } /** + * + * @param typeId Type ID + * @return Meta data. + * @throws BinaryObjectException In case of error. + */ + @Nullable public BinaryMetadata metadata0(int typeId) throws BinaryObjectException { + return metaHnd != null ? metaHnd.metadata0(typeId) : null; + } + + /** * @param typeId Type ID. * @param schemaId Schema ID. * @return Meta data. @@ -1351,6 +1364,24 @@ public class BinaryContext { } /** + * + * @param cls Class + * @return Enum name to ordinal mapping. + */ + private static Map<String, Integer> enumMap(Class<?> cls) { + assert cls.isEnum(); + + Object[] enumVals = cls.getEnumConstants(); + + Map<String, Integer> enumMap = new LinkedHashMap<>(enumVals.length); + + for (Object enumVal : enumVals) + enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal()); + + return enumMap; + } + + /** * Type descriptors. */ private static class TypeDescriptors { @@ -1366,6 +1397,7 @@ public class BinaryContext { * @param identity Key hashing mode. * @param affKeyFieldName Affinity key field name. * @param isEnum Enum flag. + * @param enumMap Enum constants mapping. * @param canOverride Whether this descriptor can be override. * @throws BinaryObjectException If failed. */ @@ -1375,6 +1407,7 @@ public class BinaryContext { BinaryIdentityResolver identity, String affKeyFieldName, boolean isEnum, + Map<String, Integer> enumMap, boolean canOverride) throws BinaryObjectException { TypeDescriptor desc = new TypeDescriptor(clsName, @@ -1383,6 +1416,7 @@ public class BinaryContext { identity, affKeyFieldName, isEnum, + enumMap, canOverride); TypeDescriptor oldDesc = descs.get(clsName); @@ -1425,6 +1459,9 @@ public class BinaryContext { /** Enum flag. */ private boolean isEnum; + /** Enum ordinal to name mapping. */ + private Map<String, Integer> enumMap; + /** Whether this descriptor can be override. */ private boolean canOverride; @@ -1436,17 +1473,19 @@ public class BinaryContext { * @param identity Key hashing mode. * @param affKeyFieldName Affinity key field name. * @param isEnum Enum type. + * @param enumMap Mapping of enum names to ordinals. * @param canOverride Whether this descriptor can be override. */ private TypeDescriptor(String clsName, BinaryInternalMapper mapper, BinarySerializer serializer, BinaryIdentityResolver identity, String affKeyFieldName, boolean isEnum, - boolean canOverride) { + Map<String, Integer> enumMap, boolean canOverride) { this.clsName = clsName; this.mapper = mapper; this.serializer = serializer; this.identity = identity; this.affKeyFieldName = affKeyFieldName; this.isEnum = isEnum; + this.enumMap = enumMap; this.canOverride = canOverride; } @@ -1465,6 +1504,7 @@ public class BinaryContext { identity = other.identity; affKeyFieldName = other.affKeyFieldName; isEnum = other.isEnum; + enumMap = other.enumMap; canOverride = other.canOverride; } else if (!other.canOverride) http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java index cc9941e..f889e45 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java @@ -97,9 +97,18 @@ public class BinaryEnumObjectImpl implements BinaryObjectEx, Externalizable, Cac public BinaryEnumObjectImpl(BinaryContext ctx, byte[] arr) { assert ctx != null; assert arr != null; - assert arr[0] == GridBinaryMarshaller.ENUM; - valBytes = arr; + if (arr[0] == GridBinaryMarshaller.ENUM) + valBytes = arr; + else { + assert arr[0] == GridBinaryMarshaller.BINARY_ENUM; + + valBytes = new byte[arr.length]; + + valBytes[0] = GridBinaryMarshaller.ENUM; + + U.arrayCopy(arr, 1, valBytes, 1, arr.length - 1); + } this.ctx = ctx; @@ -187,6 +196,23 @@ public class BinaryEnumObjectImpl implements BinaryObjectEx, Externalizable, Cac } /** {@inheritDoc} */ + @Override public String enumName() throws BinaryObjectException { + BinaryMetadata metadata = ctx.metadata0(typeId); + + if (metadata == null) + throw new BinaryObjectException("Failed to get metadata for enum [typeId=" + + typeId + ", typeName='" + clsName + "', ordinal=" + ord + "]"); + + String name = metadata.getEnumNameByOrdinal(ord); + + if (name == null) + throw new BinaryObjectException("Unable to resolve enum constant name [typeId=" + + typeId + ", typeName='" + metadata.typeName() + "', ordinal=" + ord + "]"); + + return name; + } + + /** {@inheritDoc} */ @Override public int hashCode() { return 31 * typeId + ord; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldAccessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldAccessor.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldAccessor.java index f7d35f0..567bee1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldAccessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldAccessor.java @@ -647,6 +647,11 @@ public abstract class BinaryFieldAccessor { break; + case BINARY_ENUM: + writer.doWriteBinaryEnum((BinaryEnumObjectImpl)val); + + break; + case ENUM_ARR: writer.writeEnumArrayField((Object[])val); @@ -863,6 +868,11 @@ public abstract class BinaryFieldAccessor { break; + case BINARY_ENUM: + val = reader.readBinaryEnum(id); + + break; + case BINARY: case OBJECT: val = reader.readObject(id); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadata.java index a8b7fcb..ead00b7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadata.java @@ -27,9 +27,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; + import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.jetbrains.annotations.Nullable; @@ -41,6 +44,9 @@ public class BinaryMetadata implements Externalizable { /** */ private static final long serialVersionUID = 0L; + /** */ + private static final int VERSION = 1; + /** Type ID. */ @GridToStringInclude(sensitive = true) private int typeId; @@ -67,6 +73,12 @@ public class BinaryMetadata implements Externalizable { /** Whether this is enum type. */ private boolean isEnum; + /** Enum name to ordinal mapping. */ + private Map<String, Integer> nameToOrdinal; + + /** Enum ordinal to name mapping. */ + private Map<Integer, String> ordinalToName; + /** * For {@link Externalizable}. */ @@ -83,9 +95,11 @@ public class BinaryMetadata implements Externalizable { * @param affKeyFieldName Affinity key field name. * @param schemas Schemas. * @param isEnum Enum flag. + * @param enumMap Enum name to ordinal mapping. */ public BinaryMetadata(int typeId, String typeName, @Nullable Map<String, BinaryFieldMetadata> fields, - @Nullable String affKeyFieldName, @Nullable Collection<BinarySchema> schemas, boolean isEnum) { + @Nullable String affKeyFieldName, @Nullable Collection<BinarySchema> schemas, boolean isEnum, + @Nullable Map<String, Integer> enumMap) { assert typeName != null; this.typeId = typeId; @@ -104,6 +118,15 @@ public class BinaryMetadata implements Externalizable { schemaIds = Collections.emptySet(); this.isEnum = isEnum; + + if (enumMap != null) { + this.nameToOrdinal = new LinkedHashMap<>(enumMap); + + this.ordinalToName = new LinkedHashMap<>(enumMap.size()); + + for (Map.Entry<String, Integer> e: nameToOrdinal.entrySet()) + this.ordinalToName.put(e.getValue(), e.getKey()); + } } /** @@ -197,6 +220,7 @@ public class BinaryMetadata implements Externalizable { * @exception IOException Includes any I/O exceptions that may occur. */ public void writeTo(DataOutput out) throws IOException { + out.writeByte(VERSION); out.writeInt(typeId); U.writeString(out, typeName); @@ -224,6 +248,18 @@ public class BinaryMetadata implements Externalizable { } out.writeBoolean(isEnum); + + if (isEnum) { + Map<String, Integer> map = enumMap(); + + out.writeInt(map.size()); + + for (Map.Entry<String, Integer> e : map.entrySet()) { + U.writeString(out, e.getKey()); + + out.writeInt(e.getValue()); + } + } } /** {@inheritDoc} */ @@ -242,6 +278,8 @@ public class BinaryMetadata implements Externalizable { * @exception IOException if I/O errors occur. */ public void readFrom(DataInput in) throws IOException { + in.readByte(); //skip version + typeId = in.readInt(); typeName = U.readString(in); @@ -285,6 +323,59 @@ public class BinaryMetadata implements Externalizable { } isEnum = in.readBoolean(); + + if (isEnum) { + int size = in.readInt(); + + if (size >= 0) { + ordinalToName = new LinkedHashMap<>(size); + nameToOrdinal = new LinkedHashMap<>(size); + + for (int idx = 0; idx < size; idx++) { + String name = U.readString(in); + + int ord = in.readInt(); + + ordinalToName.put(ord, name); + nameToOrdinal.put(name, ord); + } + } + } + } + + /** + * Gets enum constant name given its ordinal value. + * + * @param ord Enum constant ordinal value. + * @return Enum constant name. + */ + public String getEnumNameByOrdinal(int ord) { + if (ordinalToName == null) + return null; + + return ordinalToName.get(ord); + } + + /** + * Gets enum constant ordinal value given its name. + * + * @param name Enum constant name. + * @return Enum constant ordinal value. + */ + public Integer getEnumOrdinalByName(String name) { + assert name != null; + + return nameToOrdinal.get(name); + } + + /** + * @return Name to ordinal mapping. + */ + public Map<String, Integer> enumMap() { + if (nameToOrdinal == null) + return Collections.emptyMap(); + + return nameToOrdinal; } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadataHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadataHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadataHandler.java index 748a283..e565338 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadataHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMetadataHandler.java @@ -43,6 +43,15 @@ public interface BinaryMetadataHandler { public BinaryType metadata(int typeId) throws BinaryObjectException; /** + * Gets unwrapped meta data for provided type ID. + * + * @param typeId Type ID. + * @return Metadata. + * @throws BinaryObjectException In case of error. + */ + public BinaryMetadata metadata0(int typeId) throws BinaryObjectException; + + /** * Gets metadata for provided type ID and schema ID. * * @param typeId Type ID. http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryNoopMetadataHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryNoopMetadataHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryNoopMetadataHandler.java index 770d9c8..39c942a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryNoopMetadataHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryNoopMetadataHandler.java @@ -52,6 +52,11 @@ public class BinaryNoopMetadataHandler implements BinaryMetadataHandler { } /** {@inheritDoc} */ + @Override public BinaryMetadata metadata0(int typeId) throws BinaryObjectException { + return null; + } + + /** {@inheritDoc} */ @Override public BinaryType metadata(int typeId, int schemaId) throws BinaryObjectException { return null; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectExImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectExImpl.java index ae9a160..b5e066b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectExImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectExImpl.java @@ -77,6 +77,11 @@ public abstract class BinaryObjectExImpl implements BinaryObjectEx { throw new BinaryObjectException("Object is not enum."); } + /** {@inheritDoc} */ + @Override public String enumName() throws BinaryObjectException { + throw new BinaryObjectException("Object is not enum."); + } + /** * Get offset of data begin. * http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java index c8ca803..2b7964c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java @@ -41,6 +41,7 @@ import org.apache.ignite.internal.util.typedef.internal.SB; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BINARY_ENUM; import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BINARY_OBJ; import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BOOLEAN; import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BOOLEAN_ARR; @@ -1426,6 +1427,15 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina /** * @param fieldId Field ID. + * @return Binary Enum + * @throws BinaryObjectException If failed. + */ + @Nullable BinaryEnumObjectImpl readBinaryEnum(int fieldId) throws BinaryObjectException { + return findFieldById(fieldId) ? BinaryUtils.doReadBinaryEnum(in, ctx) : null; + } + + /** + * @param fieldId Field ID. * @param cls Class. * @return Value. * @throws BinaryObjectException In case of error. @@ -1930,6 +1940,14 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina break; + case BINARY_ENUM: + obj = BinaryUtils.doReadBinaryEnum(in, ctx); + + if (!GridBinaryMarshaller.KEEP_BINARIES.get()) + obj = ((BinaryObject)obj).deserialize(); + + break; + case CLASS: obj = BinaryUtils.doReadClass(in, ctx, ldr); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java index 132702c..fac1ff9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java @@ -17,9 +17,12 @@ package org.apache.ignite.internal.binary; +import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryType; +import java.util.ArrayList; import java.util.Collection; + import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.internal.S; @@ -80,6 +83,18 @@ public class BinaryTypeImpl implements BinaryType { return meta.isEnum(); } + /** {@inheritDoc} */ + @Override public Collection<BinaryObject> enumValues() { + Collection<Integer> ordinals = meta.enumMap().values(); + + ArrayList<BinaryObject> enumValues = new ArrayList<>(ordinals.size()); + + for (Integer ord: ordinals) + enumValues.add(new BinaryEnumObjectImpl(ctx, typeId(), typeName(), ord)); + + return enumValues; + } + /** * @return Context. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeProxy.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeProxy.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeProxy.java index df9901e..3a51050 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeProxy.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeProxy.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.binary; import org.apache.ignite.binary.BinaryField; +import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryObjectException; import org.apache.ignite.binary.BinaryType; import org.apache.ignite.internal.util.tostring.GridToStringExclude; @@ -92,6 +93,11 @@ public class BinaryTypeProxy implements BinaryType { return target().isEnum(); } + /** {@inheritDoc} */ + @Override public Collection<BinaryObject> enumValues() { + return target().enumValues(); + } + /** * @return Target type. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java index f36c137..00b15da 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java @@ -266,6 +266,7 @@ public class BinaryUtils { FIELD_TYPE_NAMES[GridBinaryMarshaller.TIME_ARR] = "Time[]"; FIELD_TYPE_NAMES[GridBinaryMarshaller.OBJ_ARR] = "Object[]"; FIELD_TYPE_NAMES[GridBinaryMarshaller.ENUM_ARR] = "Enum[]"; + FIELD_TYPE_NAMES[GridBinaryMarshaller.BINARY_ENUM] = "Enum"; if (wrapTrees()) { CLS_TO_WRITE_REPLACER.put(TreeMap.class, new BinaryTreeMapWriteReplacer()); @@ -975,6 +976,14 @@ public class BinaryUtils { boolean changed = false; + Map<String, Integer> mergedEnumMap = null; + + if (!F.isEmpty(newMeta.enumMap())) { + mergedEnumMap = mergeEnumValues(oldMeta.typeName(), oldMeta.enumMap(), newMeta.enumMap()); + + changed = mergedEnumMap.size() > oldMeta.enumMap().size(); + } + for (Map.Entry<String, BinaryFieldMetadata> newField : newFields.entrySet()) { BinaryFieldMetadata oldFieldMeta = mergedFields.put(newField.getKey(), newField.getValue()); @@ -1005,7 +1014,7 @@ public class BinaryUtils { // Return either old meta if no changes detected, or new merged meta. return changed ? new BinaryMetadata(oldMeta.typeId(), oldMeta.typeName(), mergedFields, - oldMeta.affinityKeyFieldName(), mergedSchemas, oldMeta.isEnum()) : oldMeta; + oldMeta.affinityKeyFieldName(), mergedSchemas, oldMeta.isEnum(), mergedEnumMap) : oldMeta; } } @@ -1106,6 +1115,8 @@ public class BinaryUtils { return BinaryWriteMode.MAP; else if (cls.isEnum()) return BinaryWriteMode.ENUM; + else if (cls == BinaryEnumObjectImpl.class) + return BinaryWriteMode.BINARY_ENUM; else if (cls == Class.class) return BinaryWriteMode.CLASS; else if (Proxy.class.isAssignableFrom(cls)) @@ -1627,6 +1638,17 @@ public class BinaryUtils { * * @param in Input stream. * @param ctx Binary context. + * @return Enum. + */ + public static BinaryEnumObjectImpl doReadBinaryEnum(BinaryInputStream in, BinaryContext ctx) { + return doReadBinaryEnum(in, ctx, doReadEnumType(in)); + } + + /** + * Read binary enum. + * + * @param in Input stream. + * @param ctx Binary context. * @param type Plain type. * @return Enum. */ @@ -1903,6 +1925,7 @@ public class BinaryUtils { return doReadBinaryObject(in, ctx, detach); case GridBinaryMarshaller.ENUM: + case GridBinaryMarshaller.BINARY_ENUM: return doReadBinaryEnum(in, ctx, doReadEnumType(in)); case GridBinaryMarshaller.ENUM_ARR: @@ -2356,6 +2379,85 @@ public class BinaryUtils { } /** + * Checks enum values mapping. + * + * @param typeName Name of the type. + * @param enumValues Enum name to ordinal mapping. + * @throws BinaryObjectException + */ + public static void validateEnumValues(String typeName, @Nullable Map<String, Integer> enumValues) + throws BinaryObjectException { + + if (enumValues == null) + return; + + Map<Integer, String> tmpMap = new LinkedHashMap<>(enumValues.size()); + for (Map.Entry<String, Integer> e: enumValues.entrySet()) { + + String prevName = tmpMap.put(e.getValue(), e.getKey()); + + if (prevName != null) + throw new BinaryObjectException("Conflicting enum values. Name '" + e.getKey() + + "' uses ordinal value (" + e.getValue() + + ") that is also used for name '" + prevName + + "' [typeName='" + typeName + "']"); + } + } + + /** + * Merges enum value mappings and checks for conflicts. + * + * Possible conflicts: + * - same name is used for different ordinal values. + * - ordinal value is used more than once. + * + * @param typeName Name of the type. + * @param oldValues Old enum value mapping. + * @param newValues New enum value mapping. + * @throws BinaryObjectException in case of name or value conflict. + */ + public static Map<String, Integer> mergeEnumValues(String typeName, + @Nullable Map<String, Integer> oldValues, + Map<String, Integer> newValues) + throws BinaryObjectException { + + assert newValues != null; + + int size = (oldValues != null) ? oldValues.size() + newValues.size() : newValues.size(); + + Map<Integer, String> revMap = new LinkedHashMap<>(size); + Map<String, Integer> mergedMap = new LinkedHashMap<>(size); + + if (oldValues != null) { + //assuming that old values were validated earlier once. + for (Map.Entry<String, Integer> e : oldValues.entrySet()) { + revMap.put(e.getValue(), e.getKey()); + mergedMap.put(e.getKey(), e.getValue()); + } + } + + for (Map.Entry<String, Integer> e: newValues.entrySet()) { + String prevName = revMap.put(e.getValue(), e.getKey()); + + if (prevName != null && !prevName.equals(e.getKey())) + throw new BinaryObjectException("Conflicting enum values. Name '" + e.getKey() + + "' uses ordinal value (" + e.getValue() + + ") that is also used for name '" + prevName + + "' [typeName='" + typeName + "']"); + + Integer prevVal = mergedMap.put(e.getKey(), e.getValue()); + + if (prevVal != null && !prevVal.equals(e.getValue())) + throw new BinaryObjectException("Conflicting enum values. Value (" + e.getValue() + + ") has name '" + e.getKey() + + "' that is also used for value '" + prevVal + + "' [typeName='" + typeName + "']"); + } + + return mergedMap; + } + + /** * Enum type. */ private static class EnumType { http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java index 7efe4b3..f2ba779 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java @@ -820,15 +820,23 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje int typeId = val.typeId(); - out.unsafeEnsure(1 + 4); + if (typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID) { + out.unsafeEnsure(1 + 4 + 4); - out.unsafeWriteByte(GridBinaryMarshaller.ENUM); - out.unsafeWriteInt(typeId); + out.unsafeWriteByte(GridBinaryMarshaller.BINARY_ENUM); + out.unsafeWriteInt(typeId); + out.unsafeWriteInt(val.enumOrdinal()); + } + else { + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridBinaryMarshaller.BINARY_ENUM); + out.unsafeWriteInt(typeId); - if (typeId == GridBinaryMarshaller.UNREGISTERED_TYPE_ID) doWriteString(val.className()); - out.writeInt(val.enumOrdinal()); + out.writeInt(val.enumOrdinal()); + } } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java index d4b0ff4..291c638 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java @@ -153,6 +153,9 @@ public class GridBinaryMarshaller { /** Time array. */ public static final byte TIME_ARR = 37; + /** Binary enum */ + public static final byte BINARY_ENUM = 38; + /** */ public static final byte NULL = (byte)101; http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java index 6974176..b1a8da9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java @@ -19,6 +19,7 @@ package org.apache.ignite.internal.binary.builder; import java.util.Collection; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.internal.binary.BinaryMetadata; @@ -115,7 +116,14 @@ class BinaryBuilderSerializer { int typeId = writer.context().typeId(clsName); String typeName = writer.context().userTypeName(clsName); - BinaryMetadata meta = new BinaryMetadata(typeId, typeName, null, null, null, true); + Object[] enumVals = val.getClass().getEnumConstants(); + + Map<String, Integer> enumMap = new LinkedHashMap<>(enumVals.length); + + for (Object enumVal : enumVals) + enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal()); + + BinaryMetadata meta = new BinaryMetadata(typeId, typeName, null, null, null, true, enumMap); writer.context().updateMetadata(typeId, meta); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java index 02e06fd..d6cd5ca 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java @@ -350,7 +350,7 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder { BinarySchema curSchema = writer.currentSchema(); ctx.updateMetadata(typeId, new BinaryMetadata(typeId, typeName, fieldsMeta, - ctx.affinityKeyFieldName(typeId), Collections.singleton(curSchema), false)); + ctx.affinityKeyFieldName(typeId), Collections.singleton(curSchema), false, null)); schemaReg.addSchema(curSchema.schemaId(), curSchema); } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java index 1564ff3..4d285ab 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java @@ -59,10 +59,12 @@ public interface CacheObjectBinaryProcessor extends IgniteCacheObjectProcessor { * @param affKeyFieldName Affinity key field name. * @param fieldTypeIds Fields map. * @param isEnum Enum flag. + * @param enumMap Enum name to ordinal mapping. * @throws IgniteException In case of error. */ public void updateMetadata(int typeId, String typeName, @Nullable String affKeyFieldName, - Map<String, BinaryFieldMetadata> fieldTypeIds, boolean isEnum) throws IgniteException; + Map<String, BinaryFieldMetadata> fieldTypeIds, boolean isEnum, @Nullable Map<String, Integer> enumMap) + throws IgniteException; /** * @param typeId Type ID. @@ -102,6 +104,23 @@ public interface CacheObjectBinaryProcessor extends IgniteCacheObjectProcessor { public BinaryObject buildEnum(String typeName, int ord) throws IgniteException; /** + * @param typeName Type name. + * @param name Name. + * @return Enum object. + * @throws IgniteException If failed. + */ + public BinaryObject buildEnum(String typeName, String name) throws IgniteException; + + /** + * Register enum type + * + * @param typeName Type name. + * @param vals Mapping of enum constant names to ordinals. + * @return Binary Type for registered enum. + */ + public BinaryType registerEnum(String typeName, Map<String, Integer> vals) throws IgniteException; + + /** * @return Binaries interface. * @throws IgniteException If failed. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java index 636d149..14947e9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java @@ -71,6 +71,7 @@ import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.T1; import org.apache.ignite.internal.util.typedef.T2; +import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteClosure; @@ -170,6 +171,10 @@ public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorIm return CacheObjectBinaryProcessorImpl.this.metadata(typeId); } + @Override public BinaryMetadata metadata0(int typeId) throws BinaryObjectException { + return CacheObjectBinaryProcessorImpl.this.metadata0(typeId); + } + @Override public BinaryType metadata(int typeId, int schemaId) throws BinaryObjectException { return CacheObjectBinaryProcessorImpl.this.metadata(typeId, schemaId); } @@ -207,6 +212,9 @@ public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorIm c.isEnum() ) ); + + if (c.isEnum()) + BinaryUtils.validateEnumValues(c.getTypeName(), c.getEnumValues()); } map.put("typeCfgs", typeCfgsMap); @@ -399,8 +407,10 @@ public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorIm /** {@inheritDoc} */ @Override public void updateMetadata(int typeId, String typeName, @Nullable String affKeyFieldName, - Map<String, BinaryFieldMetadata> fieldTypeIds, boolean isEnum) throws BinaryObjectException { - BinaryMetadata meta = new BinaryMetadata(typeId, typeName, fieldTypeIds, affKeyFieldName, null, isEnum); + Map<String, BinaryFieldMetadata> fieldTypeIds, boolean isEnum, @Nullable Map<String, Integer> enumMap) + throws BinaryObjectException { + BinaryMetadata meta = new BinaryMetadata(typeId, typeName, fieldTypeIds, affKeyFieldName, null, isEnum, + enumMap); binaryCtx.updateMetadata(typeId, meta); } @@ -433,6 +443,17 @@ public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorIm /** {@inheritDoc} */ @Nullable @Override public BinaryType metadata(final int typeId) { + BinaryMetadata meta = metadata0(typeId); + + return meta != null ? meta.wrap(binaryCtx) : null; + } + + /** + * @param typeId Type ID. + * @return Meta data. + * @throws IgniteException In case of error. + */ + @Nullable public BinaryMetadata metadata0(final int typeId) { BinaryMetadataHolder holder = metadataLocCache.get(typeId); if (holder == null) { @@ -466,7 +487,7 @@ public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorIm } } - return holder.metadata().wrap(binaryCtx); + return holder.metadata(); } else return null; @@ -547,17 +568,58 @@ public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorIm } /** {@inheritDoc} */ - @Override public BinaryObject buildEnum(String typeName, int ord) throws IgniteException { + @Override public BinaryObject buildEnum(String typeName, int ord) throws BinaryObjectException { + A.notNullOrEmpty(typeName, "enum type name"); + int typeId = binaryCtx.typeId(typeName); typeName = binaryCtx.userTypeName(typeName); - updateMetadata(typeId, typeName, null, null, true); + updateMetadata(typeId, typeName, null, null, true, null); return new BinaryEnumObjectImpl(binaryCtx, typeId, null, ord); } /** {@inheritDoc} */ + @Override public BinaryObject buildEnum(String typeName, String name) throws BinaryObjectException { + A.notNullOrEmpty(typeName, "enum type name"); + A.notNullOrEmpty(name, "enum name"); + + int typeId = binaryCtx.typeId(typeName); + + BinaryMetadata metadata = metadata0(typeId); + + if (metadata == null) + throw new BinaryObjectException("Failed to get metadata for type [typeId=" + + typeId + ", typeName='" + typeName + "']"); + + Integer ordinal = metadata.getEnumOrdinalByName(name); + + typeName = binaryCtx.userTypeName(typeName); + + if (ordinal == null) + throw new BinaryObjectException("Failed to resolve enum ordinal by name [typeId=" + + typeId + ", typeName='" + typeName + "', name='" + name + "']"); + + return new BinaryEnumObjectImpl(binaryCtx, typeId, null, ordinal); + } + + /** {@inheritDoc} */ + @Override public BinaryType registerEnum(String typeName, Map<String, Integer> vals) throws BinaryObjectException { + A.notNullOrEmpty(typeName, "enum type name"); + + int typeId = binaryCtx.typeId(typeName); + + typeName = binaryCtx.userTypeName(typeName); + + BinaryUtils.validateEnumValues(typeName, vals); + + updateMetadata(typeId, typeName, null, null, true, vals); + + return binaryCtx.metadata(typeId); + } + + /** {@inheritDoc} */ @Override public IgniteBinary binary() throws IgniteException { return binaries; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java index 1a2d0a9..e88819b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java @@ -18,6 +18,8 @@ package org.apache.ignite.internal.processors.cache.binary; import java.util.Collection; +import java.util.Map; + import org.apache.ignite.IgniteBinary; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor; @@ -155,6 +157,30 @@ public class IgniteBinaryImpl implements IgniteBinary { } } + /** {@inheritDoc} */ + @Override public BinaryObject buildEnum(String typeName, String name) { + guard(); + + try { + return proc.buildEnum(typeName, name); + } + finally { + unguard(); + } + } + + /** {@inheritDoc} */ + public BinaryType registerEnum(String typeName, Map<String, Integer> vals) { + guard(); + + try { + return proc.registerEnum(typeName, vals); + } + finally { + unguard(); + } + } + /** * @return Binary processor. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java index c1c8fed..32c3be6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java @@ -17,6 +17,8 @@ package org.apache.ignite.internal.processors.cacheobject; import java.util.Collection; +import java.util.Map; + import org.apache.ignite.IgniteBinary; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryObjectBuilder; @@ -74,6 +76,16 @@ public class NoOpBinary implements IgniteBinary { } /** {@inheritDoc} */ + @Override public BinaryObject buildEnum(String typeName, String name) { + throw unsupported(); + } + + /** {@inheritDoc} */ + @Override public BinaryType registerEnum(String typeName, Map<String, Integer> vals) { + throw unsupported(); + } + + /** {@inheritDoc} */ private BinaryObjectException unsupported() { return new BinaryObjectException("Binary marshaller is not configured."); } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java index 090f382..f115a9c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java @@ -82,6 +82,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -371,8 +372,19 @@ public class PlatformContextImpl implements PlatformContext { } }); + Map<String, Integer> enumMap = null; + boolean isEnum = reader.readBoolean(); + if (isEnum) { + int size = reader.readInt(); + + enumMap = new LinkedHashMap<>(size); + + for (int idx = 0; idx < size; idx++) + enumMap.put(reader.readString(), reader.readInt()); + } + // Read schemas int schemaCnt = reader.readInt(); @@ -393,7 +405,7 @@ public class PlatformContextImpl implements PlatformContext { } } - return new BinaryMetadata(typeId, typeName, fields, affKey, schemas, isEnum); + return new BinaryMetadata(typeId, typeName, fields, affKey, schemas, isEnum, enumMap); } } ); @@ -474,7 +486,20 @@ public class PlatformContextImpl implements PlatformContext { writer.writeInt(e.getValue().fieldId()); } - writer.writeBoolean(meta.isEnum()); + if (meta.isEnum()) { + writer.writeBoolean(true); + + Map<String, Integer> enumMap = meta0.enumMap(); + + writer.writeInt(enumMap.size()); + + for (Map.Entry<String, Integer> e: enumMap.entrySet()) { + writer.writeString(e.getKey()); + writer.writeInt(e.getValue()); + } + } + else + writer.writeBoolean(false); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java index 8d95ac8..be43848 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/binary/PlatformBinaryProcessor.java @@ -19,12 +19,16 @@ package org.apache.ignite.internal.processors.platform.binary; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryType; import org.apache.ignite.internal.MarshallerPlatformIds; import org.apache.ignite.internal.binary.BinaryRawReaderEx; import org.apache.ignite.internal.binary.BinaryRawWriterEx; import org.apache.ignite.internal.processors.platform.PlatformAbstractTarget; import org.apache.ignite.internal.processors.platform.PlatformContext; +import java.util.HashMap; +import java.util.Map; + /** * Platform binary processor. */ @@ -47,6 +51,9 @@ public class PlatformBinaryProcessor extends PlatformAbstractTarget { /** */ private static final int OP_GET_TYPE = 6; + /** */ + private static final int OP_REGISTER_ENUM = 7; + /** * Constructor. * @@ -122,6 +129,24 @@ public class PlatformBinaryProcessor extends PlatformAbstractTarget { break; } + case OP_REGISTER_ENUM: { + String name = reader.readString(); + + int cnt = reader.readInt(); + + Map<String, Integer> vals = new HashMap<>(cnt); + + for (int i = 0; i< cnt; i++) { + vals.put(reader.readString(), reader.readInt()); + } + + BinaryType binaryType = platformCtx.kernalContext().grid().binary().registerEnum(name, vals); + + platformCtx.writeMetadata(writer, binaryType.typeId()); + + break; + } + default: super.processInStreamOutStream(type, reader, writer); break; http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryEnumsSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryEnumsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryEnumsSelfTest.java index a223022..fd26d4a 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryEnumsSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryEnumsSelfTest.java @@ -19,10 +19,14 @@ package org.apache.ignite.internal.binary; import java.io.Serializable; import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.Callable; + import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryObject; +import org.apache.ignite.binary.BinaryObjectException; import org.apache.ignite.binary.BinaryTypeConfiguration; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.configuration.BinaryConfiguration; @@ -31,7 +35,9 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; /** @@ -42,6 +48,9 @@ public class BinaryEnumsSelfTest extends GridCommonAbstractTest { /** Cache name. */ private static String CACHE_NAME = "cache"; + /** Name of the node that starts with bad config */ + private static String WRONG_CONF_NODE_NAME = "WrongConfNode"; + /** Whether to register types or not. */ private boolean register; @@ -81,8 +90,20 @@ public class BinaryEnumsSelfTest extends GridCommonAbstractTest { BinaryConfiguration bCfg = new BinaryConfiguration(); BinaryTypeConfiguration enumCfg = new BinaryTypeConfiguration(EnumType.class.getName()); + enumCfg.setEnum(true); + if (igniteInstanceName.equals(WRONG_CONF_NODE_NAME)) + enumCfg.setEnumValues(F.asMap(EnumType.ONE.name(), + EnumType.ONE.ordinal(), + EnumType.TWO.name(), + EnumType.ONE.ordinal())); + else + enumCfg.setEnumValues(F.asMap(EnumType.ONE.name(), + EnumType.ONE.ordinal(), + EnumType.TWO.name(), + EnumType.TWO.ordinal())); + bCfg.setTypeConfigurations(Arrays.asList(enumCfg, new BinaryTypeConfiguration(EnumHolder.class.getName()))); cfg.setBinaryConfiguration(bCfg); @@ -317,11 +338,14 @@ public class BinaryEnumsSelfTest extends GridCommonAbstractTest { public void checkSimpleBuilder(boolean registered) throws Exception { startUp(registered); - BinaryObject binary = node1.binary().buildEnum(EnumType.class.getName(), EnumType.ONE.ordinal()); + BinaryObject binaryOne = node1.binary().buildEnum(EnumType.class.getName(), EnumType.ONE.ordinal()); + BinaryObject binaryTwo = node1.binary().buildEnum(EnumType.class.getName(), EnumType.TWO.ordinal()); - cacheBinary1.put(1, binary); + cacheBinary1.put(EnumType.ONE.ordinal(), binaryOne); + cacheBinary1.put(EnumType.TWO.ordinal(), binaryTwo); - validateSimple(1, EnumType.ONE, registered); + validateSimple(EnumType.ONE.ordinal(), EnumType.ONE, registered); + validateSimple(EnumType.TWO.ordinal(), EnumType.TWO, registered); } /** @@ -409,6 +433,112 @@ public class BinaryEnumsSelfTest extends GridCommonAbstractTest { } /** + * Checks ability to get a collection of binary enums from binary type + * + * @throws Exception + */ + public void testBinaryTypeEnumValues() throws Exception { + startUp(false); + + defineEnum(); + + BinaryObject binaryOne = node1.binary().buildEnum(EnumType.class.getName(), EnumType.ONE.ordinal()); + BinaryObject binaryTwo = node1.binary().buildEnum(EnumType.class.getName(), EnumType.TWO.name()); + + Collection<BinaryObject> vals = binaryOne.type().enumValues(); + + assertEqualsCollections(F.asList(binaryOne, binaryTwo), vals); + } + + /** + * Checks the enum configuration validation during start up + * + * @throws Exception + */ + public void testEnumWrongBinaryConfig() throws Exception { + this.register = true; + + GridTestUtils.assertThrows(log, new Callable<Object> (){ + @Override public Object call() throws Exception { + startGrid(WRONG_CONF_NODE_NAME); + + return null; + } + }, IgniteCheckedException.class, "Conflicting enum values"); + } + + /** + * Checks the enum validation during type registration + * + * @throws Exception + */ + public void testEnumValidation() throws Exception { + startUp(false); + + GridTestUtils.assertThrows(log, new Callable<Object> (){ + + @Override public Object call() throws Exception { + + node1.binary().registerEnum("invalidEnumType1", + F.asMap(EnumType.ONE.name(), EnumType.ONE.ordinal(), + EnumType.TWO.name(), EnumType.ONE.ordinal())); + + return null; + } + }, BinaryObjectException.class, "Conflicting enum values"); + } + + /** + * Checks the enum merge + * + * @throws Exception + */ + public void testEnumMerge() throws Exception { + startUp(false); + + final String enumName = "mergedEnum"; + + node1.binary().registerEnum(enumName, + F.asMap(EnumType.ONE.name(), EnumType.ONE.ordinal())); + + GridTestUtils.assertThrows(log, new Callable<Object> (){ + + @Override public Object call() throws Exception { + + node2.binary().registerEnum(enumName, + F.asMap(EnumType.TWO.name(), EnumType.ONE.ordinal())); + + return null; + } + }, BinaryObjectException.class, "Conflicting enum values. Name "); + + GridTestUtils.assertThrows(log, new Callable<Object> (){ + @Override public Object call() throws Exception { + + node2.binary().registerEnum(enumName, + F.asMap(EnumType.ONE.name(), EnumType.TWO.ordinal())); + + return null; + } + }, BinaryObjectException.class, "Conflicting enum values. Value "); + + node2.binary().registerEnum(enumName, + F.asMap(EnumType.ONE.name(), EnumType.ONE.ordinal(), + EnumType.TWO.name(), EnumType.TWO.ordinal())); + + Collection<BinaryObject> vals = node1.binary().type(enumName).enumValues(); + BinaryObject[] values = vals.toArray(new BinaryObject[vals.size()]); + + assertEquals(2, values.length); + + assertEquals(EnumType.ONE.ordinal(), values[0].enumOrdinal()); + assertEquals(EnumType.TWO.ordinal(), values[1].enumOrdinal()); + + assertEquals(EnumType.ONE.name(), values[0].enumName()); + assertEquals(EnumType.TWO.name(), values[1].enumName()); + } + + /** * Validate simple array. * * @param registered Registered flag. @@ -472,6 +602,16 @@ public class BinaryEnumsSelfTest extends GridCommonAbstractTest { assertEquals(node2.binary().typeId(EnumType.class.getName()), obj.type().typeId()); assertEquals(val.ordinal(), obj.enumOrdinal()); + + if (register) + assertEquals(val.name(), obj.enumName()); + } + + /** Register enum */ + private void defineEnum() { + node1.binary().registerEnum(EnumType.class.getName(), + F.asMap(EnumType.ONE.name(), EnumType.ONE.ordinal(), + EnumType.TWO.name(), EnumType.TWO.ordinal())); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/test/java/org/apache/ignite/internal/binary/TestCachingMetadataHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/TestCachingMetadataHandler.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/TestCachingMetadataHandler.java index 704c8f3..77cbffe 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/binary/TestCachingMetadataHandler.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/TestCachingMetadataHandler.java @@ -44,6 +44,11 @@ public class TestCachingMetadataHandler implements BinaryMetadataHandler { } /** {@inheritDoc} */ + @Override public BinaryMetadata metadata0(int typeId) throws BinaryObjectException { + return null; + } + + /** {@inheritDoc} */ @Override public BinaryType metadata(int typeId, int schemaId) throws BinaryObjectException { return null; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java index a5a35c1..984cf62 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java @@ -110,6 +110,9 @@ public class PlatformComputeEchoTask extends ComputeTaskAdapter<Integer, Object> /** Type: ignite uuid. */ private static final int TYPE_IGNITE_UUID = 22; + /** Type: binary enum. */ + private static final int TYPE_BINARY_ENUM = 23; + /** Default cache name. */ public static final String DEFAULT_CACHE_NAME = "default"; @@ -228,6 +231,16 @@ public class PlatformComputeEchoTask extends ComputeTaskAdapter<Integer, Object> case TYPE_IGNITE_UUID: return ignite.cache(DEFAULT_CACHE_NAME).get(TYPE_IGNITE_UUID); + case TYPE_BINARY_ENUM: { + Map<String, Integer> values = new HashMap<>(2); + values.put("JavaFoo", 1); + values.put("JavaBar", 2); + + ignite.binary().registerEnum("JavaDynEnum", values); + + return ignite.binary().buildEnum("JavaDynEnum", "JavaFoo"); + } + default: throw new IgniteException("Unknown type: " + type); } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs index a7794c6..61f90a3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs @@ -1140,6 +1140,9 @@ namespace Apache.Ignite.Core.Tests.Binary Assert.AreEqual(new[] { TestEnum.Two }, obj.FEnumArr); } + /// <summary> + /// Tests the enum metadata. + /// </summary> [Test] public void TestEnumMeta() { @@ -1148,14 +1151,21 @@ namespace Apache.Ignite.Core.Tests.Binary // Put to cache to populate metas var binEnum = bin.ToBinary<IBinaryObject>(TestEnumRegistered.One); - Assert.AreEqual(_marsh.GetDescriptor(typeof (TestEnumRegistered)).TypeId, binEnum.GetBinaryType().TypeId); + Assert.AreEqual(_marsh.GetDescriptor(typeof(TestEnumRegistered)).TypeId, binEnum.GetBinaryType().TypeId); Assert.AreEqual(0, binEnum.EnumValue); + Assert.AreEqual("One", binEnum.EnumName); var meta = binEnum.GetBinaryType(); Assert.IsTrue(meta.IsEnum); - Assert.AreEqual(GetTypeName(typeof (TestEnumRegistered)), meta.TypeName); + Assert.AreEqual(GetTypeName(typeof(TestEnumRegistered)), meta.TypeName); Assert.AreEqual(0, meta.Fields.Count); + + var enumValues = meta.GetEnumValues().OrderBy(x => x.EnumValue).ToArray(); + Assert.AreEqual(0, enumValues[0].EnumValue); + Assert.AreEqual("One", enumValues[0].EnumName); + Assert.AreEqual(1, enumValues[1].EnumValue); + Assert.AreEqual("Two", enumValues[1].EnumName); } /// <summary> @@ -1653,26 +1663,30 @@ namespace Apache.Ignite.Core.Tests.Binary { var binary = _grid.GetBinary(); - int val = (int)TestEnumRegistered.Two; + var enumVal = TestEnumRegistered.Two; + var intVal = (int) enumVal; var typeName = GetTypeName(typeof(TestEnumRegistered)); var typeId = BinaryUtils.GetStringHashCode(typeName); var binEnums = new[] { - binary.BuildEnum(typeof (TestEnumRegistered), val), - binary.BuildEnum(typeName, val) + binary.BuildEnum(typeof (TestEnumRegistered), intVal), + binary.BuildEnum(typeName, intVal), + binary.BuildEnum(typeof (TestEnumRegistered), enumVal.ToString()), + binary.BuildEnum(typeName, enumVal.ToString()) }; foreach (var binEnum in binEnums) { Assert.IsTrue(binEnum.GetBinaryType().IsEnum); - Assert.AreEqual(val, binEnum.EnumValue); + Assert.AreEqual(intVal, binEnum.EnumValue); + Assert.AreEqual(enumVal.ToString(), binEnum.EnumName); Assert.AreEqual(string.Format("{0} [typeId={1}, enumValue={2}, enumValueName={3}]", - typeName, typeId, val, (TestEnumRegistered) val), binEnum.ToString()); + typeName, typeId, intVal, enumVal), binEnum.ToString()); - Assert.AreEqual((TestEnumRegistered)val, binEnum.Deserialize<TestEnumRegistered>()); + Assert.AreEqual(enumVal, binEnum.Deserialize<TestEnumRegistered>()); } Assert.AreEqual(binEnums[0], binEnums[1]); @@ -1687,6 +1701,60 @@ namespace Apache.Ignite.Core.Tests.Binary } /// <summary> + /// Tests enum registration. + /// </summary> + [Test] + public void TestRegisterEnum() + { + var binary = _grid.GetBinary(); + + // Register enum and verify resulting type. + const string typeName = "DotNetDynEnum"; + var binType = binary.RegisterEnum(typeName, new Dictionary<string, int> {{"Baz", 3}, {"Bar", 4}}); + + Assert.AreEqual(typeName, binType.TypeName); + Assert.IsTrue(binType.IsEnum); + + var enumFields = binType.GetEnumValues().OrderBy(x => x.EnumValue).ToArray(); + Assert.AreEqual(new[] {3, 4}, enumFields.Select(x => x.EnumValue)); + Assert.AreEqual(new[] {"Baz", "Bar"}, enumFields.Select(x => x.EnumName)); + + // Build enum values. + var binEnum1 = binary.BuildEnum(typeName, 3); + var binEnum2 = binary.BuildEnum(typeName, "Baz"); + + Assert.AreEqual(binEnum1, binEnum2); + Assert.AreEqual("Baz", binEnum1.EnumName); + Assert.AreEqual(3, binEnum2.EnumValue); + + // Register additional value explicitly. + binary.RegisterEnum(typeName, new Dictionary<string, int> {{"Foo", 6}}); + binary.RegisterEnum(typeName, new Dictionary<string, int> {{"Foo", 6}, {"Baz", 3}}); + binType = binary.GetBinaryType(typeName); + + Assert.AreEqual(typeName, binType.TypeName); + Assert.IsTrue(binType.IsEnum); + + enumFields = binType.GetEnumValues().OrderBy(x => x.EnumValue).ToArray(); + Assert.AreEqual(new[] { 3, 4, 6 }, enumFields.Select(x => x.EnumValue)); + Assert.AreEqual(new[] { "Baz", "Bar", "Foo" }, enumFields.Select(x => x.EnumName)); + + // Register existing value with different name. + var ex = Assert.Throws<BinaryObjectException>( + () => binary.RegisterEnum(typeName, new Dictionary<string, int> {{"Baz1", 3}})); + + Assert.AreEqual(string.Format("Conflicting enum values. Name 'Baz1' uses ordinal value (3) that " + + "is also used for name 'Baz' [typeName='{0}']", typeName), ex.Message); + + // Register different value with existing name. + ex = Assert.Throws<BinaryObjectException>( + () => binary.RegisterEnum(typeName, new Dictionary<string, int> {{"Baz", 33}})); + + Assert.AreEqual(string.Format("Conflicting enum values. Value (33) has name 'Baz' that is " + + "also used for value '3' [typeName='{0}']", typeName), ex.Message); + } + + /// <summary> /// Tests the compact footer setting. /// </summary> [Test] @@ -2102,13 +2170,13 @@ namespace Apache.Ignite.Core.Tests.Binary /** <inheritdoc /> */ public int GetTypeId(string typeName) { - return typeName == TestTypeName ? TestTypeId : 0; + return typeName == TestTypeName ? TestTypeId : BinaryUtils.GetStringHashCode(typeName); } /** <inheritdoc /> */ public int GetFieldId(int typeId, string fieldName) { - return 0; + return BinaryUtils.GetStringHashCode(fieldName); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs index b9b7a04..1d8ceb9 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs @@ -122,6 +122,9 @@ namespace Apache.Ignite.Core.Tests.Compute /** Echo type: IgniteUuid. */ private const int EchoTypeIgniteUuid = 22; + /** Echo type: binary enum (created with builder). */ + private const int EchoTypeBinaryEnum = 23; + /** */ private const string DefaultCacheName = "default"; @@ -940,6 +943,28 @@ namespace Apache.Ignite.Core.Tests.Compute /// Tests the echo task returning enum. /// </summary> [Test] + public void TestEchoTaskBinaryEnum() + { + var res = _grid1.GetCompute().WithKeepBinary() + .ExecuteJavaTask<IBinaryObject>(EchoTask, EchoTypeBinaryEnum); + + Assert.AreEqual("JavaFoo", res.EnumName); + Assert.AreEqual(1, res.EnumValue); + + var binType = res.GetBinaryType(); + + Assert.IsTrue(binType.IsEnum); + Assert.AreEqual("JavaDynEnum", binType.TypeName); + + var vals = binType.GetEnumValues().OrderBy(x => x.EnumValue).ToArray(); + Assert.AreEqual(new[] {1, 2}, vals.Select(x => x.EnumValue)); + Assert.AreEqual(new[] {"JavaFoo", "JavaBar"}, vals.Select(x => x.EnumName)); + } + + /// <summary> + /// Tests the echo task returning enum. + /// </summary> + [Test] public void TestEchoTaskEnumFromCache() { var cache = _grid1.GetCache<int, PlatformComputeEnum>(DefaultCacheName); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs index c36b9fd..2d299f3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs @@ -18,6 +18,7 @@ namespace Apache.Ignite.Core.Binary { using System; + using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Common; /// <summary> @@ -51,7 +52,7 @@ namespace Apache.Ignite.Core.Binary IgniteArgumentCheck.NotNull(type, "type"); TypeName = type.AssemblyQualifiedName; - IsEnum = type.IsEnum; + IsEnum = BinaryUtils.IsIgniteEnum(type); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs index f269681..671efa4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs @@ -131,5 +131,29 @@ namespace Apache.Ignite.Core.Binary /// <param name="value">Enum int value.</param> /// <returns>Binary representation of the specified enum value.</returns> IBinaryObject BuildEnum(Type type, int value); + + /// <summary> + /// Converts enum to a binary form. + /// </summary> + /// <param name="typeName">Enum type name.</param> + /// <param name="valueName">Enum value name.</param> + /// <returns>Binary representation of the specified enum value.</returns> + IBinaryObject BuildEnum(string typeName, string valueName); + + /// <summary> + /// Converts enum to a binary form. + /// </summary> + /// <param name="type">Enum type.</param> + /// <param name="valueName">Enum value name.</param> + /// <returns>Binary representation of the specified enum value.</returns> + IBinaryObject BuildEnum(Type type, string valueName); + + /// <summary> + /// Registers enum type. + /// </summary> + /// <param name="typeName">Name of the type.</param> + /// <param name="values">Mapping of enum value names to int values.</param> + /// <returns>Binary type for registered enum.</returns> + IBinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values); } }