Remove unnecessary casting
[netconf.git] / netconf / netconf-netty-util / src / main / java / org / opendaylight / netconf / nettyutil / handler / BufferedWriter.java
1 /*
2  * Copyright (c) 2015 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.nettyutil.handler;
9
10 import java.io.IOException;
11 import java.io.Writer;
12
13 /**
14  * Custom BufferedWriter optimized for NETCONF pipeline implemented instead of default BufferedWriter provided by JDK..
15  *
16  * <p>
17  * In versions up to and including Java 8, java.io.BufferedWriter initialized its lineSeparator field using
18  * AccessController and takes considerable amount of time especially if lots of BufferedWriters are created in the
19  * system. This has been rectified in <a href="https://bugs.openjdk.org/browse/JDK-8068498">Java 9</a>.
20  *
21  * <p>
22  * Despite that issue having been fixed we retain this implementation because its methods are not synchronized, hence
23  * offer a tad better performance.
24  *
25  * <p>
26  * This implementation should only be used if newLine method is not required such as NETCONF message to XML encoders.
27  */
28 public final class BufferedWriter extends Writer {
29     private static final int DEFAULT_CHAR_BUFFER_SIZE = 8192;
30
31     private final Writer writer;
32     private final char[] buffer;
33     private final int bufferSize;
34
35     private int nextChar = 0;
36
37     public BufferedWriter(final Writer writer) {
38         this(writer, DEFAULT_CHAR_BUFFER_SIZE);
39     }
40
41     public BufferedWriter(final Writer writer, final int bufferSize) {
42         super(writer);
43         if (bufferSize <= 0) {
44             throw new IllegalArgumentException("Buffer size <= 0");
45         }
46         this.writer = writer;
47         this.bufferSize = bufferSize;
48         buffer = new char[bufferSize];
49     }
50
51     private void flushBuffer() throws IOException {
52         if (nextChar == 0) {
53             return;
54         }
55         writer.write(buffer, 0, nextChar);
56         nextChar = 0;
57     }
58
59     @Override
60     public void write(final int character) throws IOException {
61         if (nextChar >= bufferSize) {
62             flushBuffer();
63         }
64         buffer[nextChar++] = (char) character;
65     }
66
67     @Override
68     @SuppressWarnings("checkstyle:hiddenField")
69     public void write(final char[] buffer, final int offset, final int length) throws IOException {
70         if (offset < 0 || offset > buffer.length
71                 || length < 0 || offset + length > buffer.length || offset + length < 0) {
72             throw new IndexOutOfBoundsException(
73                 "Buffer size: %d, Offset: %d, Length: %d".formatted(buffer.length, offset, length));
74         } else if (length == 0) {
75             return;
76         }
77
78         if (length >= bufferSize) {
79             flushBuffer();
80             writer.write(buffer, offset, length);
81             return;
82         }
83
84         int bufferOffset = offset;
85         final int t = offset + length;
86         while (bufferOffset < t) {
87             final int d = Math.min(bufferSize - nextChar, t - bufferOffset);
88             System.arraycopy(buffer, bufferOffset, this.buffer, nextChar, d);
89             bufferOffset += d;
90             nextChar += d;
91             if (nextChar >= bufferSize) {
92                 flushBuffer();
93             }
94         }
95     }
96
97     @Override
98     public void write(final String string, final int offset, final int length) throws IOException {
99         int bufferOffset = offset;
100         final int t = offset + length;
101         while (bufferOffset < t) {
102             final int d = Math.min(bufferSize - nextChar, t - bufferOffset);
103             string.getChars(bufferOffset, bufferOffset + d, buffer, nextChar);
104             bufferOffset += d;
105             nextChar += d;
106             if (nextChar >= bufferSize) {
107                 flushBuffer();
108             }
109         }
110     }
111
112     @Override
113     public void flush() throws IOException {
114         flushBuffer();
115         writer.flush();
116     }
117
118     @Override
119     public void close() throws IOException {
120         try {
121             flushBuffer();
122         } finally {
123             writer.close();
124         }
125     }
126 }