Split out AbstractValidation
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / AbstractValidation.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
9
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import java.util.Optional;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
17 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
19 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * A forwarding {@link ModificationApplyOperation}. Useful for strategies which do not deal with data layout, but rather
26  * perform additional validation.
27  */
28 abstract class AbstractValidation extends ModificationApplyOperation {
29     private static final Logger LOG = LoggerFactory.getLogger(AbstractValidation.class);
30
31     private final @NonNull ModificationApplyOperation delegate;
32
33     AbstractValidation(final ModificationApplyOperation delegate) {
34         this.delegate = requireNonNull(delegate);
35     }
36
37     @Override
38     public final Optional<ModificationApplyOperation> getChild(final PathArgument child) {
39         return delegate.getChild(child);
40     }
41
42     @Override
43     final ChildTrackingPolicy getChildPolicy() {
44         return delegate.getChildPolicy();
45     }
46
47     @Override
48     final void mergeIntoModifiedNode(final ModifiedNode node, final NormalizedNode<?, ?> value, final Version version) {
49         delegate.mergeIntoModifiedNode(node, value, version);
50     }
51
52     @Override
53     final void quickVerifyStructure(final NormalizedNode<?, ?> modification) {
54         delegate.quickVerifyStructure(modification);
55     }
56
57     @Override
58     final void recursivelyVerifyStructure(final NormalizedNode<?, ?> value) {
59         delegate.recursivelyVerifyStructure(value);
60     }
61
62     @Override
63     final Optional<? extends TreeNode> apply(final ModifiedNode modification,
64             final Optional<? extends TreeNode> storeMeta, final Version version) {
65         Optional<? extends TreeNode> ret = modification.getValidatedNode(this, storeMeta);
66         if (ret == null) {
67             // This might also mean the delegate is maintaining validation
68             if (delegate instanceof AbstractValidation) {
69                 ret = modification.getValidatedNode(delegate, storeMeta);
70                 if (ret != null) {
71                     return ret;
72                 }
73             }
74
75             // Deal with the result moving on us
76             ret = delegate.apply(modification, storeMeta, version);
77             ret.ifPresent(meta -> enforceOnData(meta.getData()));
78         }
79         return ret;
80     }
81
82     @Override
83     final void checkApplicable(final ModificationPath path, final NodeModification modification,
84             final Optional<? extends TreeNode> current, final Version version) throws DataValidationFailedException {
85         delegate.checkApplicable(path, modification, current, version);
86         if (!(modification instanceof ModifiedNode)) {
87             // FIXME: 7.0.0: turn this into a verify?
88             LOG.debug("Could not validate {}, does not implement expected class {}", modification, ModifiedNode.class);
89             return;
90         }
91
92         final ModifiedNode modified = (ModifiedNode) modification;
93         if (delegate instanceof AbstractValidation) {
94             checkApplicable(path, verifyNotNull(modified.getValidatedNode(delegate, current)));
95             return;
96         }
97
98         // We need to actually perform the operation to deal with merge in a sane manner. We know the modification
99         // is immutable, so the result of validation will probably not change. Note we should not be checking number
100         final Optional<? extends TreeNode> applied = delegate.apply(modified, current, version);
101         checkApplicable(path, applied);
102
103         // Everything passed. We now have a snapshot of the result node, it would be too bad if we just threw it out.
104         // We know what the result of an apply operation is going to be *if* the following are kept unchanged:
105         // - the 'current' node
106         // - the effective model context (therefore, the fact this object is associated with the modification)
107         //
108         // So let's stash the result. We will pick it up during apply operation.
109         modified.setValidatedNode(this, current, applied);
110     }
111
112     private void checkApplicable(final ModificationPath path, final Optional<? extends TreeNode> applied)
113             throws DataValidationFailedException {
114         if (applied.isPresent()) {
115             // We only enforce min/max on present data and rely on MandatoryLeafEnforcer to take care of the empty case
116             enforceOnData(path, applied.orElseThrow().getData());
117         }
118     }
119
120     @Override
121     void fullVerifyStructure(final NormalizedNode<?, ?> modification) {
122         delegate.fullVerifyStructure(modification);
123         enforceOnData(modification);
124     }
125
126     final @NonNull ModificationApplyOperation delegate() {
127         return delegate;
128     }
129
130     abstract void enforceOnData(ModificationPath path, NormalizedNode<?, ?> value)
131         throws DataValidationFailedException;
132
133     abstract void enforceOnData(@NonNull NormalizedNode<?, ?> data);
134
135     @Override
136     ToStringHelper addToStringAttributes(final ToStringHelper helper) {
137         return helper.add("delegate", delegate);
138     }
139 }