This is an automated email from the ASF dual-hosted git repository.
shishkovilja pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new a20d1c0f302 IGNITE-28928 Use MessageSerializer for
SecurityPermissionSet (#13414)
a20d1c0f302 is described below
commit a20d1c0f3022d43230b28a7eada1748dd81e69df
Author: Ilya Shishkov <[email protected]>
AuthorDate: Fri Jul 31 10:40:07 2026 +0300
IGNITE-28928 Use MessageSerializer for SecurityPermissionSet (#13414)
---
.../apache/ignite/internal/MessageProcessor.java | 127 +++++++++++++++---
.../internal/MessageSerializerGenerator.java | 46 ++++---
.../ignite/internal/CoreMessagesProvider.java | 2 +
.../direct/stream/DirectByteBufferStream.java | 9 ++
.../security/SecurityBasicPermissionSet.java | 52 +++----
.../plugin/security/SecurityPermissionSet.java | 3 +-
.../internal/codegen/MessageProcessorTest.java | 70 +++++++++-
...ecurityBasicPermissionSetSerializationTest.java | 149 +++++++++++++++++++++
.../security/SecurityPermissionSetBuilderTest.java | 2 +-
.../ignite/testsuites/SecurityTestSuite.java | 2 +
...ustomEnumMapperOnNonEnumCollectionMessage.java} | 11 +-
...va => CustomEnumMapperOnNonEnumMapMessage.java} | 11 +-
.../codegen/CustomMapperEnumFieldsMessage.java | 7 +-
.../CustomMapperEnumFieldsMessageSerializer.java | 21 ++-
.../codegen/DefaultMapperEnumFieldsMessage.java | 9 ++
.../DefaultMapperEnumFieldsMessageSerializer.java | 46 ++++++-
... => DefaultMapperEnumMapCollectionMessage.java} | 9 +-
...a => TwoDifferentEnumsInCollectionMessage.java} | 10 +-
.../communication/MessageCollectionItemType.java | 5 +-
.../extensions/communication/MessageEnumType.java | 59 ++++++++
20 files changed, 562 insertions(+), 88 deletions(-)
diff --git
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java
index d15090e4436..23e110b1eb4 100644
---
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java
+++
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -39,8 +40,10 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import
org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor;
import org.apache.ignite.internal.util.typedef.F;
@@ -294,34 +297,99 @@ public class MessageProcessor extends AbstractProcessor {
private void validateEnumFieldMapping(TypeElement type, Element el) {
CustomMapper custMappAnn = el.getAnnotation(CustomMapper.class);
- if (enumType(processingEnv, el.asType())) {
- String enumClsFullName = el.asType().toString();
- String enumMapperClsName = custMappAnn != null ?
custMappAnn.value() : DLFT_ENUM_MAPPER_CLS;
- String msgClsName = type.toString();
+ Map<Element, String> enumsPerField = new HashMap<>();
- IgniteBiTuple<String, String> otherMsgAndMapperClassesNames =
- enumMappersInUse.put(enumClsFullName, new
IgniteBiTuple<>(msgClsName, enumMapperClsName));
+ if (!inspectFieldForEnumTypes(type.toString(), el, el.asType(),
custMappAnn, enumsPerField) && custMappAnn != null) {
+ processingEnv.getMessager().printMessage(
+ Diagnostic.Kind.ERROR,
+ "Annotation @CustomMapper must only be used for enum fields or
enum collections and maps, including nested ones.",
+ el);
+ }
+ }
+
+ /**
+ * @param msgClsName Message class name currently being inspected.
+ * @param field Field being inspected.
+ * @param type Type that should be inpected for enum type (direct type or
type parameter).
+ * @param custMappAnn Custom mapper annotation declared for the enum type.
+ * @param enumsPerField Map for collecting enum types related to a
particular field.
+ */
+ private boolean inspectFieldForEnumTypes(String msgClsName, Element field,
TypeMirror type, CustomMapper custMappAnn,
+ Map<Element, String> enumsPerField) {
+ String enumClsFullName = type.toString();
+ String enumMapperClsName = custMappAnn != null ? custMappAnn.value() :
DLFT_ENUM_MAPPER_CLS;
- if (otherMsgAndMapperClassesNames != null) {
- String otherMsgClsName = otherMsgAndMapperClassesNames.get1();
- String otherEnumMapperClsName =
otherMsgAndMapperClassesNames.get2();
+ if (enumType(processingEnv, type)) {
+ inspectForDuplicatedMappers(msgClsName, field, enumClsFullName,
enumMapperClsName);
- if (!otherEnumMapperClsName.equals(enumMapperClsName)) {
- processingEnv.getMessager().printMessage(
- Diagnostic.Kind.ERROR,
- "Enum " + enumClsFullName + " is declared with
different mappers: " +
- otherEnumMapperClsName + " in " + otherMsgClsName
+ " and " +
- enumMapperClsName + " in " + msgClsName +
- ". Only one mapper is allowed per enum type.",
- el);
- }
+ inspectForDuplicatedEnums(msgClsName, field, type, enumsPerField);
+
+ return true;
+ }
+ else if (assignableFrom(erasedType(type),
type(Collection.class.getName()))) {
+ List<? extends TypeMirror> typeArgs =
((DeclaredType)type).getTypeArguments();
+
+ assert typeArgs.size() == 1 : type.toString();
+
+ TypeMirror typeArg = typeArgs.get(0);
+
+ return inspectFieldForEnumTypes(msgClsName, field, typeArg,
custMappAnn, enumsPerField);
+ }
+ else if (assignableFrom(erasedType(type), type(Map.class.getName()))) {
+ List<? extends TypeMirror> typeArgs =
((DeclaredType)type).getTypeArguments();
+
+ assert typeArgs.size() == 2 : type.toString();
+
+ TypeMirror keyType = typeArgs.get(0);
+ TypeMirror valType = typeArgs.get(1);
+
+ return inspectFieldForEnumTypes(msgClsName, field, keyType,
custMappAnn, enumsPerField) |
+ inspectFieldForEnumTypes(msgClsName, field, valType,
custMappAnn, enumsPerField);
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks, that only single type of mapper is used for the enum type.
+ * Particular enum should be processed with a concrete enum mapper: custom
or default one.
+ */
+ private void inspectForDuplicatedMappers(String msgClsName, Element field,
String enumClsFullName,
+ String enumMapperClsName) {
+ IgniteBiTuple<String, String> otherMsgAndMapperClassesNames =
+ enumMappersInUse.put(enumClsFullName, new
IgniteBiTuple<>(msgClsName, enumMapperClsName));
+
+ if (otherMsgAndMapperClassesNames != null) {
+ String otherMsgClsName = otherMsgAndMapperClassesNames.get1();
+ String otherEnumMapperClsName =
otherMsgAndMapperClassesNames.get2();
+
+ if (!otherEnumMapperClsName.equals(enumMapperClsName)) {
+ processingEnv.getMessager().printMessage(
+ Diagnostic.Kind.ERROR,
+ "Enum " + enumClsFullName + " is declared with different
mappers: " +
+ otherEnumMapperClsName + " in " + otherMsgClsName + "
and " +
+ enumMapperClsName + " in " + msgClsName +
+ ". Only one mapper is allowed per enum type.",
+ field);
}
}
- else if (custMappAnn != null) {
+ }
+
+ /**
+ * Checks that only single type of enum is introduced for a particular
field.
+ * Multiple enum types currently are not supported for custom mapper.
+ */
+ private void inspectForDuplicatedEnums(String msgClsName, Element field,
TypeMirror type,
+ Map<Element, String> enumsPerField) {
+ String otherEnum = type.toString();
+ String existingEnum = enumsPerField.put(field, otherEnum);
+
+ if (existingEnum != null && !Objects.equals(existingEnum, otherEnum)) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR,
- "Annotation @CustomMapper must only be used for enum fields.",
- el);
+ String.format("Multiple enums of different types are not
supported for a single field " +
+ "[msgClsName=%s, field=%s, existingEnumType=%s,
otherEnumType=%s]", msgClsName,
+ field.getSimpleName(), existingEnum, otherEnum));
}
}
@@ -345,4 +413,21 @@ public class MessageProcessor extends AbstractProcessor {
.flatMap(c ->
ElementFilter.fieldsIn(c.getEnclosedElements()).stream())
.anyMatch(f -> f.getAnnotation(Marshalled.class) != null);
}
+
+ /** */
+ boolean assignableFrom(TypeMirror type, TypeMirror superType) {
+ return superType != null &&
processingEnv.getTypeUtils().isAssignable(type, superType);
+ }
+
+ /** */
+ TypeMirror erasedType(TypeMirror type) {
+ return processingEnv.getTypeUtils().erasure(type);
+ }
+
+ /** @return the {@link TypeMirror} for the fully-qualified {@code clazz},
or {@code null} if not on classpath. */
+ TypeMirror type(String clazz) {
+ Elements elementUtils = processingEnv.getElementUtils();
+ TypeElement typeElement = elementUtils.getTypeElement(clazz);
+ return typeElement != null ? typeElement.asType() : null;
+ }
}
diff --git
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
index d3344ea8003..6ae7e029410 100644
---
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
+++
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
@@ -41,6 +41,7 @@ import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import
org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor;
+import org.apache.ignite.internal.util.typedef.F;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.MessageProcessor.CACHE_OBJECT_CLS;
@@ -110,6 +111,9 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
/** */
private final List<String> read = new ArrayList<>();
+ /** Static class fields, which should come before ordinary class fields. */
+ private final Set<String> headingClsFields = new TreeSet<>();
+
/** Class-field declarations (enum mappers/values, collection descriptors)
emitted at the top of the generated class. */
private final Set<String> clsFields = new TreeSet<>();
@@ -261,7 +265,7 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
/** @return Writer/reader call expression for {@code field}. */
private String callExpr(VariableElement field, boolean write) throws
Exception {
if (enumType(env, field.asType())) {
- String prefix = registerEnumMapper(field);
+ String prefix = registerEnumMapper(field, field.asType());
boolean custMapper = field.getAnnotation(CustomMapper.class) !=
null;
@@ -425,8 +429,8 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
*
* @return Class-field name prefix derived from the enum type name.
*/
- private String registerEnumMapper(VariableElement field) {
- Element enumElem = env.getTypeUtils().asElement(field.asType());
+ private String registerEnumMapper(VariableElement field, TypeMirror
fieldType) {
+ Element enumElem = env.getTypeUtils().asElement(fieldType);
imports.add(enumElem.toString());
@@ -446,12 +450,12 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
String simpleName =
fullMapperName.substring(fullMapperName.lastIndexOf('.') + 1);
- clsFields.add("private final EnumMapper<" + enumName + "> " +
prefix + "Mapper = new " + simpleName + "();");
+ headingClsFields.add("private static final EnumMapper<" + enumName
+ "> " + prefix + "Mapper = new " + simpleName + "();");
}
else {
imports.add(DLFT_ENUM_MAPPER_CLS);
- clsFields.add("private final " + enumName + "[] " + prefix + "Vals
= " + enumName + ".values();");
+ headingClsFields.add("private static final " + enumName + "[] " +
prefix + "Vals = " + enumName + ".values();");
}
return prefix;
@@ -488,7 +492,7 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
/** */
private String messageCollectionItemTypes(VariableElement field,
TypeMirror type) throws Exception {
- String desc = messageCollectionItemTypeDescriptor(type);
+ String desc = messageCollectionItemTypeDescriptor(type, field);
String descName = field.getSimpleName() + "CollDesc";
String typeName = desc.substring(desc.indexOf(' ') + 1,
desc.indexOf('('));
@@ -498,7 +502,7 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
}
/** */
- private String messageCollectionItemTypeDescriptor(TypeMirror type) throws
Exception {
+ private String messageCollectionItemTypeDescriptor(TypeMirror type,
VariableElement field) throws Exception {
imports.add(MESSAGE_COLLECTION_ITEM_TYPE_CLS);
if (type.getKind() == TypeKind.ARRAY) {
@@ -527,18 +531,18 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
imports.add(MESSAGE_ARRAY_TYPE_CLS);
- return "new MessageArrayType(" +
messageCollectionItemTypeDescriptor(componentType) + ", " + clazz + ")";
+ return "new MessageArrayType(" +
messageCollectionItemTypeDescriptor(componentType, field) + ", " + clazz + ")";
}
else if (assignableFrom(erasedType(type), type(Map.class.getName()))) {
imports.add(MESSAGE_MAP_TYPE_CLS);
List<? extends TypeMirror> typeArgs =
((DeclaredType)type).getTypeArguments();
- assert typeArgs.size() == 2;
+ assert typeArgs.size() == 2 : type.toString();
return "new MessageMapType(" +
- messageCollectionItemTypeDescriptor(typeArgs.get(0)) + ", " +
- messageCollectionItemTypeDescriptor(typeArgs.get(1)) + ", " +
+ messageCollectionItemTypeDescriptor(typeArgs.get(0), field) +
", " +
+ messageCollectionItemTypeDescriptor(typeArgs.get(1), field) +
", " +
assignableFrom(erasedType(type),
type(LinkedHashMap.class.getName())) + ")";
}
else if (assignableFrom(erasedType(type),
type(Collection.class.getName()))) {
@@ -546,12 +550,24 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
List<? extends TypeMirror> typeArgs =
((DeclaredType)type).getTypeArguments();
- assert typeArgs.size() == 1;
+ assert typeArgs.size() == 1 : type.toString();
return "new MessageCollectionType(" +
- messageCollectionItemTypeDescriptor(typeArgs.get(0)) + ", " +
+ messageCollectionItemTypeDescriptor(typeArgs.get(0), field) +
", " +
assignableFrom(erasedType(type), type(Set.class.getName())) +
")";
}
+ else if (enumType(env, type)) {
+
imports.add("org.apache.ignite.plugin.extensions.communication.MessageEnumType");
+
+ String prefix = registerEnumMapper(field, type);
+ boolean custMapper = field.getAnnotation(CustomMapper.class) !=
null;
+
+ String encoder = (custMapper ? prefix + "Mapper" :
"DefaultEnumMapper.INSTANCE") + "::encode";
+ String decoder = custMapper ? prefix + "Mapper::decode" :
+ "b -> DefaultEnumMapper.INSTANCE.decode(" + prefix + "Vals,
b)";
+
+ return String.format("new MessageEnumType<>(%s, %s)", encoder,
decoder);
+ }
else {
imports.add(MESSAGE_ITEM_TYPE_CLS);
@@ -656,10 +672,10 @@ public class MessageSerializerGenerator extends
MessageCompanionGenerator {
/** Write serializer class fields: enum values, custom enum mappers,
collection descriptors. */
private void writeClassFields(Writer writer) throws IOException {
- if (clsFields.isEmpty())
+ if (headingClsFields.isEmpty() && clsFields.isEmpty())
return;
- for (String field: clsFields) {
+ for (String field: F.concat(false, headingClsFields, clsFields)) {
writer.write(indentedLine(METHOD_JAVADOC));
writer.write(NL);
writer.write(indentedLine(field));
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
index 7921779c09e..fa6514e2148 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
@@ -270,6 +270,7 @@ import
org.apache.ignite.internal.util.distributed.SingleNodeMessage;
import org.apache.ignite.marshaller.Marshaller;
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.security.SecurityBasicPermissionSet;
import org.apache.ignite.spi.collision.jobstealing.JobStealingRequest;
import
org.apache.ignite.spi.communication.tcp.internal.TcpConnectionRequestDiscoveryMessage;
import
org.apache.ignite.spi.communication.tcp.internal.TcpInverseConnectionResponseMessage;
@@ -667,6 +668,7 @@ public class CoreMessagesProvider extends
AbstractMarshallableMessageFactoryProv
withNoSchema(UserAuthenticateResponseMessage.class);
withNoSchema(TcpDiscoveryAuthFailedMessage.class);
withNoSchema(AuthentificationDataBagItem.class);
+ withNoSchema(SecurityBasicPermissionSet.class);
// [12200 - 12300]: Binary, classloading and marshalling messages.
msgIdx = 12200;
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
index 6b673aa88d4..75440117e23 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
@@ -50,6 +50,7 @@ import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.apache.ignite.plugin.extensions.communication.MessageArrayType;
import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
+import org.apache.ignite.plugin.extensions.communication.MessageEnumType;
import org.apache.ignite.plugin.extensions.communication.MessageFactory;
import org.apache.ignite.plugin.extensions.communication.MessageMapType;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
@@ -2134,6 +2135,11 @@ public class DirectByteBufferStream {
break;
+ case ENUM:
+ writeByte(((MessageEnumType)type).encode((Enum<?>)val));
+
+ break;
+
case MSG:
writeMessage((Message)val, writer);
@@ -2247,6 +2253,9 @@ public class DirectByteBufferStream {
case ARRAY:
return nestedRead(reader, () ->
reader.readObjectArray((MessageArrayType)type));
+ case ENUM:
+ return ((MessageEnumType)type).decode(readByte());
+
case MSG:
return readMessage(reader);
diff --git
a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
index 87587afa90e..3daf23d9088 100644
---
a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
+++
b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import org.apache.ignite.internal.Order;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.S;
@@ -45,24 +46,29 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
/** Cache permissions. */
@GridToStringInclude
- private Map<String, Collection<SecurityPermission>> cachePermissions = new
HashMap<>();
+ @Order(0)
+ Map<String, Collection<SecurityPermission>> cachePermissions = new
HashMap<>();
/** Task permissions. */
@GridToStringInclude
- private Map<String, Collection<SecurityPermission>> taskPermissions = new
HashMap<>();
+ @Order(1)
+ Map<String, Collection<SecurityPermission>> taskPermissions = new
HashMap<>();
/** Service permissions. */
@GridToStringInclude
- private transient Map<String, Collection<SecurityPermission>>
servicePermissions = isSecurityCompatibilityMode()
+ @Order(2)
+ transient Map<String, Collection<SecurityPermission>> srvcPermissions =
isSecurityCompatibilityMode()
? compatibleServicePermissions()
- : new HashMap<String, Collection<SecurityPermission>>();
+ : new HashMap<>();
/** System permissions. */
@GridToStringInclude
- private Collection<SecurityPermission> systemPermissions;
+ @Order(3)
+ Collection<SecurityPermission> sysPermissions;
/** Default allow all. */
- private boolean dfltAllowAll;
+ @Order(4)
+ boolean dfltAllowAll;
/**
* Setter for set cache permission map.
@@ -89,21 +95,21 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
/**
* Setter for set service permission map.
*
- * @param servicePermissions Service permissions.
+ * @param srvcPermissions Service permissions.
*/
- public void setServicePermissions(Map<String,
Collection<SecurityPermission>> servicePermissions) {
+ public void setServicePermissions(Map<String,
Collection<SecurityPermission>> srvcPermissions) {
A.notNull(taskPermissions, "servicePermissions");
- this.servicePermissions = servicePermissions;
+ this.srvcPermissions = srvcPermissions;
}
/**
* Setter for set collection system permission.
*
- * @param systemPermissions System permissions.
+ * @param sysPermissions System permissions.
*/
- public void setSystemPermissions(Collection<SecurityPermission>
systemPermissions) {
- this.systemPermissions = systemPermissions;
+ public void setSystemPermissions(Collection<SecurityPermission>
sysPermissions) {
+ this.sysPermissions = sysPermissions;
}
/**
@@ -127,12 +133,12 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
/** {@inheritDoc} */
@Override public Map<String, Collection<SecurityPermission>>
servicePermissions() {
- return servicePermissions;
+ return srvcPermissions;
}
/** {@inheritDoc} */
@Nullable @Override public Collection<SecurityPermission>
systemPermissions() {
- return systemPermissions;
+ return sysPermissions;
}
/** {@inheritDoc} */
@@ -153,8 +159,8 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
return dfltAllowAll == other.dfltAllowAll &&
Objects.equals(cachePermissions, other.cachePermissions) &&
Objects.equals(taskPermissions, other.taskPermissions) &&
- Objects.equals(servicePermissions, other.servicePermissions) &&
- Objects.equals(systemPermissions, other.systemPermissions);
+ Objects.equals(srvcPermissions, other.srvcPermissions) &&
+ Objects.equals(sysPermissions, other.sysPermissions);
}
/** {@inheritDoc} */
@@ -163,8 +169,8 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
res = 31 * res + (cachePermissions != null ?
cachePermissions.hashCode() : 0);
res = 31 * res + (taskPermissions != null ? taskPermissions.hashCode()
: 0);
- res = 31 * res + (servicePermissions != null ?
servicePermissions.hashCode() : 0);
- res = 31 * res + (systemPermissions != null ?
systemPermissions.hashCode() : 0);
+ res = 31 * res + (srvcPermissions != null ? srvcPermissions.hashCode()
: 0);
+ res = 31 * res + (sysPermissions != null ? sysPermissions.hashCode() :
0);
return res;
}
@@ -176,7 +182,7 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
out.defaultWriteObject();
if (serializeVersion() >= 2)
- U.writeMap(out, servicePermissions);
+ U.writeMap(out, srvcPermissions);
}
/**
@@ -186,14 +192,14 @@ public class SecurityBasicPermissionSet implements
SecurityPermissionSet {
in.defaultReadObject();
if (serializeVersion() >= 2)
- servicePermissions = U.readMap(in);
+ srvcPermissions = U.readMap(in);
- if (servicePermissions == null) {
+ if (srvcPermissions == null) {
// Allow all for compatibility mode
if (serializeVersion() < 2)
- servicePermissions = compatibleServicePermissions();
+ srvcPermissions = compatibleServicePermissions();
else
- servicePermissions = Collections.emptyMap();
+ srvcPermissions = Collections.emptyMap();
}
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSet.java
b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSet.java
index 96340d8d149..20e78c6efab 100644
---
a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSet.java
+++
b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSet.java
@@ -20,6 +20,7 @@ package org.apache.ignite.plugin.security;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
+import org.apache.ignite.plugin.extensions.communication.Message;
import org.jetbrains.annotations.Nullable;
/**
@@ -31,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
* Property {@link #defaultAllowAll()} specifies whether to allow or deny
* cache and task operations if they were not explicitly specified.
*/
-public interface SecurityPermissionSet extends Serializable {
+public interface SecurityPermissionSet extends Serializable, Message {
/**
* Flag indicating whether to allow or deny cache and task operations
* if they were not explicitly specified.
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
index 30901aefd3d..24b8232cdd1 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
@@ -51,6 +51,10 @@ import static org.junit.Assert.assertTrue;
/** */
public class MessageProcessorTest {
+ /** Custom mapper error. */
+ public static final String CUSTOM_MAPPER_ERROR = "Annotation @CustomMapper
must only be used for enum fields or " +
+ "enum collections and maps, including nested ones.";
+
/** */
@Test
public void testMarshalledObjectsMessage() {
@@ -273,7 +277,7 @@ public class MessageProcessorTest {
Compilation compilation =
compile("CustomEnumMapperOnPrimitiveFieldMessage.java");
assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("Annotation @CustomMapper
must only be used for enum fields.");
+ assertThat(compilation).hadErrorContaining(CUSTOM_MAPPER_ERROR);
}
/**
@@ -285,7 +289,50 @@ public class MessageProcessorTest {
Compilation compilation =
compile("CustomEnumMapperOnArrayFieldMessage.java");
assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("Annotation @CustomMapper
must only be used for enum fields.");
+ assertThat(compilation).hadErrorContaining(CUSTOM_MAPPER_ERROR);
+ }
+
+ /**
+ * Negative test for CustomMapper annotation verifying an error is thrown
by codegeneration tool if
+ * the annotation is used with a collection, which does not store enums.
+ */
+ @Test
+ public void testCustomMapperCannotBeUsedOnNonEnumCollection() {
+ Compilation compilation =
compile("CustomEnumMapperOnArrayFieldMessage.java");
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorContaining(CUSTOM_MAPPER_ERROR);
+ }
+
+ /**
+ * Negative test for CustomMapper annotation verifying an error is thrown
by codegeneration tool if
+ * the annotation is used with a collection, which does not store enums.
+ */
+ @Test
+ public void testCustomMapperCannotBeUsedOnNonEnumMap() {
+ Compilation compilation =
compile("CustomEnumMapperOnNonEnumMapMessage.java");
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorContaining(CUSTOM_MAPPER_ERROR);
+ }
+
+ /**
+ * Negative test for enum mapper verifying an error is thrown by
codegeneration tool if
+ * the annotation is used with a collection with nested enums of different
type.
+ */
+ @Test
+ public void testEnumMapperCannotBeTwoEnums() {
+ Compilation compilation =
compile("TwoDifferentEnumsInCollectionMessage.java");
+
+ assertThat(compilation).failed();
+
+ String oai = "org.apache.ignite.";
+
+ assertThat(compilation).hadErrorContaining(String.format("Multiple
enums of different types are not supported " +
+ "for a single field [msgClsName=%s, field=%s, existingEnumType=%s,
otherEnumType=%s]",
+ oai + "internal.TwoDifferentEnumsInCollectionMessage", "col",
+ oai + "transactions.TransactionIsolation",
+ oai + "internal.processors.cache.GridCacheOperation"));
}
/**
@@ -343,6 +390,25 @@ public class MessageProcessorTest {
assertThat(compilation).hadErrorContaining(errMsg);
}
+ /**
+ * Negative test for a conflict situation when two enum mappers are used
for the same enum in different messages.
+ * Tests conflict between ordinary enum field and collection of enums.
+ */
+ @Test
+ public void
testDifferentMappersForTheSameEnumAreProhibitedWithCollection() {
+ Compilation compilation =
compile("DefaultMapperEnumMapCollectionMessage.java",
+ "CustomMapperEnumFieldsMessage.java",
+ "TransactionIsolationEnumMapper.java");
+
+ assertThat(compilation).failed();
+
+ String errMsg = "Enum " + TransactionIsolation.class.getName() + " is
declared with different mappers: " +
+ DefaultEnumMapper.class.getName() + " in
org.apache.ignite.internal.DefaultMapperEnumMapCollectionMessage" +
+ " and org.apache.ignite.internal.TransactionIsolationEnumMapper in
org.apache.ignite.internal.CustomMapperEnumFieldsMessage.";
+
+ assertThat(compilation).hadErrorContaining(errMsg);
+ }
+
/**
* Positive test verifies that codegeneration is successful when two
messages use DefaultEnumMapper for the same enum type.
*/
diff --git
a/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
b/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
new file mode 100644
index 00000000000..5d94d4e8847
--- /dev/null
+++
b/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.plugin.security;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.CoreMessagesProvider;
+import org.apache.ignite.internal.direct.DirectMessageReader;
+import org.apache.ignite.internal.direct.DirectMessageWriter;
+import
org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl;
+import org.apache.ignite.internal.util.nio.MessageSerialization;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MessageFactory;
+import
org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.GridTestKernalContext;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.util.CommonUtils.makeMessageType;
+import static org.apache.ignite.marshaller.Marshallers.jdk;
+import static org.apache.ignite.plugin.security.SecurityPermission.ADMIN_CACHE;
+import static org.apache.ignite.plugin.security.SecurityPermission.ADMIN_QUERY;
+import static
org.apache.ignite.plugin.security.SecurityPermission.CACHE_CREATE;
+import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_PUT;
+import static
org.apache.ignite.plugin.security.SecurityPermission.SERVICE_CANCEL;
+import static
org.apache.ignite.plugin.security.SecurityPermission.SERVICE_INVOKE;
+import static org.apache.ignite.plugin.security.SecurityPermission.TASK_CANCEL;
+import static
org.apache.ignite.plugin.security.SecurityPermission.TASK_EXECUTE;
+
+/** Test for serialization round-trip of {@link SecurityBasicPermissionSet}. */
+public class SecurityBasicPermissionSetSerializationTest extends
GridCommonAbstractTest {
+ /** */
+ private final MessageFactory<? extends Message> msgFactory = new
IgniteMessageFactoryImpl<>(
+ new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk())});
+
+ /** */
+ @Test
+ public void testWriteAndReadBack() throws Exception {
+ SecurityBasicPermissionSet src = new SecurityBasicPermissionSet();
+
+ src.setDefaultAllowAll(true);
+ src.setSystemPermissions(F.asList(ADMIN_CACHE, ADMIN_QUERY, null));
+ src.setTaskPermissions(Map.of("task", F.asList(TASK_EXECUTE, null,
TASK_CANCEL)));
+ src.setServicePermissions(Map.of("service", Set.of(SERVICE_INVOKE,
SERVICE_CANCEL)));
+ src.setCachePermissions(Map.of("cache", Set.of(CACHE_CREATE,
CACHE_PUT)));
+
+ src.setCachePermissions(Map.of("cache", Set.of(CACHE_CREATE,
CACHE_PUT)));
+ SecurityBasicPermissionSet res = writeAndReadBack(src);
+
+ assertTrue("Permission sets are not equal [src=" + src + ", res=" +
res + "]", deepEquals(src, res));
+ }
+
+ /**
+ * @param msg Message to write and read back through {@link
DirectMessageWriter}/{@link DirectMessageReader}.
+ * @param <T> Type of Message.
+ *
+ * @return Restored message.
+ */
+ private <T extends Message> T writeAndReadBack(T msg) throws
IgniteCheckedException {
+ GridTestKernalContext kctx = newContext();
+
+ GridTestUtils.setFieldValue(kctx.grid(), "msgFactory", msgFactory);
+
+ ByteBuffer buf = ByteBuffer.allocate(64 * 1024);
+
+ DirectMessageWriter writer = new DirectMessageWriter(msgFactory);
+ writer.setBuffer(buf);
+
+ assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer));
+
+ buf.flip();
+
+ DirectMessageReader reader = new DirectMessageReader(msgFactory, null);
+ reader.setBuffer(buf);
+
+ T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get()));
+
+ assertTrue(MessageSerialization.readFrom(msgFactory, res, reader));
+
+ return res;
+ }
+
+ /**
+ * Perfroms deep equals of permission sets.
+ *
+ * @param lhs First permissions set for equality check.
+ * @param rhs Second permissions set for equality check.
+ * @return Whether specified permission sets are equal.
+ */
+ public static boolean deepEquals(SecurityPermissionSet lhs,
SecurityPermissionSet rhs) {
+ if (lhs == rhs)
+ return true;
+
+ return lhs != null
+ && rhs != null
+ && lhs.defaultAllowAll() == rhs.defaultAllowAll()
+ && (F.isEmpty(rhs.systemPermissions()) &&
F.isEmpty(rhs.systemPermissions())
+ || F.eqNotOrdered(rhs.systemPermissions(),
lhs.systemPermissions()))
+ && eqNotOrdered(rhs.taskPermissions(), lhs.taskPermissions())
+ && eqNotOrdered(rhs.servicePermissions(), lhs.servicePermissions())
+ && eqNotOrdered(rhs.cachePermissions(), lhs.cachePermissions());
+ }
+
+ /**
+ * @param m1 First map to check.
+ * @param m2 Second map to check
+ * @return {@code True} is maps are equal, {@code False} otherwise.
+ */
+ public static boolean eqNotOrdered(
+ @Nullable Map<String, Collection<SecurityPermission>> m1,
+ @Nullable Map<String, Collection<SecurityPermission>> m2) {
+ if (m1 == m2)
+ return true;
+
+ if (m1 == null || m2 == null)
+ return false;
+
+ if (m1.size() != m2.size())
+ return false;
+
+ for (Map.Entry<String, Collection<SecurityPermission>> e :
m1.entrySet()) {
+ if (!F.eqNotOrdered(e.getValue(), m2.get(e.getKey())))
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git
a/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilderTest.java
b/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilderTest.java
index 71a63938daf..04fee907d95 100644
---
a/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilderTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilderTest.java
@@ -143,7 +143,7 @@ public class SecurityPermissionSetBuilderTest extends
GridCommonAbstractTest {
* @param perms Permissions.
* @return Collection.
*/
- private static Collection<SecurityPermission>
permissions(SecurityPermission... perms) {
+ static Collection<SecurityPermission> permissions(SecurityPermission...
perms) {
Collection<SecurityPermission> col = U.newHashSet(perms.length);
Collections.addAll(col, perms);
diff --git
a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
index 2f34fcc88d8..375908bcca8 100644
---
a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
+++
b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java
@@ -76,6 +76,7 @@ import
org.apache.ignite.internal.processors.security.service.ServiceStaticConfi
import
org.apache.ignite.internal.processors.security.snapshot.SnapshotPermissionCheckTest;
import
org.apache.ignite.internal.thread.context.OperationContextAttributePropagationTest;
import
org.apache.ignite.internal.thread.context.OperationContextAttributesTest;
+import
org.apache.ignite.plugin.security.SecurityBasicPermissionSetSerializationTest;
import org.apache.ignite.ssl.MultipleSSLContextsTest;
import org.apache.ignite.tools.junit.JUnitTeamcityReporter;
import org.junit.BeforeClass;
@@ -151,6 +152,7 @@ import org.junit.runners.Suite;
NodeConnectionCertificateCapturingTest.class,
OperationContextAttributesTest.class,
OperationContextAttributePropagationTest.class,
+ SecurityBasicPermissionSetSerializationTest.class,
})
public class SecurityTestSuite {
/** */
diff --git
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
b/modules/core/src/test/resources/codegen/CustomEnumMapperOnNonEnumCollectionMessage.java
similarity index 80%
copy from
modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
copy to
modules/core/src/test/resources/codegen/CustomEnumMapperOnNonEnumCollectionMessage.java
index 1cdf20fc579..8f5117fb571 100644
--- a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
+++
b/modules/core/src/test/resources/codegen/CustomEnumMapperOnNonEnumCollectionMessage.java
@@ -17,15 +17,16 @@
package org.apache.ignite.internal;
+import java.util.Collection;
import org.apache.ignite.plugin.extensions.communication.Message;
-import org.apache.ignite.transactions.TransactionIsolation;
-public class CustomMapperEnumFieldsMessage implements Message {
+public class CustomEnumMapperOnNonEnumCollectionMessage implements Message {
@Order(0)
- @CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper")
- TransactionIsolation txMode;
+ @CustomMapper("org.apache.ignite.internal.CustomEnumMapper")
+ private Collection<Integer> intColField;
+ @Override
public short directType() {
return 0;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
b/modules/core/src/test/resources/codegen/CustomEnumMapperOnNonEnumMapMessage.java
similarity index 80%
copy from
modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
copy to
modules/core/src/test/resources/codegen/CustomEnumMapperOnNonEnumMapMessage.java
index 1cdf20fc579..fce8f0c34d0 100644
--- a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
+++
b/modules/core/src/test/resources/codegen/CustomEnumMapperOnNonEnumMapMessage.java
@@ -17,15 +17,16 @@
package org.apache.ignite.internal;
+import java.util.Map;
import org.apache.ignite.plugin.extensions.communication.Message;
-import org.apache.ignite.transactions.TransactionIsolation;
-public class CustomMapperEnumFieldsMessage implements Message {
+public class CustomEnumMapperOnNonEnumMapMessage implements Message {
@Order(0)
- @CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper")
- TransactionIsolation txMode;
+ @CustomMapper("org.apache.ignite.internal.CustomEnumMapper")
+ Map<String, Integer> intColField;
+ @Override
public short directType() {
return 0;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
index 1cdf20fc579..b59b931780d 100644
--- a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
+++ b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal;
+import java.util.Collection;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.apache.ignite.transactions.TransactionIsolation;
@@ -25,7 +26,11 @@ public class CustomMapperEnumFieldsMessage implements
Message {
@CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper")
TransactionIsolation txMode;
+ @Order(1)
+ @CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper")
+ Collection<Collection<TransactionIsolation>> isolations;
+
public short directType() {
return 0;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
index 8d572106c43..270f40fc71b 100644
---
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
+++
b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
@@ -19,6 +19,9 @@ package org.apache.ignite.internal;
import org.apache.ignite.internal.CustomMapperEnumFieldsMessage;
import org.apache.ignite.internal.TransactionIsolationEnumMapper;
+import
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
+import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
+import org.apache.ignite.plugin.extensions.communication.MessageEnumType;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -32,7 +35,9 @@ import org.apache.ignite.transactions.TransactionIsolation;
*/
public final class CustomMapperEnumFieldsMessageSerializer implements
MessageSerializer<CustomMapperEnumFieldsMessage> {
/** */
- private final EnumMapper<TransactionIsolation> transactionIsolationMapper
= new TransactionIsolationEnumMapper();
+ private static final EnumMapper<TransactionIsolation>
transactionIsolationMapper = new TransactionIsolationEnumMapper();
+ /** */
+ private static final MessageCollectionType isolationsCollDesc = new
MessageCollectionType(new MessageCollectionType(new
MessageEnumType<>(transactionIsolationMapper::encode,
transactionIsolationMapper::decode), false), false);
/** */
@Override public final boolean writeTo(CustomMapperEnumFieldsMessage msg,
MessageWriter writer) {
@@ -49,6 +54,12 @@ public final class CustomMapperEnumFieldsMessageSerializer
implements MessageSer
return false;
writer.incrementState();
+
+ case 1:
+ if (!writer.writeCollection(msg.isolations,
isolationsCollDesc))
+ return false;
+
+ writer.incrementState();
}
return true;
@@ -60,6 +71,14 @@ public final class CustomMapperEnumFieldsMessageSerializer
implements MessageSer
case 0:
msg.txMode =
transactionIsolationMapper.decode(reader.readByte());
+ if (!reader.isLastRead())
+ return false;
+
+ reader.incrementState();
+
+ case 1:
+ msg.isolations = reader.readCollection(isolationsCollDesc);
+
if (!reader.isLastRead())
return false;
diff --git
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
index 9af3651e327..4484d8b31ca 100644
---
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
+++
b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
@@ -17,7 +17,10 @@
package org.apache.ignite.internal;
+import java.util.Collection;
+import java.util.Map;
import org.apache.ignite.internal.processors.cache.GridCacheOperation;
+import org.apache.ignite.internal.processors.cache.verify.PartitionHashRecord;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.apache.ignite.transactions.TransactionIsolation;
@@ -28,6 +31,12 @@ public class DefaultMapperEnumFieldsMessage implements
Message {
@Order(1)
GridCacheOperation internalEnum;
+ @Order(2)
+ Map<Collection<TransactionIsolation>, String> isolationStringMap;
+
+ @Order(3)
+ Collection<PartitionHashRecord.PartitionState> partStates;
+
public short directType() {
return 0;
}
diff --git
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
index da05e0d2408..25324b44875 100644
---
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
+++
b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
@@ -19,6 +19,12 @@ package org.apache.ignite.internal;
import org.apache.ignite.internal.DefaultMapperEnumFieldsMessage;
import org.apache.ignite.internal.processors.cache.GridCacheOperation;
+import
org.apache.ignite.internal.processors.cache.verify.PartitionHashRecord.PartitionState;
+import
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
+import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
+import org.apache.ignite.plugin.extensions.communication.MessageEnumType;
+import org.apache.ignite.plugin.extensions.communication.MessageItemType;
+import org.apache.ignite.plugin.extensions.communication.MessageMapType;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -32,9 +38,15 @@ import org.apache.ignite.transactions.TransactionIsolation;
*/
public final class DefaultMapperEnumFieldsMessageSerializer implements
MessageSerializer<DefaultMapperEnumFieldsMessage> {
/** */
- private final GridCacheOperation[] gridCacheOperationVals =
GridCacheOperation.values();
+ private static final GridCacheOperation[] gridCacheOperationVals =
GridCacheOperation.values();
/** */
- private final TransactionIsolation[] transactionIsolationVals =
TransactionIsolation.values();
+ private static final PartitionState[] partitionStateVals =
PartitionState.values();
+ /** */
+ private static final TransactionIsolation[] transactionIsolationVals =
TransactionIsolation.values();
+ /** */
+ private static final MessageCollectionType partStatesCollDesc = new
MessageCollectionType(new MessageEnumType<>(DefaultEnumMapper.INSTANCE::encode,
b -> DefaultEnumMapper.INSTANCE.decode(partitionStateVals, b)), false);
+ /** */
+ private static final MessageMapType isolationStringMapCollDesc = new
MessageMapType(new MessageCollectionType(new
MessageEnumType<>(DefaultEnumMapper.INSTANCE::encode, b ->
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), false), new
MessageItemType(MessageCollectionItemType.STRING), false);
/** */
@Override public final boolean writeTo(DefaultMapperEnumFieldsMessage msg,
MessageWriter writer) {
@@ -57,6 +69,18 @@ public final class DefaultMapperEnumFieldsMessageSerializer
implements MessageSe
return false;
writer.incrementState();
+
+ case 2:
+ if (!writer.writeMap(msg.isolationStringMap,
isolationStringMapCollDesc))
+ return false;
+
+ writer.incrementState();
+
+ case 3:
+ if (!writer.writeCollection(msg.partStates,
partStatesCollDesc))
+ return false;
+
+ writer.incrementState();
}
return true;
@@ -76,6 +100,22 @@ public final class DefaultMapperEnumFieldsMessageSerializer
implements MessageSe
case 1:
msg.internalEnum =
DefaultEnumMapper.INSTANCE.decode(gridCacheOperationVals, reader.readByte());
+ if (!reader.isLastRead())
+ return false;
+
+ reader.incrementState();
+
+ case 2:
+ msg.isolationStringMap =
reader.readMap(isolationStringMapCollDesc);
+
+ if (!reader.isLastRead())
+ return false;
+
+ reader.incrementState();
+
+ case 3:
+ msg.partStates = reader.readCollection(partStatesCollDesc);
+
if (!reader.isLastRead())
return false;
@@ -89,4 +129,4 @@ public final class DefaultMapperEnumFieldsMessageSerializer
implements MessageSe
@Override public final DefaultMapperEnumFieldsMessage createMessage() {
return new DefaultMapperEnumFieldsMessage();
}
-}
\ No newline at end of file
+}
diff --git
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
b/modules/core/src/test/resources/codegen/DefaultMapperEnumMapCollectionMessage.java
similarity index 84%
copy from
modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
copy to
modules/core/src/test/resources/codegen/DefaultMapperEnumMapCollectionMessage.java
index 1cdf20fc579..9e5ebb7a03c 100644
--- a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessage.java
+++
b/modules/core/src/test/resources/codegen/DefaultMapperEnumMapCollectionMessage.java
@@ -17,15 +17,16 @@
package org.apache.ignite.internal;
+import java.util.Collection;
+import java.util.Map;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.apache.ignite.transactions.TransactionIsolation;
-public class CustomMapperEnumFieldsMessage implements Message {
+public class DefaultMapperEnumMapCollectionMessage implements Message {
@Order(0)
- @CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper")
- TransactionIsolation txMode;
+ Map<Collection<TransactionIsolation>, String> isolationStringMap;
public short directType() {
return 0;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
b/modules/core/src/test/resources/codegen/TwoDifferentEnumsInCollectionMessage.java
similarity index 84%
copy from
modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
copy to
modules/core/src/test/resources/codegen/TwoDifferentEnumsInCollectionMessage.java
index 9af3651e327..c36e8b8703b 100644
---
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessage.java
+++
b/modules/core/src/test/resources/codegen/TwoDifferentEnumsInCollectionMessage.java
@@ -17,17 +17,17 @@
package org.apache.ignite.internal;
+import java.util.Collection;
+import java.util.Map;
import org.apache.ignite.internal.processors.cache.GridCacheOperation;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.apache.ignite.transactions.TransactionIsolation;
-public class DefaultMapperEnumFieldsMessage implements Message {
+public class TwoDifferentEnumsInCollectionMessage implements Message {
@Order(0)
- TransactionIsolation publicEnum;
-
- @Order(1)
- GridCacheOperation internalEnum;
+ private Collection<Map<TransactionIsolation, GridCacheOperation>> col;
+ @Override
public short directType() {
return 0;
}
diff --git
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionItemType.java
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionItemType.java
index b98e79a46af..729c1e09df0 100644
---
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionItemType.java
+++
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionItemType.java
@@ -108,7 +108,10 @@ public enum MessageCollectionItemType {
COLLECTION,
/** Array. */
- ARRAY;
+ ARRAY,
+
+ /** Enum. */
+ ENUM;
/** Enum values. */
private static final MessageCollectionItemType[] VALS = values();
diff --git
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
new file mode 100644
index 00000000000..cdf67ea5649
--- /dev/null
+++
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
@@ -0,0 +1,59 @@
+/*
+ * 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.plugin.extensions.communication;
+
+import java.util.function.Function;
+
+/** */
+public class MessageEnumType<T extends Enum<T>> implements MessageType {
+ /** */
+ private final Function<T, Byte> encoder;
+
+ /** */
+ private final Function<Byte, T> decoder;
+
+ /**
+ * @param encoder Encoder.
+ * @param decoder Decoder.
+ */
+ public MessageEnumType(Function<T, Byte> encoder, Function<Byte, T>
decoder) {
+ this.encoder = encoder;
+ this.decoder = decoder;
+ }
+
+ /**
+ * @param val Value.
+ * @return Encoded value.
+ */
+ public byte encode(T val) {
+ return encoder.apply(val);
+ }
+
+ /**
+ * @param b Byte representation of enum value.
+ * @return Corresponding enum value.
+ */
+ public T decode(byte b) {
+ return decoder.apply(b);
+ }
+
+ /** {@inheritDoc} */
+ @Override public MessageCollectionItemType type() {
+ return MessageCollectionItemType.ENUM;
+ }
+}