Simplify data encoding in AbstractNotificationsData
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / netconf / sal / streams / listeners / AbstractNotificationsData.java
1 /*
2  * Copyright (c) 2016 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.streams.listeners;
9
10 import java.io.ByteArrayOutputStream;
11 import java.io.IOException;
12 import java.nio.charset.StandardCharsets;
13 import java.util.Date;
14 import javax.xml.stream.XMLOutputFactory;
15 import javax.xml.stream.XMLStreamException;
16 import javax.xml.stream.XMLStreamWriter;
17 import javax.xml.transform.OutputKeys;
18 import javax.xml.transform.Transformer;
19 import javax.xml.transform.TransformerException;
20 import javax.xml.transform.dom.DOMResult;
21 import javax.xml.transform.dom.DOMSource;
22 import javax.xml.transform.stream.StreamResult;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
25 import org.opendaylight.restconf.Rfc8040.MonitoringModule;
26 import org.opendaylight.restconf.handlers.SchemaContextHandler;
27 import org.opendaylight.restconf.handlers.TransactionChainHandler;
28 import org.opendaylight.restconf.parser.IdentifierCodec;
29 import org.opendaylight.yangtools.util.xml.UntrustedXML;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
34 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
35 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42
43 /**
44  * Abstract class for processing and preparing data
45  *
46  */
47 abstract class AbstractNotificationsData {
48
49     private static final Logger LOG = LoggerFactory.getLogger(AbstractNotificationsData.class);
50
51     private TransactionChainHandler transactionChainHandler;
52     private SchemaContextHandler schemaHandler;
53     private String localName;
54
55     /**
56      * Transaction chain for delete data in DS on close()
57      *
58      * @param transactionChainHandler
59      *            - creating new write transaction for delete data on close
60      * @param schemaHandler
61      *            - for getting schema to deserialize
62      *            {@link MonitoringModule#PATH_TO_STREAM_WITHOUT_KEY} to
63      *            {@link YangInstanceIdentifier}
64      */
65     public void setCloseVars(final TransactionChainHandler transactionChainHandler,
66             final SchemaContextHandler schemaHandler) {
67         this.transactionChainHandler = transactionChainHandler;
68         this.schemaHandler = schemaHandler;
69     }
70
71     /**
72      * Delete data in DS
73      */
74     protected void deleteDataInDS() throws Exception {
75         final DOMDataWriteTransaction wTx = this.transactionChainHandler.get().newWriteOnlyTransaction();
76         wTx.delete(LogicalDatastoreType.OPERATIONAL, IdentifierCodec
77                 .deserialize(MonitoringModule.PATH_TO_STREAM_WITHOUT_KEY + this.localName, this.schemaHandler.get()));
78         wTx.submit().checkedGet();
79     }
80
81     /**
82      * Set localName of last path element of specific listener
83      *
84      * @param localName
85      *            - local name
86      */
87     protected void setLocalNameOfPath(final String localName) {
88         this.localName = localName;
89     }
90
91     /**
92      * Formats data specified by RFC3339.
93      *
94      * @param d
95      *            Date
96      * @return Data specified by RFC3339.
97      */
98     protected static String toRFC3339(final Date d) {
99         return ListenersConstants.RFC3339_PATTERN.matcher(ListenersConstants.RFC3339.format(d)).replaceAll("$1:$2");
100     }
101
102     /**
103      * Creates {@link Document} document.
104      *
105      * @return {@link Document} document.
106      */
107     protected static Document createDocument() {
108         return UntrustedXML.newDocumentBuilder().newDocument();
109     }
110
111     /**
112      * Write normalized node to {@link DOMResult}
113      *
114      * @param normalized
115      *            - data
116      * @param context
117      *            - actual schema context
118      * @param schemaPath
119      *            - schema path of data
120      * @return {@link DOMResult}
121      */
122     protected DOMResult writeNormalizedNode(final NormalizedNode<?, ?> normalized, final SchemaContext context,
123             final SchemaPath schemaPath) throws IOException, XMLStreamException {
124         final XMLOutputFactory XML_FACTORY = XMLOutputFactory.newFactory();
125         final Document doc = XmlDocumentUtils.getDocument();
126         final DOMResult result = new DOMResult(doc);
127         NormalizedNodeWriter normalizedNodeWriter = null;
128         NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
129         XMLStreamWriter writer = null;
130
131         try {
132             writer = XML_FACTORY.createXMLStreamWriter(result);
133             normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, context, schemaPath);
134             normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter);
135
136             normalizedNodeWriter.write(normalized);
137
138             normalizedNodeWriter.flush();
139         } finally {
140             if (normalizedNodeWriter != null) {
141                 normalizedNodeWriter.close();
142             }
143             if (normalizedNodeStreamWriter != null) {
144                 normalizedNodeStreamWriter.close();
145             }
146             if (writer != null) {
147                 writer.close();
148             }
149         }
150
151         return result;
152     }
153
154     /**
155      * Generating base element of every notification
156      *
157      * @param doc
158      *            - base {@link Document}
159      * @return element of {@link Document}
160      */
161     protected Element basePartDoc(final Document doc) {
162         final Element notificationElement =
163                 doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0", "notification");
164
165         doc.appendChild(notificationElement);
166
167         final Element eventTimeElement = doc.createElement("eventTime");
168         eventTimeElement.setTextContent(toRFC3339(new Date()));
169         notificationElement.appendChild(eventTimeElement);
170
171         return notificationElement;
172     }
173
174     /**
175      * Generating of {@link Document} transforming to string
176      *
177      * @param doc
178      *            - {@link Document} with data
179      * @return - string from {@link Document}
180      */
181     protected String transformDoc(final Document doc) {
182         final ByteArrayOutputStream out = new ByteArrayOutputStream();
183
184         try {
185             final Transformer transformer = ListenersConstants.FACTORY.newTransformer();
186             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
187             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
188             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
189             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
190             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
191             transformer.transform(new DOMSource(doc), new StreamResult(out));
192         } catch (TransformerException e) {
193             // FIXME: this should raise an exception
194             final String msg = "Error during transformation of Document into String";
195             LOG.error(msg, e);
196             return msg;
197         }
198
199         return new String(out.toByteArray(), StandardCharsets.UTF_8);
200     }
201 }