1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.util.byteaccess;
21
22 import org.apache.mina.core.buffer.IoBuffer;
23
24 /**
25 * Provides restricted, relative, write-only access to the bytes in a
26 * <code>CompositeByteArray</code>.
27 *
28 * Using this interface has the advantage that it can be automatically
29 * determined when a component <code>ByteArray</code> can no longer be written
30 * to, and thus components can be automatically flushed. This makes it easier to
31 * use pooling for underlying <code>ByteArray</code>s.
32 *
33 * By providing an appropriate <code>Expander</code> it is also possible to
34 * automatically add more backing storage as more data is written.
35 *<br/><br/>
36 * TODO: Get flushing working.
37 *
38 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
39 */
40 public class CompositeByteArrayRelativeWriter extends CompositeByteArrayRelativeBase implements IoRelativeWriter {
41
42 /**
43 * An object that knows how to expand a <code>CompositeByteArray</code>.
44 */
45 public interface Expander {
46 void expand(CompositeByteArray cba, int minSize);
47 }
48
49 /**
50 * No-op expander. The overridden method does nothing.
51 *
52 */
53 public static class NopExpander implements Expander {
54 public void expand(CompositeByteArray cba, int minSize) {
55 // Do nothing.
56 }
57 }
58
59 /**
60 * Expands the supplied {@link CompositeByteArray} by the number of
61 * bytes provided in the constructor
62 *
63 */
64 public static class ChunkedExpander implements Expander {
65
66 private final ByteArrayFactory baf;
67
68 private final int newComponentSize;
69
70 public ChunkedExpander(ByteArrayFactory baf, int newComponentSize) {
71 this.baf = baf;
72 this.newComponentSize = newComponentSize;
73 }
74
75 public void expand(CompositeByteArray cba, int minSize) {
76 int remaining = minSize;
77 while (remaining > 0) {
78 ByteArray component = baf.create(newComponentSize);
79 cba.addLast(component);
80 remaining -= newComponentSize;
81 }
82 }
83
84 }
85
86 /**
87 * An object that knows how to flush a <code>ByteArray</code>.
88 */
89 public interface Flusher {
90 // document free() behaviour
91 void flush(ByteArray ba);
92 }
93
94 /**
95 * The expander to use when the array underflows.
96 */
97 private final Expander expander;
98
99 /**
100 * The flusher to use when flushing component <code>ByteArray</code>s.
101 */
102 private final Flusher flusher;
103
104 /**
105 * Whether or not to automatically flush a component once the cursor moves
106 * past it.
107 */
108 private final boolean autoFlush;
109
110 /**
111 *
112 * Creates a new instance of CompositeByteArrayRelativeWriter.
113 *
114 * @param cba
115 * The CompositeByteArray to use to back this class
116 * @param expander
117 * The expander. Will increase the size of the internal ByteArray
118 * @param flusher
119 * Flushed the ByteArray when necessary
120 * @param autoFlush
121 * Should this class automatically flush?
122 */
123 public CompositeByteArrayRelativeWriter(CompositeByteArray cba, Expander expander, Flusher flusher,
124 boolean autoFlush) {
125 super(cba);
126 this.expander = expander;
127 this.flusher = flusher;
128 this.autoFlush = autoFlush;
129 }
130
131 private void prepareForAccess(int size) {
132 int underflow = cursor.getIndex() + size - last();
133 if (underflow > 0) {
134 expander.expand(cba, underflow);
135 }
136 }
137
138 /**
139 * Flush to the current index.
140 */
141 public void flush() {
142 flushTo(cursor.getIndex());
143 }
144
145 /**
146 * Flush to the given index.
147 */
148 public void flushTo(int index) {
149 ByteArray removed = cba.removeTo(index);
150 flusher.flush(removed);
151 }
152
153 /**
154 * @inheritDoc
155 */
156 public void skip(int length) {
157 cursor.skip(length);
158 }
159
160 @Override
161 protected void cursorPassedFirstComponent() {
162 if (autoFlush) {
163 flushTo(cba.first() + cba.getFirst().length());
164 }
165 }
166
167 /**
168 * @inheritDoc
169 */
170 public void put(byte b) {
171 prepareForAccess(1);
172 cursor.put(b);
173 }
174
175 /**
176 * @inheritDoc
177 */
178 public void put(IoBuffer bb) {
179 prepareForAccess(bb.remaining());
180 cursor.put(bb);
181 }
182
183 /**
184 * @inheritDoc
185 */
186 public void putShort(short s) {
187 prepareForAccess(2);
188 cursor.putShort(s);
189 }
190
191 /**
192 * @inheritDoc
193 */
194 public void putInt(int i) {
195 prepareForAccess(4);
196 cursor.putInt(i);
197 }
198
199 /**
200 * @inheritDoc
201 */
202 public void putLong(long l) {
203 prepareForAccess(8);
204 cursor.putLong(l);
205 }
206
207 /**
208 * @inheritDoc
209 */
210 public void putFloat(float f) {
211 prepareForAccess(4);
212 cursor.putFloat(f);
213 }
214
215 /**
216 * @inheritDoc
217 */
218 public void putDouble(double d) {
219 prepareForAccess(8);
220 cursor.putDouble(d);
221 }
222
223 /**
224 * @inheritDoc
225 */
226 public void putChar(char c) {
227 prepareForAccess(2);
228 cursor.putChar(c);
229 }
230 }