comparison src/com/go/trove/io/SpilloverByteBuffer.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /* ====================================================================
2 * Trove - Copyright (c) 1999-2000 Walt Disney Internet Group
3 * ====================================================================
4 * The Tea Software License, Version 1.1
5 *
6 * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Walt Disney Internet Group (http://opensource.go.com/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact opensource@dig.com.
31 *
32 * 5. Products derived from this software may not be called "Tea",
33 * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34 * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35 * written permission of the Walt Disney Internet Group.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * For more information about Tea, please see http://opensource.go.com/.
51 */
52
53 package com.go.trove.io;
54
55 import java.io.OutputStream;
56 import java.io.IOException;
57 import java.util.List;
58 import java.util.ArrayList;
59
60 /******************************************************************************
61 * A ByteBuffer implementation that initially stores its data in a
62 * DefaultByteBuffer, but after a certain threshold is reached, spills over
63 * into a FileByteBuffer.
64 *
65 * @author Brian S O'Neill
66 * @version
67 * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 00/12/05 <!-- $-->
68 */
69 public class SpilloverByteBuffer implements ByteBuffer {
70 private Group mGroup;
71
72 private ByteBuffer mLocalBuffer;
73 private ByteBuffer mSpillover;
74
75 private List mCaptureBuffers;
76
77 /**
78 * Create a SpilloverByteBuffer against a Group that sets the threshold
79 * and can create a spillover FileByteBuffer. The Group can be shared
80 * among many SpilloverByteBuffers.
81 *
82 * @param group a group that can be shared among many SpilloverByteBuffers
83 */
84 public SpilloverByteBuffer(Group group) {
85 mGroup = group;
86 mLocalBuffer = new DefaultByteBuffer();
87 }
88
89 public long getBaseByteCount() throws IOException {
90 if (mSpillover == null) {
91 return mLocalBuffer.getBaseByteCount();
92 }
93 else {
94 return mSpillover.getBaseByteCount();
95 }
96 }
97
98 public long getByteCount() throws IOException {
99 if (mSpillover == null) {
100 return mLocalBuffer.getByteCount();
101 }
102 else {
103 return mSpillover.getByteCount();
104 }
105 }
106
107 public void writeTo(OutputStream out) throws IOException {
108 if (mSpillover == null) {
109 mLocalBuffer.writeTo(out);
110 }
111 else {
112 mSpillover.writeTo(out);
113 }
114 }
115
116 public void append(byte b) throws IOException {
117 List captureBuffers;
118 if ((captureBuffers = mCaptureBuffers) != null) {
119 int size = captureBuffers.size();
120 for (int i=0; i<size; i++) {
121 ((ByteBuffer)captureBuffers.get(i)).append(b);
122 }
123 }
124
125 if (mSpillover == null) {
126 if (mGroup.adjustLevel(1)) {
127 mLocalBuffer.append(b);
128 return;
129 }
130 spillover();
131 }
132
133 mSpillover.append(b);
134 }
135
136 public void append(byte[] bytes) throws IOException {
137 append(bytes, 0, bytes.length);
138 }
139
140 public void append(byte[] bytes, int offset, int length)
141 throws IOException
142 {
143 List captureBuffers;
144 if ((captureBuffers = mCaptureBuffers) != null) {
145 int size = captureBuffers.size();
146 for (int i=0; i<size; i++) {
147 ((ByteBuffer)captureBuffers.get(i)).append
148 (bytes, offset, length);
149 }
150 }
151
152 if (mSpillover == null) {
153 if (mGroup.adjustLevel(length)) {
154 mLocalBuffer.append(bytes, offset, length);
155 return;
156 }
157 spillover();
158 }
159
160 mSpillover.append(bytes, offset, length);
161 }
162
163 public void appendSurrogate(ByteData s) throws IOException {
164 if (s == null) {
165 return;
166 }
167
168 List captureBuffers;
169 if ((captureBuffers = mCaptureBuffers) != null) {
170 int size = captureBuffers.size();
171 for (int i=0; i<size; i++) {
172 ((ByteBuffer)captureBuffers.get(i)).appendSurrogate(s);
173 }
174 }
175
176 if (mSpillover == null) {
177 mLocalBuffer.appendSurrogate(s);
178 }
179 else {
180 mSpillover.appendSurrogate(s);
181 }
182 }
183
184 public void addCaptureBuffer(ByteBuffer buffer) {
185 List captureBuffers;
186 if ((captureBuffers = mCaptureBuffers) == null) {
187 captureBuffers = mCaptureBuffers = new ArrayList();
188 }
189 captureBuffers.add(buffer);
190 }
191
192 public void removeCaptureBuffer(ByteBuffer buffer) {
193 List captureBuffers;
194 if ((captureBuffers = mCaptureBuffers) != null) {
195 captureBuffers.remove(buffer);
196 }
197 }
198
199 public void reset() throws IOException {
200 mLocalBuffer.reset();
201 if (mSpillover != null) {
202 mSpillover.reset();
203 }
204
205 List captureBuffers;
206 if ((captureBuffers = mCaptureBuffers) != null) {
207 int size = captureBuffers.size();
208 for (int i=0; i<size; i++) {
209 ((ByteData)captureBuffers.get(i)).reset();
210 }
211 }
212 }
213
214 protected void finalize() throws IOException {
215 if (mLocalBuffer != null) {
216 long count = mLocalBuffer.getBaseByteCount();
217 mLocalBuffer = null;
218 mGroup.adjustLevel(-count);
219 }
220 }
221
222 private void spillover() throws IOException {
223 mSpillover = mGroup.createFileByteBuffer();
224 // TODO: This is bad! By writing out the contents of the existing
225 // buffer early, surrogates are evaluated too soon!
226 mLocalBuffer.writeTo(new ByteBufferOutputStream(mSpillover));
227
228 long count = mLocalBuffer.getBaseByteCount();
229 mLocalBuffer = null;
230 mGroup.adjustLevel(-count);
231 }
232
233 public static abstract class Group {
234 private final long mThreshold;
235 private long mLevel;
236
237 public Group(long threshold) {
238 mThreshold = threshold;
239 }
240
241 public final long getThreshold() {
242 return mThreshold;
243 }
244
245 public final synchronized long getCurrentLevel() {
246 return mLevel;
247 }
248
249 public abstract FileByteBuffer createFileByteBuffer()
250 throws IOException;
251
252 synchronized boolean adjustLevel(long delta) {
253 long newLevel;
254 if ((newLevel = mLevel + delta) > mThreshold) {
255 return false;
256 }
257 else {
258 if (newLevel < 0) {
259 newLevel = 0;
260 }
261 mLevel = newLevel;
262 return true;
263 }
264 }
265 }
266 }