Rework BindingRuntimeTypes
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / BindingRuntimeTypesFactory.java
index 8c5a49450416f788b0ba575d17911ea1b09bde7a..49953954cc3156bee7f22173a176640b7ffa4fef 100644 (file)
@@ -10,92 +10,117 @@ package org.opendaylight.mdsal.binding.generator.impl;
 import static com.google.common.base.Verify.verify;
 
 import com.google.common.base.Stopwatch;
-import java.util.Collection;
 import java.util.HashMap;
-import java.util.IdentityHashMap;
 import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.AbstractExplicitGenerator;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.Generator;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.GeneratorReactor;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.IdentityGenerator;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.ModuleGenerator;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.RpcGenerator;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.RpcInputGenerator;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.RpcOutputGenerator;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.TypeBuilderFactory;
+import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultBindingRuntimeTypes;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes;
+import org.opendaylight.mdsal.binding.runtime.api.IdentityRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.InputRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ModuleRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.OutputRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.concepts.Mutable;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.IdentityEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 final class BindingRuntimeTypesFactory implements Mutable {
     private static final Logger LOG = LoggerFactory.getLogger(BindingRuntimeTypesFactory.class);
 
-    private final Map<Type, AugmentationSchemaNode> augmentationToSchema = new HashMap<>();
-    private final Map<Type, WithStatus> typeToSchema = new HashMap<>();
-    private final Map<QName, Type> identities = new HashMap<>();
-
-    // Note: we are keying through WithStatus, but these nodes compare on semantics, so equivalent schema nodes
-    //       can result in two distinct types. We certainly need to keep them separate.
-    private final Map<WithStatus, Type> schemaToType = new IdentityHashMap<>();
+    // Modules, indexed by their QNameModule
+    private final Map<QNameModule, ModuleRuntimeType> modules = new HashMap<>();
+    // Identities, indexed by their QName
+    private final Map<QName, IdentityRuntimeType> identities = new HashMap<>();
+    // All known types, indexed by their JavaTypeName
+    private final Map<JavaTypeName, RuntimeType> allTypes = new HashMap<>();
+    // All RpcOutputs, indexed by their RPC's QName
+    private final Map<QName, OutputRuntimeType> rpcOutputs = new HashMap<>();
+    // All RpcInputs, indexed by their RPC's QName
+    private final Map<QName, InputRuntimeType> rpcInputs = new HashMap<>();
 
     private BindingRuntimeTypesFactory() {
         // Hidden on purpose
     }
 
     static @NonNull BindingRuntimeTypes createTypes(final @NonNull EffectiveModelContext context) {
-        final Collection<ModuleGenerator> moduleGens = new GeneratorReactor(context)
-            .execute(TypeBuilderFactory.runtime())
-            .values();
+        final var moduleGens = new GeneratorReactor(context).execute(TypeBuilderFactory.runtime());
 
         final Stopwatch sw = Stopwatch.createStarted();
         final BindingRuntimeTypesFactory factory = new BindingRuntimeTypesFactory();
-        factory.indexTypes(moduleGens);
+        factory.indexModules(moduleGens);
         LOG.debug("Indexed {} generators in {}", moduleGens.size(), sw);
 
-        return new DefaultBindingRuntimeTypes(context, factory.augmentationToSchema, factory.typeToSchema,
-            factory.schemaToType, factory.identities);
+        return new DefaultBindingRuntimeTypes(context, factory.modules, factory.allTypes, factory.identities,
+            factory.rpcInputs, factory.rpcOutputs);
     }
 
-    private void indexTypes(final Iterable<? extends Generator> generators) {
-        for (Generator gen : generators) {
-            gen.generatedType().ifPresent(type -> indexType(gen, type));
-            indexTypes(gen);
-        }
-    }
+    private void indexModules(final Map<QNameModule, ModuleGenerator> moduleGens) {
+        for (var entry : moduleGens.entrySet()) {
+            final var modGen = entry.getValue();
 
-    private void indexType(final @NonNull Generator generator, final @NonNull GeneratedType type) {
-        if (generator instanceof AbstractExplicitGenerator) {
-            final EffectiveStatement<?, ?> stmt = ((AbstractExplicitGenerator<?>) generator).statement();
-            if (stmt instanceof IdentityEffectiveStatement) {
-                identities.put(((IdentityEffectiveStatement) stmt).argument(), type);
-            } else if (stmt instanceof AugmentEffectiveStatement) {
-                verify(stmt instanceof AugmentationSchemaNode, "Unexpected statement %s", stmt);
-                augmentationToSchema.put(type, (AugmentationSchemaNode) stmt);
-            }
+            // index the module's runtime type
+            modGen.runtimeType().ifPresent(type -> {
+                safePut(modules, "modules", entry.getKey(), type);
+            });
 
-            final WithStatus schema;
-            if (stmt instanceof TypedDataSchemaNode) {
-                schema = ((TypedDataSchemaNode) stmt).getType();
-            } else if (stmt instanceof TypedefEffectiveStatement) {
-                schema = ((TypedefEffectiveStatement) stmt).getTypeDefinition();
-            } else if (stmt instanceof WithStatus) {
-                schema = (WithStatus) stmt;
-            } else {
-                return;
+            // index module's identities and RPC input/outputs
+            for (var gen : modGen) {
+                if (gen instanceof IdentityGenerator) {
+                    ((IdentityGenerator) gen).runtimeType().ifPresent(identity -> {
+                        safePut(identities, "identities", identity.statement().argument(), identity);
+                    });
+                }
+                // FIXME: do not collect these once we they generate a proper RuntimeType
+                if (gen instanceof RpcGenerator) {
+                    final QName rpcName = ((RpcGenerator) gen).statement().argument();
+                    for (var subgen : gen) {
+                        if (subgen instanceof RpcInputGenerator) {
+                            ((RpcInputGenerator) subgen).runtimeType()
+                                .ifPresent(input -> rpcInputs.put(rpcName, input));
+                        } else if (subgen instanceof RpcOutputGenerator) {
+                            ((RpcOutputGenerator) subgen).runtimeType()
+                                .ifPresent(output -> rpcOutputs.put(rpcName, output));
+                        }
+                    }
+                }
             }
+        }
 
-            typeToSchema.put(type, schema);
-            final var prevType = schemaToType.put(schema, type);
-            verify(prevType == null, "Conflicting types %s and %s on %s", type, prevType, schema);
+        indexRuntimeTypes(moduleGens.values());
+    }
+
+    private void indexRuntimeTypes(final Iterable<? extends Generator> generators) {
+        for (Generator gen : generators) {
+            if (gen instanceof AbstractExplicitGenerator && gen.generatedType().isPresent()) {
+                final var type = ((AbstractExplicitGenerator<?, ?>) gen).runtimeType().orElseThrow();
+                final var javaType = type.javaType();
+                if (javaType instanceof GeneratedType) {
+                    final var name = javaType.getIdentifier();
+                    final var prev = allTypes.put(name, type);
+                    verify(prev == null || prev == type, "Conflict on runtime type mapping of %s between %s and %s",
+                        name, prev, type);
+                }
+            }
+            indexRuntimeTypes(gen);
         }
     }
+
+    private static <K, V> void safePut(final Map<K, V> map, final String name, final K key, final V value) {
+        final var prev = map.put(key, value);
+        verify(prev == null, "Conflict in %s, key %s conflicts on %s versus %s", name, key, prev, value);
+    }
 }