tkalkirill commented on a change in pull request #366:
URL: https://github.com/apache/ignite-3/pull/366#discussion_r738494253



##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java
##########
@@ -1244,196 +1780,959 @@ private static String capitalize(String name) {
     }
 
     /**
-     * Create bytecode blocks that invokes of {@link ConfigurationVisitor}'s 
methods for
-     * {@link InnerNode#traverseChildren(ConfigurationVisitor, boolean)}.
+     * Get interfaces for {@link InnerNode} definition for a configuration 
schema.
      *
-     * @param schemaFields Fields of the schema.
-     * @param fieldDefs Definitions for all fields in {@code schemaFields}.
-     * @param traverseChildrenMtd Method definition {@link 
InnerNode#traverseChildren(ConfigurationVisitor, boolean)}
-     *      defined in {@code *Node} class.
-     * @return Created bytecode blocks that invokes of {@link 
ConfigurationVisitor}'s methods for fields.
+     * @param schemaClass Configuration schema class.
+     * @param schemaExtensions Internal extensions of the configuration schema.
+     * @return Interfaces for {@link InnerNode} definition for a configuration 
schema.
+     */
+    private static ParameterizedType[] nodeClassInterfaces(Class<?> 
schemaClass, Set<Class<?>> schemaExtensions) {
+        Collection<ParameterizedType> res = new ArrayList<>();
+
+        for (Class<?> cls : concat(List.of(schemaClass), schemaExtensions)) {
+            res.add(typeFromJavaClassName(viewClassName(cls)));
+            res.add(typeFromJavaClassName(changeClassName(cls)));
+        }
+
+        if (isPolymorphicConfigInstance(schemaClass))
+            res.add(type(PolymorphicInstance.class));
+
+        return res.toArray(ParameterizedType[]::new);
+    }
+
+    /**
+     * Get interfaces for {@link DynamicConfiguration} definition for a 
configuration schema.
+     *
+     * @param schemaClass Configuration schema class.
+     * @param schemaExtensions Internal extensions of the configuration schema.
+     * @return Interfaces for {@link DynamicConfiguration} definition for a 
configuration schema.
+     */
+    private ParameterizedType[] configClassInterfaces(Class<?> schemaClass, 
Set<Class<?>> schemaExtensions) {
+        var result = new ArrayList<ParameterizedType>();
+
+        Stream.concat(Stream.of(schemaClass), schemaExtensions.stream())
+            .map(cls -> typeFromJavaClassName(configurationClassName(cls)))
+            .forEach(result::add);
+
+        if (schemasInfo.get(schemaClass).direct)
+            result.add(type(DirectConfigurationProperty.class));
+
+        return result.toArray(new ParameterizedType[0]);
+    }
+
+    /**
+     * Add {@link DynamicConfiguration#configType} method implementation to 
the class. It looks like the following code:
+     * <pre><code>
+     * public Class configType() {
+     *     return RootConfiguration.class;
+     * }
+     * </code></pre>
+     * @param classDef Class definition.
+     * @param clazz Definition of the configuration interface, for example 
{@code RootConfiguration}.
+     */
+    private static void addCfgImplConfigTypeMethod(ClassDefinition classDef, 
ParameterizedType clazz) {
+        classDef.declareMethod(of(PUBLIC), "configType", type(Class.class))
+            .getBody()
+            .append(constantClass(clazz))
+            .retObject();
+    }
+
+    /**
+     * Create a {@code *Node} for the polymorphic configuration instance 
schema.
+     *
+     * @param schemaClass Polymorphic configuration schema (parent).
+     * @param polymorphicExtension Polymorphic configuration instance schema 
(child).
+     * @param schemaInnerNodeClassDef {@link InnerNode} definition for the 
polymorphic configuration schema {@code schemaClass}.
+     * @param schemaFields Schema fields of polymorphic configuration {@code 
schemaClass}.
+     * @param polymorphicFields Schema fields of a polymorphic configuration 
instance {@code polymorphicExtension}.
+     */
+    private ClassDefinition createPolymorphicExtensionNodeClass(
+        Class<?> schemaClass,
+        Class<?> polymorphicExtension,
+        ClassDefinition schemaInnerNodeClassDef,
+        Collection<Field> schemaFields,
+        Collection<Field> polymorphicFields
+    ) {
+        SchemaClassesInfo schemaClassInfo = schemasInfo.get(schemaClass);
+        SchemaClassesInfo polymorphicExtensionClassInfo = 
schemasInfo.get(polymorphicExtension);
+
+        // Node class definition.
+        ClassDefinition classDef = new ClassDefinition(
+            of(PUBLIC, FINAL),
+            internalName(polymorphicExtensionClassInfo.nodeClassName),
+            type(Object.class),
+            nodeClassInterfaces(polymorphicExtension, Set.of())
+        );
+
+        // private final ParentNode parent#innerNode;
+        FieldDefinition parentInnerNodeFieldDef = classDef.declareField(
+            of(PRIVATE, FINAL),
+            "parent#innerNode",
+            typeFromJavaClassName(schemaClassInfo.nodeClassName)
+        );
+
+        // Constructor.
+        MethodDefinition constructorMtd = classDef.declareConstructor(
+            of(PUBLIC),
+            arg("parent", typeFromJavaClassName(schemaClassInfo.nodeClassName))
+        );
+
+        Variable parentVar = constructorMtd.getScope().getVariable("parent");
+
+        // Constructor body.
+        constructorMtd.getBody()
+            .append(constructorMtd.getThis())
+            .append(constructorMtd.getThis().setField(
+                parentInnerNodeFieldDef,
+                parentVar
+            ))
+            .invokeConstructor(Object.class)
+            .ret();
+
+        Map<String, FieldDefinition> fieldDefs = 
schemaInnerNodeClassDef.getFields().stream()
+            .collect(toMap(FieldDefinition::getName, identity()));
+
+        // Creates view and change methods for parent schema.
+        for (Field schemaField : schemaFields) {
+            // Must be skipped, this is an internal special field.
+            if (isPolymorphicId(schemaField))
+                continue;
+
+            FieldDefinition schemaFieldDef = 
fieldDefs.get(fieldName(schemaField));
+
+            addNodeViewMethod(classDef, schemaField, parentInnerNodeFieldDef, 
schemaFieldDef);
+
+            MethodDefinition changeMtd = addNodeChangeMethod(
+                classDef,
+                schemaField,
+                polymorphicExtensionClassInfo.nodeClassName,
+                parentInnerNodeFieldDef,
+                schemaFieldDef
+            );
+
+            addNodeChangeBridgeMethod(classDef, 
schemaClassInfo.changeClassName, changeMtd);
+        }
+
+        // Creates view and change methods for specific polymorphic instance 
schema.
+        for (Field polymorphicField : polymorphicFields) {
+            FieldDefinition polymorphicFieldDef = 
fieldDefs.get(fieldName(polymorphicField));
+
+            addNodeViewMethod(classDef, polymorphicField, 
parentInnerNodeFieldDef, polymorphicFieldDef);
+
+            MethodDefinition changeMtd = addNodeChangeMethod(
+                classDef,
+                polymorphicField,
+                polymorphicExtensionClassInfo.nodeClassName,
+                parentInnerNodeFieldDef,
+                polymorphicFieldDef
+            );
+
+            addNodeChangeBridgeMethod(classDef, 
polymorphicExtensionClassInfo.changeClassName, changeMtd);
+        }
+
+        ParameterizedType returnType = 
typeFromJavaClassName(schemaClassInfo.changeClassName);
+
+        // Creates {@code Node#convert}.
+        MethodDefinition convertMtd = classDef.declareMethod(
+            of(PUBLIC),
+            CONVERT_MTD_NAME,
+            returnType,
+            arg("changeClass", Class.class)
+        );
+
+        // Find parent {@code Node#convert}.
+        MethodDefinition parentConvertMtd = 
schemaInnerNodeClassDef.getMethods().stream()
+            .filter(mtd -> CONVERT_MTD_NAME.equals(mtd.getName()))
+            .findAny()
+            .orElse(null);
+
+        assert parentConvertMtd != null : schemaInnerNodeClassDef.getName();
+
+        // return this.parent#innerNode.convert(changeClass);
+        convertMtd.getBody()
+            .append(getThisFieldCode(convertMtd, parentInnerNodeFieldDef))
+            .append(convertMtd.getScope().getVariable("changeClass"))
+            .invokeVirtual(parentConvertMtd)
+            .retObject();
+
+        return classDef;
+    }
+
+    /**
+     * Create a {@code *CfgImpl} for the polymorphic configuration instance 
schema.
+     *
+     * @param schemaClass Polymorphic configuration schema (parent).
+     * @param polymorphicExtension Polymorphic configuration instance schema 
(child).
+     * @param schemaCfgImplClassDef {@link DynamicConfiguration} definition 
for the polymorphic configuration schema {@code schemaClass}.
+     * @param schemaFields Schema fields of polymorphic configuration {@code 
schemaClass}.
+     * @param polymorphicFields Schema fields of a polymorphic configuration 
instance {@code polymorphicExtension}.
      */
-    private static Collection<BytecodeNode> invokeVisitForTraverseChildren(
+    private ClassDefinition createPolymorphicExtensionCfgImplClass(
+        Class<?> schemaClass,
+        Class<?> polymorphicExtension,
+        ClassDefinition schemaCfgImplClassDef,
         Collection<Field> schemaFields,
+        Collection<Field> polymorphicFields
+    ) {
+        SchemaClassesInfo schemaClassInfo = schemasInfo.get(schemaClass);
+        SchemaClassesInfo polymorphicExtensionClassInfo = 
schemasInfo.get(polymorphicExtension);
+
+        Class<?> superClass = schemaClassInfo.direct || 
polymorphicExtensionClassInfo.direct
+            ? DirectConfigurationTreeWrapper.class : 
ConfigurationTreeWrapper.class;
+
+        // Configuration impl class definition.
+        ClassDefinition classDef = new ClassDefinition(
+            of(PUBLIC, FINAL),
+            internalName(polymorphicExtensionClassInfo.cfgImplClassName),
+            type(superClass),
+            configClassInterfaces(polymorphicExtension, Set.of())
+        );
+
+        // private final ParentCfgImpl parent#cfgImpl;
+        FieldDefinition parentCfgImplFieldDef = classDef.declareField(
+            of(PRIVATE, FINAL),
+            "parent#cfgImpl",
+            typeFromJavaClassName(schemaClassInfo.cfgImplClassName)
+        );
+
+        // Constructor.
+        MethodDefinition constructorMtd = classDef.declareConstructor(
+            of(PUBLIC),
+            arg("parent", 
typeFromJavaClassName(schemaClassInfo.cfgImplClassName))
+        );
+
+        Variable parentVar = constructorMtd.getScope().getVariable("parent");
+
+        // Constructor body.
+        // super(parent);
+        // this.parent#cfgImpl = parent;
+        constructorMtd.getBody()
+            .append(constructorMtd.getThis())
+            .append(parentVar)
+            .invokeConstructor(superClass, ConfigurationTree.class)
+            .append(constructorMtd.getThis().setField(
+                parentCfgImplFieldDef,
+                parentVar
+            ))
+            .ret();
+
+        Map<String, FieldDefinition> fieldDefs = 
schemaCfgImplClassDef.getFields().stream()
+            .collect(toMap(FieldDefinition::getName, identity()));
+
+        for (Field schemaField : concat(schemaFields, polymorphicFields)) {
+            // Must be skipped, this is an internal special field.
+            if (isPolymorphicId(schemaField))
+                continue;
+
+            addConfigurationImplGetMethod(
+                classDef,
+                schemaField,
+                parentCfgImplFieldDef,
+                fieldDefs.get(fieldName(schemaField))
+            );
+        }
+
+        return classDef;
+    }
+
+    /**
+     * Adds a {@link InnerNode#specificNode} override for the polymorphic 
configuration case.
+     *
+     * @param classDef                  Definition of a polymorphic 
configuration class (parent).
+     * @param polymorphicExtensions     Polymorphic configuration instance 
schemas (children).
+     * @param polymorphicTypeIdFieldDef Identification field for the 
polymorphic configuration instance.
+     */
+    private void addNodeSpecificNodeMethod(
+        ClassDefinition classDef,
+        Set<Class<?>> polymorphicExtensions,
+        FieldDefinition polymorphicTypeIdFieldDef
+    ) {
+        MethodDefinition specificNodeMtd = classDef.declareMethod(
+            of(PUBLIC),
+            SPECIFIC_NODE_MTD.getName(),
+            type(Object.class)
+        );
+
+        StringSwitchBuilder switchBuilder = 
typeIdSwitchBuilder(specificNodeMtd, polymorphicTypeIdFieldDef);
+
+        for (Class<?> polymorphicExtension : polymorphicExtensions) {
+            SchemaClassesInfo polymorphicExtensionClassInfo = 
schemasInfo.get(polymorphicExtension);
+
+            switchBuilder.addCase(
+                polymorphicInstanceId(polymorphicExtension),
+                newInstance(
+                    
typeFromJavaClassName(polymorphicExtensionClassInfo.nodeClassName),
+                    specificNodeMtd.getThis()
+                ).ret()
+            );
+        }
+
+        specificNodeMtd.getBody()
+            .append(switchBuilder.build())

Review comment:
       Here i use a **ConfigurationAsmGenerator#typeIdSwitchBuilder** in which 
there is a default statement




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to