Reduce use of Status
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / jersey / providers / XmlPatchStatusBodyWriter.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.restconf.nb.rfc8040.jersey.providers;
9
10 import java.io.IOException;
11 import java.io.OutputStream;
12 import java.nio.charset.StandardCharsets;
13 import java.util.List;
14 import javax.ws.rs.Produces;
15 import javax.ws.rs.ext.Provider;
16 import javax.xml.stream.XMLOutputFactory;
17 import javax.xml.stream.XMLStreamException;
18 import javax.xml.stream.XMLStreamWriter;
19 import org.opendaylight.restconf.api.MediaTypes;
20 import org.opendaylight.restconf.common.errors.RestconfError;
21 import org.opendaylight.restconf.server.api.DatabindContext;
22 import org.opendaylight.restconf.server.api.PatchStatusContext;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.status.YangPatchStatus;
24
25 @Provider
26 @Produces(MediaTypes.APPLICATION_YANG_DATA_XML)
27 public class XmlPatchStatusBodyWriter extends AbstractPatchStatusBodyWriter {
28     private static final String XML_NAMESPACE = YangPatchStatus.QNAME.getNamespace().toString();
29     private static final XMLOutputFactory XML_FACTORY;
30
31     static {
32         XML_FACTORY = XMLOutputFactory.newFactory();
33         XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
34     }
35
36     @Override
37     void writeTo(final PatchStatusContext body, final OutputStream out) throws IOException {
38         try {
39             final var xmlWriter = XML_FACTORY.createXMLStreamWriter(out, StandardCharsets.UTF_8.name());
40             writeDocument(xmlWriter, body);
41         } catch (final XMLStreamException e) {
42             throw new IOException("Failed to write body", e);
43         }
44     }
45
46     private static void writeDocument(final XMLStreamWriter writer, final PatchStatusContext body)
47             throws XMLStreamException {
48         writer.writeStartElement("", "yang-patch-status", XML_NAMESPACE);
49         writer.writeStartElement("patch-id");
50         writer.writeCharacters(body.patchId());
51         writer.writeEndElement();
52
53         if (body.ok()) {
54             writer.writeEmptyElement("ok");
55         } else {
56             final var globalErrors = body.globalErrors();
57             if (globalErrors != null) {
58                 reportErrors(body.databind(), globalErrors, writer);
59             } else {
60                 writer.writeStartElement("edit-status");
61                 for (var patchStatusEntity : body.editCollection()) {
62                     writer.writeStartElement("edit");
63                     writer.writeStartElement("edit-id");
64                     writer.writeCharacters(patchStatusEntity.getEditId());
65                     writer.writeEndElement();
66
67                     final var editErrors = patchStatusEntity.getEditErrors();
68                     if (editErrors != null) {
69                         reportErrors(body.databind(), editErrors, writer);
70                     } else if (patchStatusEntity.isOk()) {
71                         writer.writeEmptyElement("ok");
72                     }
73                     writer.writeEndElement();
74                 }
75                 writer.writeEndElement();
76             }
77         }
78         writer.writeEndElement();
79         writer.flush();
80     }
81
82     private static void reportErrors(final DatabindContext databind, final List<RestconfError> errors,
83             final XMLStreamWriter writer) throws XMLStreamException {
84         writer.writeStartElement("errors");
85
86         for (var restconfError : errors) {
87             writer.writeStartElement("error-type");
88             writer.writeCharacters(restconfError.getErrorType().elementBody());
89             writer.writeEndElement();
90
91             writer.writeStartElement("error-tag");
92             writer.writeCharacters(restconfError.getErrorTag().elementBody());
93             writer.writeEndElement();
94
95             // optional node
96             final var errorPath = restconfError.getErrorPath();
97             if (errorPath != null) {
98                 writer.writeStartElement("error-path");
99                 databind.xmlCodecs().instanceIdentifierCodec().writeValue(writer, errorPath);
100                 writer.writeEndElement();
101             }
102
103             // optional node
104             final var errorMessage = restconfError.getErrorMessage();
105             if (errorMessage != null) {
106                 writer.writeStartElement("error-message");
107                 writer.writeCharacters(errorMessage);
108                 writer.writeEndElement();
109             }
110
111             // optional node
112             final var errorInfo = restconfError.getErrorInfo();
113             if (errorInfo != null) {
114                 writer.writeStartElement("error-info");
115                 writer.writeCharacters(errorInfo);
116                 writer.writeEndElement();
117             }
118         }
119
120         writer.writeEndElement();
121     }
122 }