BUG-1281: optimize ListenerAdapter 81/8581/3
authorRobert Varga <rovarga@cisco.com>
Wed, 2 Jul 2014 19:28:46 +0000 (21:28 +0200)
committerTony Tkacik <ttkacik@cisco.com>
Thu, 3 Jul 2014 11:52:03 +0000 (11:52 +0000)
TransformerFactory should be reused, so that's what we're doing here.
Here we do not cache the transformer, as we are called from datastore
thread, which has essentially no business in this. Same goes for
DocumentBuilderFactory.

Also, the transformation to RFC3339 timestamp was compiling the same
regex over and over, so compile it once and reuse it.

Change-Id: Ia66f42fa123bbb4f86b396520757d9bc28f7b9d2
Signed-off-by: Robert Varga <rovarga@cisco.com>
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java

index e1c163bc48ad14bf3a7cb59757320d5bc5ab4d65..925a09337ca3ee1e8fba707020e3c7a19b8e03f6 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.sal.streams.listeners;
 
+import com.google.common.base.Charsets;
 import com.google.common.base.Preconditions;
 import com.google.common.eventbus.AsyncEventBus;
 import com.google.common.eventbus.EventBus;
@@ -28,6 +29,7 @@ import java.util.Map.Entry;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.Executors;
+import java.util.regex.Pattern;
 
 import javax.activation.UnsupportedDataTypeException;
 import javax.xml.parsers.DocumentBuilder;
@@ -64,8 +66,11 @@ import org.w3c.dom.Node;
  */
 public class ListenerAdapter implements DataChangeListener {
 
-    private static final Logger logger = LoggerFactory
-            .getLogger(ListenerAdapter.class);
+    private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class);
+    private static final DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance();
+    private static final TransformerFactory FACTORY = TransformerFactory.newInstance();
+    private static final Pattern RFC3339_PATTERN = Pattern.compile("(\\d\\d)(\\d\\d)$");
+
     private final XmlMapper xmlMapper = new XmlMapper();
     private final SimpleDateFormat rfc3339 = new SimpleDateFormat(
             "yyyy-MM-dd'T'hh:mm:ssZ");
@@ -77,6 +82,7 @@ public class ListenerAdapter implements DataChangeListener {
     private final EventBus eventBus;
     private final EventBusChangeRecorder eventBusChangeRecorder;
 
+
     /**
      * Creates new {@link ListenerAdapter} listener specified by path and stream
      * name.
@@ -131,12 +137,12 @@ public class ListenerAdapter implements DataChangeListener {
             } else if (event.getType() == EventType.NOTIFY) {
                 for (Channel subscriber : subscribers) {
                     if (subscriber.isActive()) {
-                        logger.debug("Data are sent to subscriber {}:",
+                        LOG.debug("Data are sent to subscriber {}:",
                                 subscriber.remoteAddress());
                         subscriber.writeAndFlush(new TextWebSocketFrame(event
                                 .getData()));
                     } else {
-                        logger.debug(
+                        LOG.debug(
                                 "Subscriber {} is removed - channel is not active yet.",
                                 subscriber.remoteAddress());
                         subscribers.remove(subscriber);
@@ -248,22 +254,19 @@ public class ListenerAdapter implements DataChangeListener {
 
         try {
             ByteArrayOutputStream out = new ByteArrayOutputStream();
-            TransformerFactory tf = TransformerFactory.newInstance();
-            Transformer transformer = tf.newTransformer();
-            transformer
-            .setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+            Transformer transformer = FACTORY.newTransformer();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-            transformer.setOutputProperty(
-                    "{http://xml.apache.org/xslt}indent-amount", "4");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
             transformer.transform(new DOMSource(doc), new StreamResult(
-                    new OutputStreamWriter(out, "UTF-8")));
+                    new OutputStreamWriter(out, Charsets.UTF_8)));
             byte[] charData = out.toByteArray();
             return new String(charData, "UTF-8");
         } catch (TransformerException | UnsupportedEncodingException e) {
             String msg = "Error during transformation of Document into String";
-            logger.error(msg, e);
+            LOG.error(msg, e);
             return msg;
         }
     }
@@ -276,7 +279,7 @@ public class ListenerAdapter implements DataChangeListener {
      * @return Data specified by RFC3339.
      */
     private String toRFC3339(final Date d) {
-        return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
+        return RFC3339_PATTERN.matcher(rfc3339.format(d)).replaceAll("$1:$2");
     }
 
     /**
@@ -285,15 +288,13 @@ public class ListenerAdapter implements DataChangeListener {
      * @return {@link Document} document.
      */
     private Document createDocument() {
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        Document doc = null;
+        final DocumentBuilder bob;
         try {
-            DocumentBuilder bob = dbf.newDocumentBuilder();
-            doc = bob.newDocument();
+            bob = DBF.newDocumentBuilder();
         } catch (ParserConfigurationException e) {
             return null;
         }
-        return doc;
+        return bob.newDocument();
     }
 
     /**
@@ -444,7 +445,7 @@ public class ListenerAdapter implements DataChangeListener {
         DataNodeContainer schemaNode = ControllerContext.getInstance()
                 .getDataNodeContainerFor(path);
         if (schemaNode == null) {
-            logger.info(
+            LOG.info(
                     "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.",
                     path);
             return null;
@@ -453,7 +454,7 @@ public class ListenerAdapter implements DataChangeListener {
             Document xml = xmlMapper.write(data, schemaNode);
             return xml.getFirstChild();
         } catch (UnsupportedDataTypeException e) {
-            logger.error(
+            LOG.error(
                     "Error occured during translation of notification to XML.",
                     e);
             return null;
@@ -474,6 +475,8 @@ public class ListenerAdapter implements DataChangeListener {
         Map<String, String> prefixes = new HashMap<>();
         InstanceIdentifier instanceIdentifier = path;
         StringBuilder textContent = new StringBuilder();
+
+        // FIXME: BUG-1281: this is duplicated code from yangtools (BUG-1275)
         for (PathArgument pathArgument : instanceIdentifier.getPathArguments()) {
             textContent.append("/");
             writeIdentifierWithNamespacePrefix(element, textContent,
@@ -613,7 +616,7 @@ public class ListenerAdapter implements DataChangeListener {
      */
     public void addSubscriber(final Channel subscriber) {
         if (!subscriber.isActive()) {
-            logger.debug("Channel is not active between websocket server and subscriber {}"
+            LOG.debug("Channel is not active between websocket server and subscriber {}"
                     + subscriber.remoteAddress());
         }
         Event event = new Event(EventType.REGISTER);
@@ -628,7 +631,7 @@ public class ListenerAdapter implements DataChangeListener {
      * @param subscriber
      */
     public void removeSubscriber(final Channel subscriber) {
-        logger.debug("Subscriber {} is removed.", subscriber.remoteAddress());
+        LOG.debug("Subscriber {} is removed.", subscriber.remoteAddress());
         Event event = new Event(EventType.DEREGISTER);
         event.setSubscriber(subscriber);
         eventBus.post(event);