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