Bug 3866: Support for Restconf HTTP Patch
[netconf.git] / opendaylight / restconf / sal-rest-connector / src / main / java / org / opendaylight / netconf / sal / rest / impl / PATCHXmlBodyWriter.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.netconf.sal.rest.impl;
9
10 import java.io.IOException;
11 import java.io.OutputStream;
12 import java.lang.annotation.Annotation;
13 import java.lang.reflect.Type;
14 import java.util.List;
15 import javax.ws.rs.Produces;
16 import javax.ws.rs.WebApplicationException;
17 import javax.ws.rs.core.MediaType;
18 import javax.ws.rs.core.MultivaluedMap;
19 import javax.ws.rs.ext.MessageBodyWriter;
20 import javax.ws.rs.ext.Provider;
21 import javax.xml.stream.FactoryConfigurationError;
22 import javax.xml.stream.XMLOutputFactory;
23 import javax.xml.stream.XMLStreamException;
24 import javax.xml.stream.XMLStreamWriter;
25 import org.opendaylight.netconf.sal.rest.api.Draft02.MediaTypes;
26 import org.opendaylight.netconf.sal.rest.api.RestconfService;
27 import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusContext;
28 import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusEntity;
29 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
30
31 @Provider
32 @Produces({ MediaTypes.PATCH_STATUS + RestconfService.XML})
33 public class PATCHXmlBodyWriter implements MessageBodyWriter<PATCHStatusContext> {
34
35     private static final XMLOutputFactory XML_FACTORY;
36
37     static {
38         XML_FACTORY = XMLOutputFactory.newFactory();
39         XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
40     }
41
42     @Override
43     public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
44         return type.equals(PATCHStatusContext.class);
45     }
46
47     @Override
48     public long getSize(PATCHStatusContext patchStatusContext, Class<?> type, Type genericType, Annotation[]
49             annotations, MediaType mediaType) {
50         return -1;
51     }
52
53     @Override
54     public void writeTo(PATCHStatusContext patchStatusContext, Class<?> type, Type genericType, Annotation[]
55             annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
56                 throws IOException, WebApplicationException {
57
58         try {
59             XMLStreamWriter xmlWriter = XML_FACTORY.createXMLStreamWriter(entityStream);
60             writeDocument(xmlWriter, patchStatusContext);
61         } catch (final XMLStreamException e) {
62             throw new IllegalStateException(e);
63         } catch (final FactoryConfigurationError e) {
64             throw new IllegalStateException(e);
65         }
66
67     }
68
69     private static void writeDocument(XMLStreamWriter writer, PATCHStatusContext context) throws XMLStreamException, IOException {
70         writer.writeStartElement("", "yang-patch-status", "urn:ietf:params:xml:ns:yang:ietf-yang-patch");
71         writer.writeStartElement("patch-id");
72         writer.writeCharacters(context.getPatchId());
73         writer.writeEndElement();
74
75         if (context.isOk()) {
76             writer.writeEmptyElement("ok");
77         } else {
78             if (context.getGlobalErrors() != null) {
79                 reportErrors(context.getGlobalErrors(), writer);
80             }
81             writer.writeStartElement("edit-status");
82             for (PATCHStatusEntity patchStatusEntity : context.getEditCollection()) {
83                 writer.writeStartElement("edit");
84                 writer.writeStartElement("edit-id");
85                 writer.writeCharacters(patchStatusEntity.getEditId());
86                 writer.writeEndElement();
87                 if (patchStatusEntity.getEditErrors() != null) {
88                     reportErrors(patchStatusEntity.getEditErrors(), writer);
89                 } else {
90                     if (patchStatusEntity.isOk()) {
91                         writer.writeEmptyElement("ok");
92                     }
93                 }
94                 writer.writeEndElement();
95             }
96             writer.writeEndElement();
97
98         }
99         writer.writeEndElement();
100
101         writer.flush();
102     }
103
104     private static void reportErrors(List<RestconfError> errors, XMLStreamWriter writer) throws IOException, XMLStreamException {
105         writer.writeStartElement("errors");
106
107         for (RestconfError restconfError : errors) {
108             writer.writeStartElement("error-type");
109             writer.writeCharacters(restconfError.getErrorType().getErrorTypeTag());
110             writer.writeEndElement();
111             writer.writeStartElement("error-tag");
112             writer.writeCharacters(restconfError.getErrorTag().getTagValue());
113             writer.writeEndElement();
114             //TODO: fix error-path reporting (separate error-path from error-message)
115 //            writer.writeStartElement("error-path");
116 //            writer.writeCharacters(restconfError.getErrorPath());
117 //            writer.writeEndElement();
118             writer.writeStartElement("error-message");
119             writer.writeCharacters(restconfError.getErrorMessage());
120             writer.writeEndElement();
121         }
122
123         writer.writeEndElement();
124     }
125 }