ibessonov commented on a change in pull request #122:
URL: https://github.com/apache/ignite-3/pull/122#discussion_r639470052



##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/asm/ConfigurationAsmGenerator.java
##########
@@ -0,0 +1,1117 @@
+/*
+ * 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.configuration.internal.asm;
+
+import com.facebook.presto.bytecode.BytecodeBlock;
+import com.facebook.presto.bytecode.ClassDefinition;
+import com.facebook.presto.bytecode.ClassGenerator;
+import com.facebook.presto.bytecode.FieldDefinition;
+import com.facebook.presto.bytecode.MethodDefinition;
+import com.facebook.presto.bytecode.ParameterizedType;
+import com.facebook.presto.bytecode.Variable;
+import com.facebook.presto.bytecode.control.IfStatement;
+import com.facebook.presto.bytecode.expression.BytecodeExpression;
+import java.io.Serializable;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.ConfigurationValue;
+import org.apache.ignite.configuration.NamedConfigurationTree;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.ConfigurationRoot;
+import org.apache.ignite.configuration.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.DynamicProperty;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+import org.apache.ignite.configuration.tree.ConfigurationSource;
+import org.apache.ignite.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.configuration.tree.ConstructableTreeNode;
+import org.apache.ignite.configuration.tree.InnerNode;
+import org.apache.ignite.configuration.tree.NamedListNode;
+import org.apache.ignite.configuration.tree.NamedListView;
+import org.jetbrains.annotations.NotNull;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import static com.facebook.presto.bytecode.Access.FINAL;
+import static com.facebook.presto.bytecode.Access.PRIVATE;
+import static com.facebook.presto.bytecode.Access.PUBLIC;
+import static com.facebook.presto.bytecode.Access.STATIC;
+import static com.facebook.presto.bytecode.Access.SYNTHETIC;
+import static com.facebook.presto.bytecode.Parameter.arg;
+import static com.facebook.presto.bytecode.ParameterizedType.type;
+import static 
com.facebook.presto.bytecode.ParameterizedType.typeFromJavaClassName;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.constantClass;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.constantNull;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.inlineIf;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeDynamic;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeStatic;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.isNull;
+import static 
com.facebook.presto.bytecode.expression.BytecodeExpressions.newInstance;
+import static java.lang.invoke.MethodType.methodType;
+import static java.util.Collections.singleton;
+import static java.util.EnumSet.of;
+import static org.objectweb.asm.Opcodes.H_NEWINVOKESPECIAL;
+import static org.objectweb.asm.Type.getMethodDescriptor;
+import static org.objectweb.asm.Type.getMethodType;
+import static org.objectweb.asm.Type.getType;
+
+/**
+ * This class is responsible for generating internal implementation classes 
for configuration schemas. It uses classes
+ * from {@code bytecode} module to achieve this goal, like {@link 
ClassGenerator}, for examples.
+ */
+public class ConfigurationAsmGenerator {
+    /** {@link LambdaMetafactory#metafactory(Lookup, String, MethodType, 
MethodType, MethodHandle, MethodType)} */
+    private static final Method LAMBDA_METAFACTORY;
+
+    /** {@link Consumer#accept(Object)}*/
+    private static final Method ACCEPT;
+
+    /** {@link ConfigurationVisitor#visitLeafNode(String, Serializable)} */
+    private static final Method VISIT_LEAF;
+
+    /** {@link ConfigurationVisitor#visitInnerNode(String, InnerNode)} */
+    private static final Method VISIT_INNER;
+
+    /** {@link ConfigurationVisitor#visitNamedListNode(String, NamedListNode)} 
*/
+    private static final Method VISIT_NAMED;
+
+    /** {@link ConfigurationSource#unwrap(Class)} */
+    private static final Method UNWRAP;
+
+    /** {@link ConfigurationSource#descend(ConstructableTreeNode)} */
+    private static final Method DESCEND;
+
+    /** {@link ConstructableTreeNode#copy()} */
+    private static final Method COPY;
+
+    /** {@link DynamicConfiguration#DynamicConfiguration(List, String, 
RootKey, ConfigurationChanger)} */
+    private static final Constructor DYNAMIC_CONFIGURATION_CTOR;
+
+    /** {@link DynamicConfiguration#add(ConfigurationProperty)} */
+    private static final Method DYNAMIC_CONFIGURATION_ADD;
+
+    static {
+        try {
+            LAMBDA_METAFACTORY = LambdaMetafactory.class.getDeclaredMethod(
+                "metafactory",
+                Lookup.class,
+                String.class,
+                MethodType.class,
+                MethodType.class,
+                MethodHandle.class,
+                MethodType.class
+            );
+
+            ACCEPT = Consumer.class.getDeclaredMethod("accept", Object.class);
+
+            VISIT_LEAF = 
ConfigurationVisitor.class.getDeclaredMethod("visitLeafNode", String.class, 
Serializable.class);
+
+            VISIT_INNER = 
ConfigurationVisitor.class.getDeclaredMethod("visitInnerNode", String.class, 
InnerNode.class);
+
+            VISIT_NAMED = 
ConfigurationVisitor.class.getDeclaredMethod("visitNamedListNode", 
String.class, NamedListNode.class);
+
+            UNWRAP = ConfigurationSource.class.getDeclaredMethod("unwrap", 
Class.class);
+
+            DESCEND = ConfigurationSource.class.getDeclaredMethod("descend", 
ConstructableTreeNode.class);
+
+            COPY = ConstructableTreeNode.class.getDeclaredMethod("copy");
+
+            DYNAMIC_CONFIGURATION_CTOR = 
DynamicConfiguration.class.getDeclaredConstructor(
+                List.class,
+                String.class,
+                RootKey.class,
+                ConfigurationChanger.class
+            );
+
+            DYNAMIC_CONFIGURATION_ADD = 
DynamicConfiguration.class.getDeclaredMethod(
+                "add",
+                ConfigurationProperty.class
+            );
+        }
+        catch (NoSuchMethodException nsme) {
+            throw new ExceptionInInitializerError(nsme);
+        }
+    }
+
+    /** Information about schema classes - bunch of names and dynamically 
compiled internal classes. */
+    private final Map<Class<?>, SchemaClassesInfo> schemasInfo = new 
HashMap<>();
+
+    /** Class generator instance. */
+    private final ClassGenerator generator = 
ClassGenerator.classGenerator(this.getClass().getClassLoader());
+
+    /**
+     * Creates new instance of {@code *Node} class corresponding to the given 
Configuration Schema.
+     * @param schemaClass Configuration Schema class.
+     * @return Node instance.
+     */
+    public synchronized InnerNode instantiateNode(Class<?> schemaClass) {
+        SchemaClassesInfo info = schemasInfo.get(schemaClass);
+
+        assert info != null && info.nodeClass != null : schemaClass;
+
+        try {
+            Constructor<? extends InnerNode> constructor = 
info.nodeClass.getConstructor();
+
+            assert constructor.canAccess(null);
+
+            return constructor.newInstance();
+        }
+        catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Creates new instance of {@code *Configuration} class corresponding to 
the given Configuration Schema.
+     * @param rootKey Root key of the configuration root.
+     * @param changer Configuration changer instance to pass into constructor.
+     * @return Configuration instance.
+     */
+    public synchronized DynamicConfiguration<?, ?> instantiateCfg(
+        RootKey<?, ?> rootKey,
+        ConfigurationChanger changer
+    ) {
+        SchemaClassesInfo info = schemasInfo.get(rootKey.schemaClass());
+
+        assert info != null && info.cfgImplClass != null;
+
+        try {
+            Constructor<? extends DynamicConfiguration<?, ?>> constructor = 
info.cfgImplClass.getConstructor(
+                List.class,
+                String.class,
+                RootKey.class,
+                ConfigurationChanger.class
+            );
+
+            assert constructor.canAccess(null);
+
+            return constructor.newInstance(Collections.emptyList(), 
rootKey.key(), rootKey, changer);
+        }
+        catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Generates, defines, loads and initializes all dynamic classes required 
for the given Configuration Schema.
+     * @param rootSchemaClass Class of the root Configuration Schema.
+     */
+    public synchronized void compileRootSchema(Class<?> rootSchemaClass) {
+        if (schemasInfo.containsKey(rootSchemaClass))
+            return; // Already compiled.
+
+        Queue<Class<?>> compileQueue = new LinkedList<>();
+        compileQueue.add(rootSchemaClass);
+
+        schemasInfo.put(rootSchemaClass, new 
SchemaClassesInfo(rootSchemaClass));
+
+        Set<Class<?>> schemas = new HashSet<>();
+        List<ClassDefinition> definitions = new ArrayList<>();
+
+        while (!compileQueue.isEmpty()) {
+            Class<?> schemaClass = compileQueue.poll();
+
+            assert schemaClass.isAnnotationPresent(ConfigurationRoot.class)
+                || schemaClass.isAnnotationPresent(Config.class)
+                : schemaClass + " is not properly annotated";
+
+            assert schemasInfo.containsKey(schemaClass);
+
+            for (Field field : schemaClass.getDeclaredFields()) {
+                if (isConfigValue(field) || isNamedConfigValue(field)) {
+                    Class<?> subSchemaClass = field.getType();
+
+                    if (!schemasInfo.containsKey(subSchemaClass)) {
+                        compileQueue.offer(subSchemaClass);
+                        schemasInfo.put(subSchemaClass, new 
SchemaClassesInfo(subSchemaClass));
+                    }
+                }
+            }
+
+            schemas.add(schemaClass);

Review comment:
       Please refer to line 265, there I check that schema is not yet compiled.




-- 
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.

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


Reply via email to