Unify GeneratedType verification
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / BindingRuntimeTypesFactory.java
index 49953954cc3156bee7f22173a176640b7ffa4fef..8a7376042f3dc08a232d1cf9929e9d393fa38faf 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.mdsal.binding.generator.impl;
 import static com.google.common.base.Verify.verify;
 
 import com.google.common.base.Stopwatch;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
 import java.util.HashMap;
 import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
@@ -17,15 +19,16 @@ import org.opendaylight.mdsal.binding.generator.impl.reactor.AbstractExplicitGen
 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.InputGenerator;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.ModuleGenerator;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.OutputGenerator;
 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.JavaTypeName;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.IdentityRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.InputRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ModuleRuntimeType;
@@ -51,6 +54,8 @@ final class BindingRuntimeTypesFactory implements Mutable {
     private final Map<QName, OutputRuntimeType> rpcOutputs = new HashMap<>();
     // All RpcInputs, indexed by their RPC's QName
     private final Map<QName, InputRuntimeType> rpcInputs = new HashMap<>();
+    // All known 'choice's to their corresponding cases
+    private final SetMultimap<JavaTypeName, CaseRuntimeType> choiceToCases = HashMultimap.create();
 
     private BindingRuntimeTypesFactory() {
         // Hidden on purpose
@@ -65,7 +70,7 @@ final class BindingRuntimeTypesFactory implements Mutable {
         LOG.debug("Indexed {} generators in {}", moduleGens.size(), sw);
 
         return new DefaultBindingRuntimeTypes(context, factory.modules, factory.allTypes, factory.identities,
-            factory.rpcInputs, factory.rpcOutputs);
+            factory.rpcInputs, factory.rpcOutputs, factory.choiceToCases);
     }
 
     private void indexModules(final Map<QNameModule, ModuleGenerator> moduleGens) {
@@ -73,27 +78,23 @@ final class BindingRuntimeTypesFactory implements Mutable {
             final var modGen = entry.getValue();
 
             // index the module's runtime type
-            modGen.runtimeType().ifPresent(type -> {
-                safePut(modules, "modules", entry.getKey(), type);
-            });
+            safePut(modules, "modules", entry.getKey(), modGen.runtimeType().orElseThrow());
 
             // index module's identities and RPC input/outputs
             for (var gen : modGen) {
-                if (gen instanceof IdentityGenerator) {
-                    ((IdentityGenerator) gen).runtimeType().ifPresent(identity -> {
+                if (gen instanceof IdentityGenerator idGen) {
+                    idGen.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();
+                if (gen instanceof RpcGenerator rpcGen) {
+                    final QName rpcName = rpcGen.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));
+                        if (subgen instanceof InputGenerator inputGen) {
+                            inputGen.runtimeType().ifPresent(input -> rpcInputs.put(rpcName, input));
+                        } else if (subgen instanceof OutputGenerator outputGen) {
+                            outputGen.runtimeType().ifPresent(output -> rpcOutputs.put(rpcName, output));
                         }
                     }
                 }
@@ -105,14 +106,24 @@ final class BindingRuntimeTypesFactory implements Mutable {
 
     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();
+            if (gen instanceof AbstractExplicitGenerator<?, ?> explicitGen && gen.generatedType().isPresent()) {
+                final var type = explicitGen.runtimeType().orElseThrow();
+                if (type.javaType() instanceof GeneratedType genType) {
+                    final var name = genType.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);
+
+                    // Global indexing of cases generated for a particular choice. We look at the Generated type
+                    // and make assumptions about its shape -- which works just fine without touching the
+                    // ChoiceRuntimeType for cases.
+                    if (type instanceof CaseRuntimeType caseType) {
+                        final var ifaces = genType.getImplements();
+                        // The appropriate choice and DataObject at the very least. The choice interface is the first
+                        // one mentioned.
+                        verify(ifaces.size() >= 2, "Unexpected implemented interfaces %s", ifaces);
+                        choiceToCases.put(ifaces.get(0).getIdentifier(), caseType);
+                    }
                 }
             }
             indexRuntimeTypes(gen);