Bug 2366 - Effective statement implementation
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / AugmentUtils.java
index 3b9c18c0333b2a441a8b2e1cb21acf46e0888a01..9d99af203aa5c8077996b7e58e1bddac95bebff6 100644 (file)
@@ -7,10 +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;
@@ -18,22 +24,25 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 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(
@@ -43,7 +52,8 @@ public final class AugmentUtils {
         return Utils.parseXPath(ctx, path);
     }
 
-    public static void copyFromSourceToTarget(StatementContextBase<?, ?, ?> sourceCtx,
+    public static void copyFromSourceToTarget(
+            StatementContextBase<?, ?, ?> sourceCtx,
             StatementContextBase<?, ?, ?> targetCtx) throws SourceException {
 
         QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceCtx);
@@ -52,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);
@@ -65,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);
@@ -78,13 +98,15 @@ public final class AugmentUtils {
         }
     }
 
-    public static QNameModule getNewQNameModule(StatementContextBase<?, ?, ?> targetCtx,
+    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;
@@ -106,48 +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 augmentTargetPath = augmentNode.getStatementArgument();
-
-        QNameModule module;
-        if (augmentTargetPath != null) {
-            module = augmentTargetPath.getPathFromRoot().iterator().next().getModule();
-        } else {
+        final SchemaNodeIdentifier augmentTargetNode = augmentNode
+                .getStatementArgument();
+        if (augmentTargetNode == null) {
             throw new IllegalArgumentException(
                     "Augment argument null, something bad happened in some of previous parsing phases");
         }
 
-        StatementContextBase<?, ?, ?> rootStatementCtx = (StatementContextBase<?, ?, ?>) augmentNode.getFromNamespace(
-                NamespaceToModule.class, module);
+        List<StatementContextBase<?, ?, ?>> rootStatementCtxList = new LinkedList<>();
 
-        final StatementContextBase<?, ?, ?> augmentTargetCtx = Utils.findCtxOfNodeInRoot(rootStatementCtx,
-                augmentTargetPath);
+        if (augmentTargetNode.isAbsolute()) {
 
-        if (augmentTargetCtx == null) {
+            QNameModule module = augmentTargetNode.getPathFromRoot().iterator()
+                    .next().getModule();
 
-            throw new NullPointerException(String.format(
-                    "Augment path %s not found in target model so its resulting context is null",
-                    augmentNode.rawStatementArgument()));
+            StatementContextBase<?, ?, ?> rootStatementCtx = (StatementContextBase<?, ?, ?>) augmentNode
+                    .getFromNamespace(NamespaceToModule.class, module);
+            rootStatementCtxList.add(rootStatementCtx);
 
+            final Map<?, ?> subModules = rootStatementCtx
+                    .getAllFromNamespace(IncludedModuleContext.class);
+            if (subModules != null) {
+                rootStatementCtxList
+                        .addAll((Collection<? extends StatementContextBase<?, ?, ?>>) subModules
+                                .values());
+            }
+
+        } else {
+            StatementContextBase<?, ?, ?> parent = (StatementContextBase<?, ?, ?>) augmentNode
+                    .getParentContext();
+            if (StmtContextUtils.producesDeclared(parent, UsesStatement.class)) {
+                rootStatementCtxList.add(parent.getParentContext());
+            } else {
+                // error
+            }
+        }
+
+        StatementContextBase<?, ?, ?> augmentTargetCtx = null;
+        for (final StatementContextBase<?, ?, ?> rootStatementCtx : rootStatementCtxList) {
+            augmentTargetCtx = findCtxOfNodeInRoot(rootStatementCtx,
+                    augmentTargetNode);
+            if (augmentTargetCtx != null)
+                break;
         }
 
         return augmentTargetCtx;
     }
+
+    @Nullable
+    public static StatementContextBase<?, ?, ?> findCtxOfNodeInSubstatements(
+            StatementContextBase<?, ?, ?> rootStmtCtx,
+            final Iterable<QName> path) {
+
+        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 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());
+    }
 }