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