Merge "Bug 2983 - POST operation to list only accepts data for keys"
authorTony Tkacik <ttkacik@cisco.com>
Thu, 7 May 2015 07:55:36 +0000 (07:55 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 7 May 2015 07:55:37 +0000 (07:55 +0000)
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/BufferedWriter.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfMessageToXMLEncoder.java

diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/BufferedWriter.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/BufferedWriter.java
new file mode 100644 (file)
index 0000000..07c11b7
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.nettyutil.handler;
+
+
+import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.io.Writer;
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Custom BufferedWriter optimized for netconf pipeline implemented instead of default BufferedWriter provided by jdk.
+ * <p/>
+ * The line separator instance field in java.io.BufferedWriter is
+ * assigned using AccessController and takes considerable amount of time especially
+ * if lots of BufferedWriters are created in the system.
+ * <p/>
+ * This implementation should only be used if newLine method is not required
+ * such as netconf message to XML encoders.
+ * Methods in this implementation are not synchronized.
+ */
+@NotThreadSafe
+public final class BufferedWriter extends Writer {
+
+    private static final int DEFAULT_CHAR_BUFFER_SIZE = 8192;
+
+    private final Writer writer;
+    private final char buffer[];
+    private final int bufferSize;
+
+    private int nextChar = 0;
+
+    public BufferedWriter(final Writer writer) {
+        this(writer, DEFAULT_CHAR_BUFFER_SIZE);
+    }
+
+    public BufferedWriter(final Writer writer, final int bufferSize) {
+        super(writer);
+        Preconditions.checkArgument(bufferSize > 0, "Buffer size <= 0");
+        this.writer = writer;
+        this.buffer = new char[bufferSize];
+        this.bufferSize = bufferSize;
+    }
+
+    private void flushBuffer() throws IOException {
+        if (nextChar == 0)
+            return;
+        writer.write(buffer, 0, nextChar);
+        nextChar = 0;
+    }
+
+    @Override
+    public void write(final int c) throws IOException {
+        if (nextChar >= bufferSize)
+            flushBuffer();
+        buffer[nextChar++] = (char) c;
+    }
+
+    @Override
+    public void write(final char[] buffer, final int offset, final int length) throws IOException {
+        if ((offset < 0) || (offset > buffer.length) || (length < 0) ||
+                ((offset + length) > buffer.length) || ((offset + length) < 0)) {
+            throw new IndexOutOfBoundsException(String.format("Buffer size: %d, Offset: %d, Length: %d", buffer.length, offset, length));
+        } else if (length == 0) {
+            return;
+        }
+
+        if (length >= bufferSize) {
+            flushBuffer();
+            writer.write(buffer, offset, length);
+            return;
+        }
+
+        int b = offset;
+        final int t = offset + length;
+        while (b < t) {
+            final int d = Math.min(bufferSize - nextChar, t - b);
+            System.arraycopy(buffer, b, this.buffer, nextChar, d);
+            b += d;
+            nextChar += d;
+            if (nextChar >= bufferSize)
+                flushBuffer();
+        }
+    }
+
+    @Override
+    public void write(final String string, final int offset, final int length) throws IOException {
+        int b = offset;
+        final int t = offset + length;
+        while (b < t) {
+            final int d = Math.min(bufferSize - nextChar, t - b);
+            string.getChars(b, b + d, buffer, nextChar);
+            b += d;
+            nextChar += d;
+            if (nextChar >= bufferSize)
+                flushBuffer();
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        flushBuffer();
+        writer.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        try {
+            flushBuffer();
+        } finally {
+            writer.close();
+        }
+    }
+}
index 99251b00d4a74786902eae9b43434a8d14e49915..cf6dbb63b6364e1852070cf8255d54b576c4c02d 100644 (file)
@@ -13,7 +13,6 @@ import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufOutputStream;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.MessageToByteEncoder;
-import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -50,7 +49,10 @@ public class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMess
 
         try (OutputStream os = new ByteBufOutputStream(out)) {
             // Wrap OutputStreamWriter with BufferedWriter as suggested in javadoc for OutputStreamWriter
-            StreamResult result = new StreamResult(new BufferedWriter(new OutputStreamWriter(os)));
+
+            // Using custom BufferedWriter that does not provide newLine method as performance improvement
+            // see javadoc for org.opendaylight.controller.netconf.nettyutil.handler.BufferedWriter
+            StreamResult result = new StreamResult(new org.opendaylight.controller.netconf.nettyutil.handler.BufferedWriter(new OutputStreamWriter(os)));
             DOMSource source = new DOMSource(msg.getDocument());
             ThreadLocalTransformers.getPrettyTransformer().transform(source, result);
         }