001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Sam
047: */
048:
049: package com.caucho.portal.generic;
050:
051: import java.io.IOException;
052: import java.io.OutputStream;
053: import java.io.Writer;
054: import java.util.ArrayList;
055: import java.util.logging.Level;
056: import java.util.logging.Logger;
057:
058: public class BufferFactoryImpl implements BufferFactory {
059: static protected final Logger log = Logger
060: .getLogger(BufferFactoryImpl.class.getName());
061:
062: private static int _bufferCount = 10;
063:
064: private int _bufferSize = 8192;
065: private int _poolSize = 32;
066:
067: FreeList<CharBufferImpl> _charBufferFreeList = new FreeList<CharBufferImpl>(
068: _poolSize);
069:
070: FreeList<ByteBufferImpl> _byteBufferFreeList = new FreeList<ByteBufferImpl>(
071: _poolSize);
072:
073: public void setBufferSize(int bufferSize) {
074: synchronized (_byteBufferFreeList) {
075: synchronized (_charBufferFreeList) {
076: _byteBufferFreeList.clear();
077: _charBufferFreeList.clear();
078: _bufferSize = bufferSize;
079: }
080: }
081: }
082:
083: public void setPoolSize(int poolSize) {
084: synchronized (_byteBufferFreeList) {
085: synchronized (_charBufferFreeList) {
086: _poolSize = poolSize;
087: _byteBufferFreeList.ensureCapacity(poolSize);
088: _charBufferFreeList.ensureCapacity(poolSize);
089: }
090: }
091: }
092:
093: public int getDefaultBufferSize() {
094: return _bufferSize;
095: }
096:
097: public PortletCharBuffer allocateCharBuffer(int capacity) {
098: CharBufferImpl b = null;
099:
100: if (capacity == Integer.MAX_VALUE)
101: capacity = _bufferSize;
102: else if (capacity < _bufferSize)
103: capacity = _bufferSize;
104:
105: if (capacity == _bufferSize)
106: b = _charBufferFreeList.allocate();
107:
108: if (b == null) {
109: b = new CharBufferImpl(capacity);
110:
111: if (log.isLoggable(Level.FINEST))
112: b.log("allocated new with capacity " + capacity);
113: } else {
114: if (log.isLoggable(Level.FINEST))
115: b.log("allocated reused with capacity "
116: + b.getCapacity());
117: }
118:
119: return b;
120: }
121:
122: public PortletByteBuffer allocateByteBuffer(int capacity) {
123: ByteBufferImpl b = null;
124:
125: if (capacity == Integer.MAX_VALUE)
126: capacity = _bufferSize;
127: else if (capacity <= _bufferSize)
128: capacity = _bufferSize;
129:
130: b = _byteBufferFreeList.allocate();
131:
132: if (b == null) {
133: b = new ByteBufferImpl(capacity);
134:
135: if (log.isLoggable(Level.FINEST))
136: b.log("allocated new with capacity " + capacity);
137: } else {
138: if (log.isLoggable(Level.FINEST))
139: b.log("allocated reused with capacity "
140: + b.getCapacity());
141: }
142:
143: return b;
144: }
145:
146: private class CharBufferImpl implements PortletCharBuffer {
147: private String _bufferId;
148:
149: private int _bufferSize;
150: private char[] _buf;
151: private int _bufferPos = 0;
152:
153: public CharBufferImpl(int size) {
154: int id = _bufferCount++;
155: _bufferId = Integer.toString(id, Character.MAX_RADIX);
156:
157: _bufferSize = size;
158: _buf = new char[size];
159: }
160:
161: void log(String message) {
162: if (log.isLoggable(Level.FINEST)) {
163: message = new StringBuffer(256).append("char buffer ")
164: .append(_bufferId).append(' ').append(message)
165: .toString();
166:
167: log.log(Level.FINEST, message);
168: }
169: }
170:
171: public boolean print(char buf[], int off, int len) {
172: if (len > _bufferSize - _bufferPos)
173: return overrun();
174: else {
175: System.arraycopy(buf, off, _buf, _bufferPos, len);
176: _bufferPos += len;
177:
178: return true;
179: }
180: }
181:
182: public boolean print(String str, int off, int len) {
183: if (len > _bufferSize - _bufferPos)
184: return overrun();
185: else {
186: str.getChars(off, off + len, _buf, _bufferPos);
187: _bufferPos += len;
188:
189: return true;
190: }
191: }
192:
193: public boolean print(int c) {
194: if (_bufferPos == _bufferSize)
195: return overrun();
196: else {
197: _buf[_bufferPos++] = (char) c;
198:
199: return true;
200: }
201: }
202:
203: private boolean overrun() {
204: log("overrun");
205: return false;
206: }
207:
208: public void flush(Writer out) throws IOException {
209: if (_bufferPos != 0) {
210: log("flush");
211:
212: out.write(_buf, 0, _bufferPos);
213: _bufferPos = 0;
214: }
215: }
216:
217: public int size() {
218: return _bufferPos;
219: }
220:
221: public int getCapacity() {
222: return _bufferSize;
223: }
224:
225: public void reset() {
226: log("reset");
227:
228: _bufferPos = 0;
229: }
230:
231: public void finish() {
232: _bufferPos = 0;
233:
234: log("finish");
235:
236: if (_bufferSize <= BufferFactoryImpl.this ._bufferSize) {
237: if (!_charBufferFreeList.free(this ))
238: _buf = null;
239: } else
240: _buf = null;
241: }
242: }
243:
244: private class ByteBufferImpl implements PortletByteBuffer {
245: private String _bufferId;
246:
247: private int _bufferSize;
248: private byte[] _buf;
249: private int _bufferPos = 0;
250:
251: public ByteBufferImpl(int size) {
252: int id = _bufferCount++;
253: _bufferId = Integer.toString(id, Character.MAX_RADIX);
254:
255: _bufferSize = size;
256: _buf = new byte[size];
257: }
258:
259: void log(String message) {
260: if (log.isLoggable(Level.FINEST)) {
261: message = new StringBuffer(256).append("byte buffer ")
262: .append(_bufferId).append(' ').append(message)
263: .toString();
264:
265: log.log(Level.FINEST, message);
266: }
267: }
268:
269: public boolean write(byte[] buf, int off, int len) {
270: if (len > _bufferSize - _bufferPos)
271: return overrun();
272: else {
273: System.arraycopy(buf, off, _buf, _bufferPos, len);
274: _bufferPos += len;
275:
276: return true;
277: }
278: }
279:
280: /**
281: * @return false if the buffer is full and the byte could not be written
282: */
283: public boolean write(int b) {
284: if (_bufferPos == _bufferSize)
285: return overrun();
286: else {
287: _buf[_bufferPos++] = (byte) b;
288:
289: return true;
290: }
291: }
292:
293: public int size() {
294: return _bufferPos;
295: }
296:
297: public int getCapacity() {
298: return _bufferSize;
299: }
300:
301: private boolean overrun() {
302: log("overrun");
303: return false;
304: }
305:
306: public void flush(OutputStream out) throws IOException {
307: if (_bufferPos != 0) {
308: log("flush");
309: out.write(_buf, 0, _bufferPos);
310: _bufferPos = 0;
311: }
312: }
313:
314: public void reset() {
315: log("reset");
316: _bufferPos = 0;
317: }
318:
319: public void finish() {
320: _bufferPos = 0;
321: log("finish");
322:
323: if (_bufferSize <= BufferFactoryImpl.this ._bufferSize) {
324: if (!_byteBufferFreeList.free(this ))
325: _buf = null;
326: } else
327: _buf = null;
328: }
329: }
330:
331: private class FreeList<E> {
332: private int _freeListSize;
333: private ArrayList<E> _freeList;
334:
335: private long _lastAllocateFail;
336:
337: public FreeList(int initialCapacity) {
338: _freeListSize = initialCapacity;
339: _freeList = new ArrayList<E>(_freeListSize);
340: }
341:
342: public E allocate() {
343: synchronized (_freeList) {
344: int size = _freeList.size();
345:
346: if (size > 0)
347: return _freeList.remove(--size);
348: }
349:
350: return null;
351: }
352:
353: public boolean free(E obj) {
354: synchronized (_freeList) {
355: int size = _freeList.size();
356:
357: if (size < _freeListSize) {
358: _freeList.add(obj);
359: return true;
360: } else {
361: if (log.isLoggable(Level.CONFIG))
362: log
363: .config("buffer pool overrun, consider increasing buffer-factory pool-size");
364: return false;
365: }
366: }
367: }
368:
369: public void clear() {
370: synchronized (_freeList) {
371: _freeList.clear();
372: }
373: }
374:
375: public void ensureCapacity(int capacity) {
376: synchronized (_freeList) {
377: _freeList.ensureCapacity(capacity);
378: }
379: }
380: }
381: }
|