2 * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.restconf.server.spi;
10 import static java.util.Objects.requireNonNull;
12 import com.google.gson.stream.JsonWriter;
13 import java.io.IOException;
14 import java.io.OutputStream;
15 import java.nio.charset.StandardCharsets;
16 import java.util.List;
17 import javax.xml.stream.XMLOutputFactory;
18 import javax.xml.stream.XMLStreamException;
19 import javax.xml.stream.XMLStreamWriter;
20 import org.opendaylight.restconf.api.FormatParameters;
21 import org.opendaylight.restconf.api.FormattableBody;
22 import org.opendaylight.restconf.api.query.PrettyPrintParam;
23 import org.opendaylight.restconf.common.errors.RestconfError;
24 import org.opendaylight.restconf.server.api.PatchStatusContext;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.status.YangPatchStatus;
28 * Result of a {@code PATCH} request as defined in
29 * <a href="https://www.rfc-editor.org/rfc/rfc8072#section-2.3">RFC8072, section 2.3</a>.
31 public final class YangPatchStatusBody extends FormattableBody {
32 private static final String XML_NAMESPACE = YangPatchStatus.QNAME.getNamespace().toString();
33 // FIXME: remove this factory
34 private static final XMLOutputFactory XML_FACTORY;
37 final var f = XMLOutputFactory.newFactory();
38 f.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
42 private final PatchStatusContext status;
44 public YangPatchStatusBody(final FormatParameters format, final PatchStatusContext status) {
46 this.status = requireNonNull(status);
50 public YangPatchStatusBody(final PatchStatusContext status) {
51 this(() -> PrettyPrintParam.FALSE, status);
55 protected void formatToJSON(final OutputStream out, final FormatParameters format) throws IOException {
56 try (var writer = FormattableBodySupport.createJsonWriter(out, () -> PrettyPrintParam.FALSE)) {
57 writer.beginObject().name("ietf-yang-patch:yang-patch-status")
58 .beginObject().name("patch-id").value(status.patchId());
63 final var globalErrors = status.globalErrors();
64 if (globalErrors != null) {
65 writeErrors(globalErrors, writer);
67 writer.name("edit-status").beginObject()
68 .name("edit").beginArray();
69 for (var editStatus : status.editCollection()) {
70 writer.beginObject().name("edit-id").value(editStatus.getEditId());
72 final var editErrors = editStatus.getEditErrors();
73 if (editErrors != null) {
74 writeErrors(editErrors, writer);
75 } else if (editStatus.isOk()) {
80 writer.endArray().endObject();
83 writer.endObject().endObject();
88 protected void formatToXML(final OutputStream out, final FormatParameters format) throws IOException {
90 final var writer = XML_FACTORY.createXMLStreamWriter(out, StandardCharsets.UTF_8.name());
92 } catch (XMLStreamException e) {
93 throw new IOException("Failed to write body", e);
97 private void formatToXML(final XMLStreamWriter writer) throws XMLStreamException {
98 writer.writeStartElement("", "yang-patch-status", XML_NAMESPACE);
99 writer.writeStartElement("patch-id");
100 writer.writeCharacters(status.patchId());
101 writer.writeEndElement();
104 writer.writeEmptyElement("ok");
106 final var globalErrors = status.globalErrors();
107 if (globalErrors != null) {
108 reportErrors(globalErrors, writer);
110 writer.writeStartElement("edit-status");
111 for (var patchStatusEntity : status.editCollection()) {
112 writer.writeStartElement("edit");
113 writer.writeStartElement("edit-id");
114 writer.writeCharacters(patchStatusEntity.getEditId());
115 writer.writeEndElement();
117 final var editErrors = patchStatusEntity.getEditErrors();
118 if (editErrors != null) {
119 reportErrors(editErrors, writer);
120 } else if (patchStatusEntity.isOk()) {
121 writer.writeEmptyElement("ok");
123 writer.writeEndElement();
125 writer.writeEndElement();
128 writer.writeEndElement();
132 private static void writeOk(final JsonWriter writer) throws IOException {
133 writer.name("ok").beginArray().nullValue().endArray();
136 private void writeErrors(final List<RestconfError> errors, final JsonWriter writer) throws IOException {
137 writer.name("errors").beginObject().name("error").beginArray();
139 for (var restconfError : errors) {
141 .name("error-type").value(restconfError.getErrorType().elementBody())
142 .name("error-tag").value(restconfError.getErrorTag().elementBody());
144 final var errorPath = restconfError.getErrorPath();
145 if (errorPath != null) {
146 writer.name("error-path");
147 status.databind().jsonCodecs().instanceIdentifierCodec().writeValue(writer, errorPath);
149 final var errorMessage = restconfError.getErrorMessage();
150 if (errorMessage != null) {
151 writer.name("error-message").value(errorMessage);
153 final var errorInfo = restconfError.getErrorInfo();
154 if (errorInfo != null) {
155 writer.name("error-info").value(errorInfo);
161 writer.endArray().endObject();
164 private void reportErrors(final List<RestconfError> errors, final XMLStreamWriter writer)
165 throws XMLStreamException {
166 writer.writeStartElement("errors");
168 for (var restconfError : errors) {
169 writer.writeStartElement("error-type");
170 writer.writeCharacters(restconfError.getErrorType().elementBody());
171 writer.writeEndElement();
173 writer.writeStartElement("error-tag");
174 writer.writeCharacters(restconfError.getErrorTag().elementBody());
175 writer.writeEndElement();
178 final var errorPath = restconfError.getErrorPath();
179 if (errorPath != null) {
180 writer.writeStartElement("error-path");
181 status.databind().xmlCodecs().instanceIdentifierCodec().writeValue(writer, errorPath);
182 writer.writeEndElement();
186 final var errorMessage = restconfError.getErrorMessage();
187 if (errorMessage != null) {
188 writer.writeStartElement("error-message");
189 writer.writeCharacters(errorMessage);
190 writer.writeEndElement();
194 final var errorInfo = restconfError.getErrorInfo();
195 if (errorInfo != null) {
196 writer.writeStartElement("error-info");
197 writer.writeCharacters(errorInfo);
198 writer.writeEndElement();
202 writer.writeEndElement();