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