JSON: Resolve 500 response from device exception
[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 // FIXME remove this class
25 abstract class StreamWriterWithDisabledValidation extends ForwardingNormalizedNodeStreamWriter {
26     private boolean inOurLeaf;
27
28     @Override
29     public final void startLeafNode(final NodeIdentifier name) throws IOException {
30         if (RestconfDocumentedExceptionMapper.ERROR_INFO_QNAME.equals(name.getNodeType())) {
31             inOurLeaf = true;
32             startLeafNodeWithDisabledValidation(name);
33         } else {
34             super.startLeafNode(name);
35         }
36     }
37
38     /**
39      * Writing of the excluded leaf to the output stream.
40      *
41      * @param nodeIdentifier Node identifier of the leaf to be written to output stream.
42      * @throws IOException Writing of the leaf to output stream failed.
43      */
44     abstract void startLeafNodeWithDisabledValidation(NodeIdentifier nodeIdentifier) throws IOException;
45
46     @Override
47     public final void scalarValue(final Object value) throws IOException {
48         if (inOurLeaf) {
49             scalarValueWithDisabledValidation(value);
50         } else {
51             super.scalarValue(value);
52         }
53     }
54
55     /**
56      * Writing of the value of the excluded leaf to the output stream.
57      *
58      * @param value Value of the excluded leaf.
59      * @throws IOException Writing of the leaf value to the output stream failed.
60      */
61     abstract void scalarValueWithDisabledValidation(Object value) throws IOException;
62
63     @Override
64     public final void endNode() throws IOException {
65         if (inOurLeaf) {
66             inOurLeaf = false;
67             endNodeWithDisabledValidation();
68         } else {
69             super.endNode();
70         }
71     }
72
73     /**
74      * Writing of the end element with disabled validation.
75      *
76      * @throws IOException Writing of the end element to the output stream failed.
77      */
78     abstract void endNodeWithDisabledValidation() throws IOException;
79
80     static final Inference errorsContainerInference(final DatabindContext databindContext) {
81         final var stack = SchemaInferenceStack.of(databindContext.modelContext());
82         stack.enterGrouping(Errors.QNAME);
83         return stack.toInference();
84     }
85 }