Do not instantiate needless objects in augment
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / DeviateStatementImpl.java
index 94f8ac2f90e77d0a3baf851c91e8146484070ff9..fda3df0b6beef35c9d2613e2c4beb2274579b284 100644 (file)
@@ -7,12 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.DeviateKind;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
@@ -20,17 +23,23 @@ 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.DeviateStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
-import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 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.meta.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModulesDeviatedByModules;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModulesDeviatedByModules.SupportedModules;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeviateEffectiveStatementImpl;
 import org.slf4j.Logger;
@@ -79,6 +88,14 @@ public class DeviateStatementImpl extends AbstractDeclaredStatement<DeviateKind>
 
     public static class Definition extends AbstractStatementSupport<DeviateKind, DeviateStatement,
             EffectiveStatement<DeviateKind, DeviateStatement>> {
+        private static final Map<String, DeviateKind> KEYWORD_TO_DEVIATE_MAP;
+        static {
+            final Builder<String, DeviateKind> keywordToDeviateMapBuilder = ImmutableMap.builder();
+            for (final DeviateKind deviate : DeviateKind.values()) {
+                keywordToDeviateMapBuilder.put(deviate.getKeyword(), deviate);
+            }
+            KEYWORD_TO_DEVIATE_MAP = keywordToDeviateMapBuilder.build();
+        }
 
         private static final Set<YangStmtMapping> SINGLETON_STATEMENTS = ImmutableSet.of(
                 YangStmtMapping.UNITS, YangStmtMapping.CONFIG, YangStmtMapping.MANDATORY,
@@ -88,115 +105,136 @@ public class DeviateStatementImpl extends AbstractDeclaredStatement<DeviateKind>
             super(YangStmtMapping.DEVIATE);
         }
 
-        @Override public DeviateKind parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
-            return Utils.parseDeviateFromString(ctx, value);
+        @Override
+        public DeviateKind parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
+            return SourceException.throwIfNull(KEYWORD_TO_DEVIATE_MAP.get(value),
+                ctx.getStatementSourceReference(), "String '%s' is not valid deviate argument", value);
         }
 
-        @Override public DeviateStatement createDeclared(final StmtContext<DeviateKind, DeviateStatement, ?> ctx) {
+        @Override
+        public DeviateStatement createDeclared(final StmtContext<DeviateKind, DeviateStatement, ?> ctx) {
             return new DeviateStatementImpl(ctx);
         }
 
-        @Override public EffectiveStatement<DeviateKind, DeviateStatement> createEffective(
+        @Override
+        public EffectiveStatement<DeviateKind, DeviateStatement> createEffective(
                 final StmtContext<DeviateKind, DeviateStatement, EffectiveStatement<DeviateKind,
                         DeviateStatement>> ctx) {
             return new DeviateEffectiveStatementImpl(ctx);
         }
 
         @Override
-        public void onFullDefinitionDeclared(final StmtContext.Mutable<DeviateKind, DeviateStatement,
+        public void onFullDefinitionDeclared(final Mutable<DeviateKind, DeviateStatement,
                 EffectiveStatement<DeviateKind, DeviateStatement>> deviateStmtCtx) {
             final DeviateKind deviateKind = deviateStmtCtx.getStatementArgument();
             getSubstatementValidatorForDeviate(deviateKind).validate(deviateStmtCtx);
 
-            final ModelActionBuilder deviateAction = deviateStmtCtx.newInferenceAction(
-                    ModelProcessingPhase.EFFECTIVE_MODEL);
-
             final SchemaNodeIdentifier deviationTarget =
                     (SchemaNodeIdentifier) deviateStmtCtx.getParentContext().getStatementArgument();
 
+            if (!isDeviationSupported(deviateStmtCtx, deviationTarget)) {
+                return;
+            }
+
+            final ModelActionBuilder deviateAction = deviateStmtCtx.newInferenceAction(
+                    ModelProcessingPhase.EFFECTIVE_MODEL);
+
             final Prerequisite<StmtContext<DeviateKind, DeviateStatement, EffectiveStatement<DeviateKind,
                     DeviateStatement>>> sourceCtxPrerequisite =
                     deviateAction.requiresCtx(deviateStmtCtx, ModelProcessingPhase.EFFECTIVE_MODEL);
 
-            final Prerequisite<StmtContext.Mutable<?, ?, EffectiveStatement<?, ?>>> targetCtxPrerequisite =
-                    (Prerequisite<StmtContext.Mutable<?, ?, EffectiveStatement<?, ?>>>) deviateAction
-                    .mutatesEffectiveCtx(deviateStmtCtx.getRoot(), SchemaNodeIdentifierBuildNamespace.class,
-                            deviationTarget);
-
-                    deviateAction.apply(new InferenceAction() {
-                        @Override
-                        public void apply() throws InferenceException {
-                            // FIXME once BUG-7760 gets fixed, there will be no need for these dirty casts
-                            final StatementContextBase<?, ?, ?> sourceNodeStmtCtx =
-                                    (StatementContextBase<?, ?, ?>) sourceCtxPrerequisite.get();
-                            final StatementContextBase<?, ?, ?> targetNodeStmtCtx =
-                                    (StatementContextBase<?, ?, ?>) targetCtxPrerequisite.get();
-
-                            switch (deviateKind) {
-                                case NOT_SUPPORTED:
-                                    targetNodeStmtCtx.setIsSupportedToBuildEffective(false);
-                                    break;
-                                case ADD:
-                                    performDeviateAdd(sourceNodeStmtCtx, targetNodeStmtCtx);
-                                    break;
-                                case REPLACE:
-                                    performDeviateReplace(sourceNodeStmtCtx, targetNodeStmtCtx);
-                                    break;
-                                case DELETE:
-                                    performDeviateDelete(sourceNodeStmtCtx, targetNodeStmtCtx);
-                            }
-                        }
-
-                        @Override
-                        public void prerequisiteFailed(Collection<? extends Prerequisite<?>> failed) {
-                            throw new InferenceException(deviateStmtCtx.getParentContext().getStatementSourceReference(),
-                                    "Deviation target '%s' not found.", deviationTarget);
-                        }
-                    });
+            final Prerequisite<Mutable<?, ?, EffectiveStatement<?, ?>>> targetCtxPrerequisite =
+                    deviateAction.mutatesEffectiveCtx(deviateStmtCtx.getRoot(),
+                        SchemaNodeIdentifierBuildNamespace.class,  deviationTarget);
+
+            deviateAction.apply(new InferenceAction() {
+                @Override
+                public void apply(final InferenceContext ctx) throws InferenceException {
+                    // FIXME once BUG-7760 gets fixed, there will be no need for these dirty casts
+                    final StatementContextBase<?, ?, ?> sourceNodeStmtCtx =
+                            (StatementContextBase<?, ?, ?>) sourceCtxPrerequisite.resolve(ctx);
+                    final StatementContextBase<?, ?, ?> targetNodeStmtCtx =
+                            (StatementContextBase<?, ?, ?>) targetCtxPrerequisite.resolve(ctx);
+
+                    switch (deviateKind) {
+                        case NOT_SUPPORTED:
+                            targetNodeStmtCtx.setIsSupportedToBuildEffective(false);
+                            break;
+                        case ADD:
+                            performDeviateAdd(sourceNodeStmtCtx, targetNodeStmtCtx);
+                            break;
+                        case REPLACE:
+                            performDeviateReplace(sourceNodeStmtCtx, targetNodeStmtCtx);
+                            break;
+                        case DELETE:
+                            performDeviateDelete(sourceNodeStmtCtx, targetNodeStmtCtx);
+                    }
+                }
+
+                @Override
+                public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
+                    throw new InferenceException(deviateStmtCtx.getParentContext().getStatementSourceReference(),
+                        "Deviation target '%s' not found.", deviationTarget);
+                }
+            });
+        }
+
+        private static boolean isDeviationSupported(final Mutable<DeviateKind, DeviateStatement,
+                EffectiveStatement<DeviateKind, DeviateStatement>> deviateStmtCtx,
+                final SchemaNodeIdentifier deviationTarget) {
+            final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules = deviateStmtCtx.getFromNamespace(
+                    ModulesDeviatedByModules.class, SupportedModules.SUPPORTED_MODULES);
+            if (modulesDeviatedByModules == null) {
+                return true;
+            }
+
+            final QNameModule currentModule = deviateStmtCtx.getFromNamespace(ModuleCtxToModuleQName.class,
+                    deviateStmtCtx.getRoot());
+            final QNameModule targetModule = deviationTarget.getLastComponent().getModule();
+
+            final Set<QNameModule> deviationModulesSupportedByTargetModule = modulesDeviatedByModules.get(targetModule);
+            if (deviationModulesSupportedByTargetModule != null) {
+                return deviationModulesSupportedByTargetModule.contains(currentModule);
+            }
+
+            return false;
         }
 
         private static void performDeviateAdd(final StatementContextBase<?, ?, ?> deviateStmtCtx,
                 final StatementContextBase<?, ?, ?> targetCtx) {
-            for (StatementContextBase<?, ?, ?> originalStmtCtx : deviateStmtCtx.declaredSubstatements()) {
+            for (Mutable<?, ?, ?> originalStmtCtx : deviateStmtCtx.mutableDeclaredSubstatements()) {
                 validateDeviationTarget(originalStmtCtx, targetCtx);
                 addStatement(originalStmtCtx, targetCtx);
             }
         }
 
-        private static void addStatement(final StatementContextBase<?, ?, ?> stmtCtxToBeAdded,
+        private static void addStatement(final Mutable<?, ?, ?> stmtCtxToBeAdded,
                 final StatementContextBase<?, ?, ?> targetCtx) {
-            if (StmtContextUtils.isUnknownStatement(stmtCtxToBeAdded)) {
-                targetCtx.addEffectiveSubstatement(stmtCtxToBeAdded.createCopy(targetCtx, CopyType.ORIGINAL));
-                return;
-            }
-
-            final StatementDefinition stmtToBeAdded = stmtCtxToBeAdded.getPublicDefinition();
-
-            if (SINGLETON_STATEMENTS.contains(stmtToBeAdded) || (YangStmtMapping.DEFAULT.equals(stmtToBeAdded)
-                    && YangStmtMapping.LEAF.equals(targetCtx.getPublicDefinition()))) {
-                final Iterable<StatementContextBase<?, ?, ?>> targetCtxSubstatements = Iterables.concat(
-                        targetCtx.declaredSubstatements(), targetCtx.effectiveSubstatements());
-
-                for (final StatementContextBase<?, ?, ?> targetCtxSubstatement : targetCtxSubstatements) {
-                    InferenceException.throwIf(stmtToBeAdded.equals(targetCtxSubstatement.getPublicDefinition()),
-                            stmtCtxToBeAdded.getStatementSourceReference(), "Deviation cannot add substatement %s " +
-                            "to target node %s because it is already defined in target and can appear only once.",
-                            stmtToBeAdded.getStatementName(), targetCtx.getStatementArgument());
+            if (!StmtContextUtils.isUnknownStatement(stmtCtxToBeAdded)) {
+                final StatementDefinition stmtToBeAdded = stmtCtxToBeAdded.getPublicDefinition();
+                if (SINGLETON_STATEMENTS.contains(stmtToBeAdded) || YangStmtMapping.DEFAULT.equals(stmtToBeAdded)
+                        && YangStmtMapping.LEAF.equals(targetCtx.getPublicDefinition())) {
+                    for (final StmtContext<?, ?, ?> targetCtxSubstatement : targetCtx.allSubstatements()) {
+                        InferenceException.throwIf(stmtToBeAdded.equals(targetCtxSubstatement.getPublicDefinition()),
+                            stmtCtxToBeAdded.getStatementSourceReference(), "Deviation cannot add substatement %s "
+                        + "to target node %s because it is already defined in target and can appear only once.",
+                        stmtToBeAdded.getStatementName(), targetCtx.getStatementArgument());
+                    }
                 }
             }
 
-            targetCtx.addEffectiveSubstatement(stmtCtxToBeAdded.createCopy(targetCtx, CopyType.ORIGINAL));
+            targetCtx.addEffectiveSubstatement(targetCtx.childCopyOf(stmtCtxToBeAdded, CopyType.ORIGINAL));
         }
 
         private static void performDeviateReplace(final StatementContextBase<?, ?, ?> deviateStmtCtx,
                 final StatementContextBase<?, ?, ?> targetCtx) {
-            for (StatementContextBase<?, ?, ?> originalStmtCtx : deviateStmtCtx.declaredSubstatements()) {
+            for (Mutable<?, ?, ?> originalStmtCtx : deviateStmtCtx.mutableDeclaredSubstatements()) {
                 validateDeviationTarget(originalStmtCtx, targetCtx);
                 replaceStatement(originalStmtCtx, targetCtx);
             }
         }
 
-        private static void replaceStatement(final StatementContextBase<?, ?, ?> stmtCtxToBeReplaced,
+        private static void replaceStatement(final Mutable<?, ?, ?> stmtCtxToBeReplaced,
                 final StatementContextBase<?, ?, ?> targetCtx) {
             final StatementDefinition stmtToBeReplaced = stmtCtxToBeReplaced.getPublicDefinition();
 
@@ -208,18 +246,18 @@ public class DeviateStatementImpl extends AbstractDeclaredStatement<DeviateKind>
                 return;
             }
 
-            for (final StatementContextBase<?, ?, ?> targetCtxSubstatement : targetCtx.effectiveSubstatements()) {
+            for (final StmtContext<?, ?, ?> targetCtxSubstatement : targetCtx.effectiveSubstatements()) {
                 if (stmtToBeReplaced.equals(targetCtxSubstatement.getPublicDefinition())) {
                     targetCtx.removeStatementFromEffectiveSubstatements(stmtToBeReplaced);
-                    targetCtx.addEffectiveSubstatement(stmtCtxToBeReplaced.createCopy(targetCtx, CopyType.ORIGINAL));
+                    targetCtx.addEffectiveSubstatement(targetCtx.childCopyOf(stmtCtxToBeReplaced, CopyType.ORIGINAL));
                     return;
                 }
             }
 
-            for (final StatementContextBase<?, ?, ?> targetCtxSubstatement : targetCtx.declaredSubstatements()) {
+            for (final Mutable<?, ?, ?> targetCtxSubstatement : targetCtx.mutableDeclaredSubstatements()) {
                 if (stmtToBeReplaced.equals(targetCtxSubstatement.getPublicDefinition())) {
                     targetCtxSubstatement.setIsSupportedToBuildEffective(false);
-                    targetCtx.addEffectiveSubstatement(stmtCtxToBeReplaced.createCopy(targetCtx, CopyType.ORIGINAL));
+                    targetCtx.addEffectiveSubstatement(targetCtx.childCopyOf(stmtCtxToBeReplaced, CopyType.ORIGINAL));
                     return;
                 }
             }
@@ -231,18 +269,18 @@ public class DeviateStatementImpl extends AbstractDeclaredStatement<DeviateKind>
 
         private static void performDeviateDelete(final StatementContextBase<?, ?, ?> deviateStmtCtx,
                 final StatementContextBase<?, ?, ?> targetCtx) {
-            for (StatementContextBase<?, ?, ?> originalStmtCtx : deviateStmtCtx.declaredSubstatements()) {
+            for (Mutable<?, ?, ?> originalStmtCtx : deviateStmtCtx.mutableDeclaredSubstatements()) {
                 validateDeviationTarget(originalStmtCtx, targetCtx);
                 deleteStatement(originalStmtCtx, targetCtx);
             }
         }
 
-        private static void deleteStatement(final StatementContextBase<?, ?, ?> stmtCtxToBeDeleted,
+        private static void deleteStatement(final StmtContext<?, ?, ?> stmtCtxToBeDeleted,
                 final StatementContextBase<?, ?, ?> targetCtx) {
             final StatementDefinition stmtToBeDeleted = stmtCtxToBeDeleted.getPublicDefinition();
             final String stmtArgument = stmtCtxToBeDeleted.rawStatementArgument();
 
-            for (final StatementContextBase<?, ?, ?> targetCtxSubstatement : targetCtx.effectiveSubstatements()) {
+            for (final Mutable<?, ?, ?> targetCtxSubstatement : targetCtx.mutableEffectiveSubstatements()) {
                 if (statementsAreEqual(stmtToBeDeleted, stmtArgument, targetCtxSubstatement.getPublicDefinition(),
                         targetCtxSubstatement.rawStatementArgument())) {
                     targetCtx.removeStatementFromEffectiveSubstatements(stmtToBeDeleted, stmtArgument);
@@ -250,7 +288,7 @@ public class DeviateStatementImpl extends AbstractDeclaredStatement<DeviateKind>
                 }
             }
 
-            for (final StatementContextBase<?, ?, ?> targetCtxSubstatement : targetCtx.declaredSubstatements()) {
+            for (final Mutable<?, ?, ?> targetCtxSubstatement : targetCtx.mutableDeclaredSubstatements()) {
                 if (statementsAreEqual(stmtToBeDeleted, stmtArgument, targetCtxSubstatement.getPublicDefinition(),
                         targetCtxSubstatement.rawStatementArgument())) {
                     targetCtxSubstatement.setIsSupportedToBuildEffective(false);
@@ -268,16 +306,16 @@ public class DeviateStatementImpl extends AbstractDeclaredStatement<DeviateKind>
             return firstStmtDef.equals(secondStmtDef) && Objects.equals(firstStmtArg, secondStmtArg);
         }
 
-        private static void validateDeviationTarget(final StatementContextBase<?, ?, ?> deviateSubStmtCtx,
-                final StatementContextBase<?, ?, ?> targetCtx) {
+        private static void validateDeviationTarget(final StmtContext<?, ?, ?> deviateSubStmtCtx,
+                final StmtContext<?, ?, ?> targetCtx) {
             InferenceException.throwIf(!isSupportedDeviationTarget(deviateSubStmtCtx, targetCtx,
                     targetCtx.getRootVersion()), deviateSubStmtCtx.getStatementSourceReference(),
                     "%s is not a valid deviation target for substatement %s.",
                     targetCtx.getStatementArgument(), deviateSubStmtCtx.getPublicDefinition().getStatementName());
         }
 
-        private static boolean isSupportedDeviationTarget(final StatementContextBase<?, ?, ?> deviateSubstatementCtx,
-                final StatementContextBase<?, ?, ?> deviateTargetCtx, final YangVersion yangVersion) {
+        private static boolean isSupportedDeviationTarget(final StmtContext<?, ?, ?> deviateSubstatementCtx,
+                final StmtContext<?, ?, ?> deviateTargetCtx, final YangVersion yangVersion) {
             Set<StatementDefinition> supportedDeviationTargets =
                     YangValidationBundles.SUPPORTED_DEVIATION_TARGETS.get(deviateTargetCtx.getRootVersion(),
                             deviateSubstatementCtx.getPublicDefinition());