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.common.base.MoreObjects.ToStringHelper;
13 import com.google.gson.stream.JsonWriter;
14 import java.io.IOException;
15 import java.io.OutputStream;
16 import java.util.List;
17 import javax.xml.XMLConstants;
18 import javax.xml.stream.XMLStreamException;
19 import javax.xml.stream.XMLStreamWriter;
20 import org.opendaylight.restconf.api.FormattableBody;
21 import org.opendaylight.restconf.api.query.PrettyPrintParam;
22 import org.opendaylight.restconf.common.errors.RestconfError;
23 import org.opendaylight.restconf.server.api.PatchStatusContext;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.status.YangPatchStatus;
27 * Result of a {@code PATCH} request as defined in
28 * <a href="https://www.rfc-editor.org/rfc/rfc8072#section-2.3">RFC8072, section 2.3</a>.
30 public final class YangPatchStatusBody extends FormattableBody {
31 private static final String IETF_YANG_PATCH_NAMESPACE = YangPatchStatus.QNAME.getNamespace().toString();
33 private final PatchStatusContext status;
35 public YangPatchStatusBody(final PatchStatusContext status) {
36 this.status = requireNonNull(status);
40 public void formatToJSON(final PrettyPrintParam prettyPrint, final OutputStream out) throws IOException {
41 try (var writer = FormattableBodySupport.createJsonWriter(out, prettyPrint)) {
42 writer.beginObject().name("ietf-yang-patch:yang-patch-status")
43 .beginObject().name("patch-id").value(status.patchId());
48 final var globalErrors = status.globalErrors();
49 if (globalErrors != null) {
50 writeErrors(globalErrors, writer);
52 writer.name("edit-status").beginObject()
53 .name("edit").beginArray();
54 for (var editStatus : status.editCollection()) {
55 writer.beginObject().name("edit-id").value(editStatus.getEditId());
57 final var editErrors = editStatus.getEditErrors();
58 if (editErrors != null) {
59 writeErrors(editErrors, writer);
60 } else if (editStatus.isOk()) {
65 writer.endArray().endObject();
68 writer.endObject().endObject();
73 public void formatToXML(final PrettyPrintParam prettyPrint, final OutputStream out) throws IOException {
74 final var writer = FormattableBodySupport.createXmlWriter(out, prettyPrint);
77 } catch (XMLStreamException e) {
78 throw new IOException("Failed to write body", e);
82 private void formatToXML(final XMLStreamWriter writer) throws XMLStreamException {
83 writer.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, "yang-patch-status", IETF_YANG_PATCH_NAMESPACE);
84 writer.writeDefaultNamespace(IETF_YANG_PATCH_NAMESPACE);
85 writer.writeStartElement("patch-id");
86 writer.writeCharacters(status.patchId());
87 writer.writeEndElement();
90 writer.writeEmptyElement("ok");
92 final var globalErrors = status.globalErrors();
93 if (globalErrors != null) {
94 reportErrors(globalErrors, writer);
96 writer.writeStartElement("edit-status");
97 for (var patchStatusEntity : status.editCollection()) {
98 writer.writeStartElement("edit");
99 writer.writeStartElement("edit-id");
100 writer.writeCharacters(patchStatusEntity.getEditId());
101 writer.writeEndElement();
103 final var editErrors = patchStatusEntity.getEditErrors();
104 if (editErrors != null) {
105 reportErrors(editErrors, writer);
106 } else if (patchStatusEntity.isOk()) {
107 writer.writeEmptyElement("ok");
109 writer.writeEndElement();
111 writer.writeEndElement();
114 writer.writeEndElement();
118 private static void writeOk(final JsonWriter writer) throws IOException {
119 writer.name("ok").beginArray().nullValue().endArray();
122 private void writeErrors(final List<RestconfError> errors, final JsonWriter writer) throws IOException {
123 writer.name("errors").beginObject().name("error").beginArray();
125 for (var restconfError : errors) {
127 .name("error-type").value(restconfError.getErrorType().elementBody())
128 .name("error-tag").value(restconfError.getErrorTag().elementBody());
130 final var errorPath = restconfError.getErrorPath();
131 if (errorPath != null) {
132 writer.name("error-path");
133 status.databind().jsonCodecs().instanceIdentifierCodec().writeValue(writer, errorPath);
135 final var errorMessage = restconfError.getErrorMessage();
136 if (errorMessage != null) {
137 writer.name("error-message").value(errorMessage);
139 final var errorInfo = restconfError.getErrorInfo();
140 if (errorInfo != null) {
141 writer.name("error-info").value(errorInfo);
147 writer.endArray().endObject();
150 private void reportErrors(final List<RestconfError> errors, final XMLStreamWriter writer)
151 throws XMLStreamException {
152 writer.writeStartElement("errors");
154 for (var restconfError : errors) {
155 writer.writeStartElement("error-type");
156 writer.writeCharacters(restconfError.getErrorType().elementBody());
157 writer.writeEndElement();
159 writer.writeStartElement("error-tag");
160 writer.writeCharacters(restconfError.getErrorTag().elementBody());
161 writer.writeEndElement();
164 final var errorPath = restconfError.getErrorPath();
165 if (errorPath != null) {
166 writer.writeStartElement("error-path");
167 status.databind().xmlCodecs().instanceIdentifierCodec().writeValue(writer, errorPath);
168 writer.writeEndElement();
172 final var errorMessage = restconfError.getErrorMessage();
173 if (errorMessage != null) {
174 writer.writeStartElement("error-message");
175 writer.writeCharacters(errorMessage);
176 writer.writeEndElement();
180 final var errorInfo = restconfError.getErrorInfo();
181 if (errorInfo != null) {
182 writer.writeStartElement("error-info");
183 writer.writeCharacters(errorInfo);
184 writer.writeEndElement();
188 writer.writeEndElement();
192 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
193 return helper.add("status", status);