Bug 2366 - Effective statement implementation
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / AugmentUtils.java
index d4d59d630deea46085e2783e945f73dc3a2b26ee..9d99af203aa5c8077996b7e58e1bddac95bebff6 100644 (file)
@@ -7,13 +7,16 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import java.util.Iterator;
+import javax.annotation.Nullable;
+
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.TypeOfCopy;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
@@ -32,13 +35,14 @@ import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
 
 public final class AugmentUtils {
 
-    private AugmentUtils() {
-    }
-
     private static final String REGEX_PATH_REL1 = "\\.\\.?\\s*/(.+)";
     private static final String REGEX_PATH_REL2 = "//.*";
 
-    public static Iterable<QName> parseAugmentPath(StmtContext<?, ?, ?> ctx, String path) {
+    private AugmentUtils() {
+    }
+
+    public static Iterable<QName> parseAugmentPath(StmtContext<?, ?, ?> ctx,
+            String path) {
 
         if (path.matches(REGEX_PATH_REL1) || path.matches(REGEX_PATH_REL2)) {
             throw new IllegalArgumentException(
@@ -48,8 +52,9 @@ public final class AugmentUtils {
         return Utils.parseXPath(ctx, path);
     }
 
-    public static void copyFromSourceToTarget(StatementContextBase<?, ?, ?> sourceCtx,
-                                              StatementContextBase<?, ?, ?> targetCtx) throws SourceException {
+    public static void copyFromSourceToTarget(
+            StatementContextBase<?, ?, ?> sourceCtx,
+            StatementContextBase<?, ?, ?> targetCtx) throws SourceException {
 
         QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceCtx);
         copyDeclaredStmts(sourceCtx, targetCtx, newQNameModule);
@@ -57,12 +62,17 @@ public final class AugmentUtils {
 
     }
 
-    public static void copyDeclaredStmts(StatementContextBase<?, ?, ?> sourceCtx,
-                                         StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule) throws SourceException {
-        Collection<? extends StatementContextBase<?, ?, ?>> declaredSubstatements = sourceCtx.declaredSubstatements();
+    public static void copyDeclaredStmts(
+            StatementContextBase<?, ?, ?> sourceCtx,
+            StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule)
+            throws SourceException {
+        Collection<? extends StatementContextBase<?, ?, ?>> declaredSubstatements = sourceCtx
+                .declaredSubstatements();
         for (StatementContextBase<?, ?, ?> originalStmtCtx : declaredSubstatements) {
             if (needToCopyByAugment(originalStmtCtx)) {
-                StatementContextBase<?, ?, ?> copy = originalStmtCtx.createCopy(newQNameModule, targetCtx);
+                StatementContextBase<?, ?, ?> copy = originalStmtCtx
+                        .createCopy(newQNameModule, targetCtx,
+                                TypeOfCopy.ADDED_BY_AUGMENTATION);
                 targetCtx.addEffectiveSubstatement(copy);
             } else if (isReusedByAugment(originalStmtCtx)) {
                 targetCtx.addEffectiveSubstatement(originalStmtCtx);
@@ -70,12 +80,17 @@ public final class AugmentUtils {
         }
     }
 
-    public static void copyEffectiveStmts(StatementContextBase<?, ?, ?> sourceCtx,
-                                          StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule) throws SourceException {
-        Collection<? extends StatementContextBase<?, ?, ?>> effectiveSubstatements = sourceCtx.effectiveSubstatements();
+    public static void copyEffectiveStmts(
+            StatementContextBase<?, ?, ?> sourceCtx,
+            StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule)
+            throws SourceException {
+        Collection<? extends StatementContextBase<?, ?, ?>> effectiveSubstatements = sourceCtx
+                .effectiveSubstatements();
         for (StatementContextBase<?, ?, ?> originalStmtCtx : effectiveSubstatements) {
             if (needToCopyByAugment(originalStmtCtx)) {
-                StatementContextBase<?, ?, ?> copy = originalStmtCtx.createCopy(newQNameModule, targetCtx);
+                StatementContextBase<?, ?, ?> copy = originalStmtCtx
+                        .createCopy(newQNameModule, targetCtx,
+                                TypeOfCopy.ADDED_BY_AUGMENTATION);
                 targetCtx.addEffectiveSubstatement(copy);
             } else if (isReusedByAugment(originalStmtCtx)) {
                 targetCtx.addEffectiveSubstatement(originalStmtCtx);
@@ -83,13 +98,15 @@ public final class AugmentUtils {
         }
     }
 
-    public static QNameModule getNewQNameModule(StatementContextBase<?, ?, ?> targetCtx,
-                                                StatementContextBase<?, ?, ?> sourceCtx) {
+    public static QNameModule getNewQNameModule(
+            StatementContextBase<?, ?, ?> targetCtx,
+            StatementContextBase<?, ?, ?> sourceCtx) {
         Object targetStmtArgument = targetCtx.getStatementArgument();
 
         final StatementContextBase<?, ?, ?> root = sourceCtx.getRoot();
         final String moduleName = (String) root.getStatementArgument();
-        final QNameModule sourceQNameModule = root.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
+        final QNameModule sourceQNameModule = root.getFromNamespace(
+                ModuleNameToModuleQName.class, moduleName);
 
         if (targetStmtArgument instanceof QName) {
             QName targetQName = (QName) targetStmtArgument;
@@ -111,76 +128,137 @@ public final class AugmentUtils {
         noCopyDefSet.add(Rfc6020Mapping.USES);
 
         StatementDefinition def = stmtContext.getPublicDefinition();
-        return (!noCopyDefSet.contains(def));
+        return !noCopyDefSet.contains(def);
     }
 
     public static boolean isReusedByAugment(StmtContext<?, ?, ?> stmtContext) {
 
-        HashSet<StatementDefinition> reusedDefSet = new HashSet<>();
+        Set<StatementDefinition> reusedDefSet = new HashSet<>();
         reusedDefSet.add(Rfc6020Mapping.TYPEDEF);
 
         StatementDefinition def = stmtContext.getPublicDefinition();
-        if (reusedDefSet.contains(def))
-            return true;
-        else
-            return false;
+
+        return reusedDefSet.contains(def);
     }
 
     public static StatementContextBase<?, ?, ?> getAugmentTargetCtx(
             final Mutable<SchemaNodeIdentifier, AugmentStatement, EffectiveStatement<SchemaNodeIdentifier, AugmentStatement>> augmentNode) {
 
-        final SchemaNodeIdentifier augmentTargetNode = augmentNode.getStatementArgument();
+        final SchemaNodeIdentifier augmentTargetNode = augmentNode
+                .getStatementArgument();
+        if (augmentTargetNode == null) {
+            throw new IllegalArgumentException(
+                    "Augment argument null, something bad happened in some of previous parsing phases");
+        }
 
         List<StatementContextBase<?, ?, ?>> rootStatementCtxList = new LinkedList<>();
 
         if (augmentTargetNode.isAbsolute()) {
 
-            QNameModule module;
-            if (augmentTargetNode != null) {
-                module = augmentTargetNode.getPathFromRoot().iterator().next().getModule();
-            } else {
-                throw new IllegalArgumentException(
-                        "Augment argument null, something bad happened in some of previous parsing phases");
-            }
+            QNameModule module = augmentTargetNode.getPathFromRoot().iterator()
+                    .next().getModule();
 
-            StatementContextBase<?, ?, ?> rootStatementCtx = (StatementContextBase<?, ?, ?>) augmentNode.getFromNamespace(
-                    NamespaceToModule.class, module);
+            StatementContextBase<?, ?, ?> rootStatementCtx = (StatementContextBase<?, ?, ?>) augmentNode
+                    .getFromNamespace(NamespaceToModule.class, module);
             rootStatementCtxList.add(rootStatementCtx);
 
-            final Map<?, ?> subModules = rootStatementCtx.getAllFromNamespace(IncludedModuleContext.class);
+            final Map<?, ?> subModules = rootStatementCtx
+                    .getAllFromNamespace(IncludedModuleContext.class);
             if (subModules != null) {
-                rootStatementCtxList.addAll((Collection<? extends StatementContextBase<?, ?, ?>>) subModules.values());
+                rootStatementCtxList
+                        .addAll((Collection<? extends StatementContextBase<?, ?, ?>>) subModules
+                                .values());
             }
 
         } else {
-            StatementContextBase<?, ?, ?> parent = (StatementContextBase<?, ?, ?>) augmentNode.getParentContext();
+            StatementContextBase<?, ?, ?> parent = (StatementContextBase<?, ?, ?>) augmentNode
+                    .getParentContext();
             if (StmtContextUtils.producesDeclared(parent, UsesStatement.class)) {
                 rootStatementCtxList.add(parent.getParentContext());
             } else {
-                //error
+                // error
             }
         }
 
-        List<QName> augmentTargetPath = new LinkedList<>();
-
-        augmentTargetPath.addAll((Collection<? extends QName>) augmentTargetNode.getPathFromRoot());
-
         StatementContextBase<?, ?, ?> augmentTargetCtx = null;
         for (final StatementContextBase<?, ?, ?> rootStatementCtx : rootStatementCtxList) {
-            augmentTargetCtx = Utils.findCtxOfNodeInRoot(rootStatementCtx,
-                    augmentTargetPath);
-            if (augmentTargetCtx != null) break;
+            augmentTargetCtx = findCtxOfNodeInRoot(rootStatementCtx,
+                    augmentTargetNode);
+            if (augmentTargetCtx != null)
+                break;
         }
 
+        return augmentTargetCtx;
+    }
 
-        if (augmentTargetCtx == null) {
+    @Nullable
+    public static StatementContextBase<?, ?, ?> findCtxOfNodeInSubstatements(
+            StatementContextBase<?, ?, ?> rootStmtCtx,
+            final Iterable<QName> path) {
 
-            throw new NullPointerException(String.format(
-                    "Augment path %s not found in target model so its resulting context is null",
-                    augmentNode.rawStatementArgument()));
+        StatementContextBase<?, ?, ?> parent = rootStmtCtx;
 
+        Iterator<QName> pathIter = path.iterator();
+        while (pathIter.hasNext()) {
+            QName nextPathQName = pathIter.next();
+            StatementContextBase<?, ?, ?> foundSubstatement = getSubstatementByQName(
+                    parent, nextPathQName);
+
+            if (foundSubstatement == null) {
+                return null;
+            }
+            if (!pathIter.hasNext()) {
+                return foundSubstatement;
+            }
+
+            parent = foundSubstatement;
         }
 
-        return augmentTargetCtx;
+        return null;
+    }
+
+    public static StatementContextBase<?, ?, ?> getSubstatementByQName(
+            StatementContextBase<?, ?, ?> parent, QName nextPathQName) {
+
+        Collection<StatementContextBase<?, ?, ?>> declaredSubstatement = parent
+                .declaredSubstatements();
+        Collection<StatementContextBase<?, ?, ?>> effectiveSubstatement = parent
+                .effectiveSubstatements();
+
+        Collection<StatementContextBase<?, ?, ?>> allSubstatements = new LinkedList<>();
+        allSubstatements.addAll(declaredSubstatement);
+        allSubstatements.addAll(effectiveSubstatement);
+
+        for (StatementContextBase<?, ?, ?> substatement : allSubstatements) {
+            if (isAllowedAugmentTarget(substatement)
+                    && nextPathQName
+                            .equals(substatement.getStatementArgument())) {
+                return substatement;
+            }
+        }
+
+        return null;
+    }
+
+    public static boolean isAllowedAugmentTarget(
+            StatementContextBase<?, ?, ?> substatement) {
+
+        /*
+         * :TODO Substatement must be allowed augment target type e.g.
+         * Container, etc... and must be not for example grouping, identity etc.
+         * It is problem in case when more than one substatements have the same
+         * QName, for example Grouping and Container are siblings and they have the
+         * same QName. We must find the Container and the Grouping must be ignored
+         * as disallowed augment target.
+         */
+
+        return true;
+    }
+
+    @Nullable
+    public static StatementContextBase<?, ?, ?> findCtxOfNodeInRoot(
+            StatementContextBase<?, ?, ?> rootStmtCtx,
+            final SchemaNodeIdentifier node) {
+        return findCtxOfNodeInSubstatements(rootStmtCtx, node.getPathFromRoot());
     }
 }