11/*
22 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33 *
4- * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
4+ * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
55 *
66 * The contents of this file are subject to the terms of either the GNU
77 * General Public License Version 2 only ("GPL") or the Common Development
9090 *
9191 * @author Anil K. Vijendran
9292 * @author Kin-man Chung
93+ * @author Dongbin Nie
9394 */
9495public class JspWriterImpl extends JspWriter {
96+
97+ private static final int MAX_BUFFER_SIZE = Integer .getInteger (
98+ "org.apache.jasper.runtime.JspWriterImpl.MAX_THREAD_LOCAL_BUFFER_SIZE" ,
99+ 32 * 1024 );
100+
101+ private static final ThreadLocal <CharBufferThreadLocalPool >
102+ charBufferPools = new ThreadLocal <CharBufferThreadLocalPool >();
95103
96104 private Writer out ;
97105 private ServletResponse response ;
98- private char cb [];
99- private int nextChar ;
106+ private CharBuffer buf ;
100107 private boolean flushed = false ;
101108 private boolean closed = false ;
102109 protected boolean implementsByteWriter = true ;
@@ -131,8 +138,7 @@ public JspWriterImpl(ServletResponse response, int sz,
131138 if (sz < 0 )
132139 throw new IllegalArgumentException ("Buffer size <= 0" );
133140 this .response = response ;
134- cb = sz == 0 ? null : new char [sz ];
135- nextChar = 0 ;
141+ allocateCharBuffer ();
136142 // START OF IASRI 4641975/6172992
137143 try {
138144 response .setBufferSize (sz );
@@ -144,11 +150,9 @@ public JspWriterImpl(ServletResponse response, int sz,
144150
145151 void init ( ServletResponse response , int sz , boolean autoFlush ) {
146152 this .response = response ;
147- if ( sz > 0 && ( cb == null || sz > cb .length ) )
148- cb =new char [sz ];
149- nextChar = 0 ;
150153 this .autoFlush =autoFlush ;
151154 this .bufferSize =sz ;
155+ allocateCharBuffer ();
152156 // START OF IASRI 4641975/6172992
153157 try {
154158 response .setBufferSize (sz );
@@ -165,7 +169,7 @@ void recycle() {
165169 closed = false ;
166170 out = null ;
167171 byteOut = null ;
168- nextChar = 0 ;
172+ releaseCharBuffer () ;
169173 response = null ;
170174 }
171175
@@ -179,11 +183,11 @@ protected final void flushBuffer() throws IOException {
179183 return ;
180184 flushed = true ;
181185 ensureOpen ();
182- if (nextChar == 0 )
186+ if (buf . pos == buf . offset )
183187 return ;
184188 initOut ();
185- out .write (cb , 0 , nextChar );
186- nextChar = 0 ;
189+ out .write (buf . buf , buf . offset , buf . pos - buf . offset );
190+ buf . pos = buf . offset ;
187191 }
188192
189193 private void initOut () throws IOException {
@@ -217,15 +221,16 @@ public final void clear() throws IOException {
217221 throw new IOException (
218222 getLocalizeMessage ("jsp.error.attempt_to_clear_flushed_buffer" ));
219223 ensureOpen ();
220- nextChar = 0 ;
224+ if (buf != null )
225+ buf .pos = buf .offset ;
221226 }
222227
223228 public void clearBuffer () throws IOException {
224229 if (bufferSize == 0 )
225230 throw new IllegalStateException (
226231 getLocalizeMessage ("jsp.error.ise_on_clear" ));
227232 ensureOpen ();
228- nextChar = 0 ;
233+ buf . pos = buf . offset ;
229234 }
230235
231236 private final void bufferOverflow () throws IOException {
@@ -273,7 +278,7 @@ public void close() throws IOException {
273278 * @return the number of bytes unused in the buffer
274279 */
275280 public int getRemaining () {
276- return bufferSize - nextChar ;
281+ return buf == null ? 0 : buf . lim - buf . pos ;
277282 }
278283
279284 /** check to make sure that the stream has not been closed */
@@ -347,12 +352,12 @@ public void write(int c) throws IOException {
347352 out .write (c );
348353 }
349354 else {
350- if (nextChar >= bufferSize )
355+ if (getRemaining () == 0 )
351356 if (autoFlush )
352357 flushBuffer ();
353358 else
354359 bufferOverflow ();
355- cb [ nextChar ++] = (char ) c ;
360+ buf . buf [ buf . pos ++] = (char ) c ;
356361 }
357362 }
358363
@@ -412,11 +417,11 @@ public void write(char cbuf[], int off, int len)
412417
413418 int b = off , t = off + len ;
414419 while (b < t ) {
415- int d = min (bufferSize - nextChar , t - b );
416- System .arraycopy (cbuf , b , cb , nextChar , d );
420+ int d = min (getRemaining () , t - b );
421+ System .arraycopy (cbuf , b , buf . buf , buf . pos , d );
417422 b += d ;
418- nextChar += d ;
419- if (nextChar >= bufferSize )
423+ buf . pos += d ;
424+ if (getRemaining () == 0 )
420425 if (autoFlush )
421426 flushBuffer ();
422427 else
@@ -449,11 +454,11 @@ public void write(String s, int off, int len) throws IOException {
449454 }
450455 int b = off , t = off + len ;
451456 while (b < t ) {
452- int d = min (bufferSize - nextChar , t - b );
453- s .getChars (b , b + d , cb , nextChar );
457+ int d = min (getRemaining () , t - b );
458+ s .getChars (b , b + d , buf . buf , buf . pos );
454459 b += d ;
455- nextChar += d ;
456- if (nextChar >= bufferSize )
460+ buf . pos += d ;
461+ if (getRemaining () == 0 )
457462 if (autoFlush )
458463 flushBuffer ();
459464 else
@@ -718,11 +723,80 @@ public void println(Object x) throws IOException {
718723
719724 // START PWC 6512276
720725 public boolean hasData () {
721- if (bufferSize != 0 && nextChar != 0 ) {
726+ if (bufferSize != 0 && buf . pos != buf . offset ) {
722727 return true ;
723728 }
724729
725730 return false ;
726731 }
727732 // END PWC 6512276
733+
734+ private void allocateCharBuffer () {
735+ if (bufferSize == 0 ) return ;
736+
737+ if (bufferSize > MAX_BUFFER_SIZE ) {
738+ buf = new CharBuffer (new char [bufferSize ], 0 , bufferSize );
739+ } else {
740+ buf = getCharBufferThreadLocalPool ().allocate (bufferSize );
741+ }
742+ }
743+
744+ private void releaseCharBuffer () {
745+ if (buf == null ) return ;
746+
747+ if ((buf .lim - buf .offset ) <= MAX_BUFFER_SIZE ) {
748+ getCharBufferThreadLocalPool ().release (buf );
749+ }
750+ buf = null ;
751+ }
752+
753+ private CharBufferThreadLocalPool getCharBufferThreadLocalPool () {
754+ CharBufferThreadLocalPool pool = charBufferPools .get ();
755+ if (pool == null ) {
756+ pool = new CharBufferThreadLocalPool ();
757+ charBufferPools .set (pool );
758+ }
759+ return pool ;
760+ }
761+
762+ private static class CharBuffer {
763+ char [] buf ;
764+ int offset ;
765+ int pos ;
766+ int lim ;
767+
768+ CharBuffer (char [] buffer , int offset , int length ) {
769+ this .buf = buffer ;
770+ this .offset = offset ;
771+ this .pos = offset ;
772+ this .lim = offset + length ;
773+ }
774+ }
775+
776+ private static class CharBufferThreadLocalPool {
777+ private char [] pool ;
778+ private int pos ;
779+
780+ public CharBuffer allocate (int size ) {
781+ if (remaining () < size ) {
782+ pool = new char [MAX_BUFFER_SIZE ];
783+ pos = 0 ;
784+ }
785+
786+ CharBuffer allocated = new CharBuffer (pool , pos , size );
787+ pos += size ;
788+
789+ return allocated ;
790+ }
791+
792+ public void release (CharBuffer buffer ) {
793+ if (buffer .buf == pool && buffer .lim == pos ) {
794+ pos = buffer .offset ;
795+ }
796+ }
797+
798+ public int remaining () {
799+ return pool == null ? 0 : pool .length - pos ;
800+ }
801+ }
728802}
0 commit comments