Update ChoiceSchemaNode design
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / effective / ChoiceEffectiveStatementImpl.java
index a9360a61340009aeebbf838191f6913e014b6448..f76df175a8753cdd8c463783e02fd55dc8754e31 100644 (file)
@@ -7,14 +7,14 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedMap;
 import java.util.LinkedHashSet;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -23,28 +23,27 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangValidationBundles;
 
 public final class ChoiceEffectiveStatementImpl extends AbstractEffectiveDataSchemaNode<ChoiceStatement> implements
         ChoiceSchemaNode, DerivableSchemaNode {
-    private final ChoiceSchemaNode original;
-    private final String defaultCase;
 
-    private final Set<ChoiceCaseNode> cases;
     private final Set<AugmentationSchemaNode> augmentations;
+    private final SortedMap<QName, ChoiceCaseNode> cases;
+    private final ChoiceCaseNode defaultCase;
+    private final ChoiceSchemaNode original;
 
     public ChoiceEffectiveStatementImpl(
             final StmtContext<QName, ChoiceStatement, EffectiveStatement<QName, ChoiceStatement>> ctx) {
         super(ctx);
         this.original = (ChoiceSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
 
-        final DefaultEffectiveStatementImpl defaultStmt = firstEffective(DefaultEffectiveStatementImpl.class);
-        this.defaultCase = defaultStmt == null ? null : defaultStmt.argument();
-
         // initSubstatementCollectionsAndFields
         final Set<AugmentationSchemaNode> augmentationsInit = new LinkedHashSet<>();
-        final SortedSet<ChoiceCaseNode> casesInit = new TreeSet<>((o1, o2) -> o1.getQName().compareTo(o2.getQName()));
+        final SortedMap<QName, ChoiceCaseNode> casesInit = new TreeMap<>();
 
         for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
             if (effectiveStatement instanceof AugmentationSchemaNode) {
@@ -53,12 +52,14 @@ public final class ChoiceEffectiveStatementImpl extends AbstractEffectiveDataSch
             }
             if (effectiveStatement instanceof ChoiceCaseNode) {
                 final ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) effectiveStatement;
-                casesInit.add(choiceCaseNode);
+                // FIXME: we may be overwriting a previous entry, is that really okay?
+                casesInit.put(choiceCaseNode.getQName(), choiceCaseNode);
             }
             if (YangValidationBundles.SUPPORTED_CASE_SHORTHANDS.contains(effectiveStatement.statementDefinition())) {
                 final DataSchemaNode dataSchemaNode = (DataSchemaNode) effectiveStatement;
                 final ChoiceCaseNode shorthandCase = new CaseShorthandImpl(dataSchemaNode);
-                casesInit.add(shorthandCase);
+                // FIXME: we may be overwriting a previous entry, is that really okay?
+                casesInit.put(shorthandCase.getQName(), shorthandCase);
                 if (dataSchemaNode.isAugmenting() && !this.augmenting) {
                     resetAugmenting(dataSchemaNode);
                 }
@@ -66,7 +67,24 @@ public final class ChoiceEffectiveStatementImpl extends AbstractEffectiveDataSch
         }
 
         this.augmentations = ImmutableSet.copyOf(augmentationsInit);
-        this.cases = ImmutableSet.copyOf(casesInit);
+        this.cases = ImmutableSortedMap.copyOfSorted(casesInit);
+
+        final DefaultEffectiveStatementImpl defaultStmt = firstEffective(DefaultEffectiveStatementImpl.class);
+        if (defaultStmt != null) {
+            final QName qname;
+            try {
+                qname = QName.create(getQName(), defaultStmt.argument());
+            } catch (IllegalArgumentException e) {
+                throw new SourceException(ctx.getStatementSourceReference(), "Default statement has invalid name '%s'",
+                    defaultStmt.argument(), e);
+            }
+
+            // FIXME: this does not work with submodules, as they are
+            defaultCase = InferenceException.throwIfNull(cases.get(qname), ctx.getStatementSourceReference(),
+                "Default statement refers to missing case %s", qname);
+        } else {
+            defaultCase = null;
+        }
     }
 
     private static void resetAugmenting(final DataSchemaNode dataSchemaNode) {
@@ -99,37 +117,13 @@ public final class ChoiceEffectiveStatementImpl extends AbstractEffectiveDataSch
     }
 
     @Override
-    public Set<ChoiceCaseNode> getCases() {
+    public SortedMap<QName, ChoiceCaseNode> getCases() {
         return cases;
     }
 
     @Override
-    public ChoiceCaseNode getCaseNodeByName(final QName name) {
-        Preconditions.checkArgument(name != null, "Choice Case QName cannot be NULL!");
-
-        for (final ChoiceCaseNode caseNode : cases) {
-            if (caseNode != null && name.equals(caseNode.getQName())) {
-                return caseNode;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public ChoiceCaseNode getCaseNodeByName(final String name) {
-        Preconditions.checkArgument(name != null, "Choice Case string Name cannot be NULL!");
-
-        for (final ChoiceCaseNode caseNode : cases) {
-            if (caseNode != null && caseNode.getQName() != null && name.equals(caseNode.getQName().getLocalName())) {
-                return caseNode;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public String getDefaultCase() {
-        return defaultCase;
+    public Optional<ChoiceCaseNode> getDefaultCase() {
+        return Optional.ofNullable(defaultCase);
     }
 
     @Override