37c2523b404bd6f55cfdb80bd08117fa7b23e895
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / jersey / providers / errors / StreamWriterWithDisabledValidation.java
1 /*
2  * Copyright © 2019 FRINX s.r.o. 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.restconf.nb.rfc8040.jersey.providers.errors;
9
10 import java.io.IOException;
11 import org.opendaylight.restconf.server.api.DatabindContext;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev170126.Errors;
13 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
14 import org.opendaylight.yangtools.yang.data.api.schema.stream.ForwardingNormalizedNodeStreamWriter;
15 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
16 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
17
18 /**
19  * Created delegating writer to special-case error-info as error-info is defined as an empty container in the restconf
20  * yang schema but we create a leaf node so we can output it. The delegate stream writer validates the node type against
21  * the schema and thus will expect a LeafSchemaNode but the schema has a ContainerSchemaNode so, to avoid an error,
22  * we override the leafNode behavior for error-info.
23  */
24 abstract class StreamWriterWithDisabledValidation extends ForwardingNormalizedNodeStreamWriter {
25     private boolean inOurLeaf;
26
27     @Override
28     public final void startLeafNode(final NodeIdentifier name) throws IOException {
29         if (RestconfDocumentedExceptionMapper.ERROR_INFO_QNAME.equals(name.getNodeType())) {
30             inOurLeaf = true;
31             startLeafNodeWithDisabledValidation(name);
32         } else {
33             super.startLeafNode(name);
34         }
35     }
36
37     /**
38      * Writing of the excluded leaf to the output stream.
39      *
40      * @param nodeIdentifier Node identifier of the leaf to be written to output stream.
41      * @throws IOException Writing of the leaf to output stream failed.
42      */
43     abstract void startLeafNodeWithDisabledValidation(NodeIdentifier nodeIdentifier) throws IOException;
44
45     @Override
46     public final void scalarValue(final Object value) throws IOException {
47         if (inOurLeaf) {
48             scalarValueWithDisabledValidation(value);
49         } else {
50             super.scalarValue(value);
51         }
52     }
53
54     /**
55      * Writing of the value of the excluded leaf to the output stream.
56      *
57      * @param value Value of the excluded leaf.
58      * @throws IOException Writing of the leaf value to the output stream failed.
59      */
60     abstract void scalarValueWithDisabledValidation(Object value) throws IOException;
61
62     @Override
63     public final void endNode() throws IOException {
64         if (inOurLeaf) {
65             inOurLeaf = false;
66             endNodeWithDisabledValidation();
67         } else {
68             super.endNode();
69         }
70     }
71
72     /**
73      * Writing of the end element with disabled validation.
74      *
75      * @throws IOException Writing of the end element to the output stream failed.
76      */
77     abstract void endNodeWithDisabledValidation() throws IOException;
78
79     static final Inference errorsContainerInference(final DatabindContext databindContext) {
80         final var stack = SchemaInferenceStack.of(databindContext.modelContext());
81         stack.enterGrouping(Errors.QNAME);
82         return stack.toInference();
83     }
84 }