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
23 import org.apache.mina.core.buffer.IoBuffer;
24
25
26 /**
27 * Provides restricted, relative, write-only access to the bytes in a
28 * <code>CompositeByteArray</code>.
29 *
30 * Using this interface has the advantage that it can be automatically
31 * determined when a component <code>ByteArray</code> can no longer be written
32 * to, and thus components can be automatically flushed. This makes it easier to
33 * use pooling for underlying <code>ByteArray</code>s.
34 *
35 * By providing an appropriate <code>Expander</code> it is also possible to
36 * automatically add more backing storage as more data is written.
37 *<br/><br/>
38 * TODO: Get flushing working.
39 *
40 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
41 */
42 public class CompositeByteArrayRelativeWriter extends CompositeByteArrayRelativeBase implements IoRelativeWriter
43 {
44
45 /**
46 * An object that knows how to expand a <code>CompositeByteArray</code>.
47 */
48 public interface Expander
49 {
50 void expand( CompositeByteArray cba, int minSize );
51 }
52
53 /**
54 * No-op expander. The overridden method does nothing.
55 *
56 */
57 public static class NopExpander implements Expander
58 {
59 public void expand( CompositeByteArray cba, int minSize )
60 {
61 // Do nothing.
62 }
63 }
64
65 /**
66 * Expands the supplied {@link CompositeByteArray} by the number of
67 * bytes provided in the constructor
68 *
69 */
70 public static class ChunkedExpander implements Expander
71 {
72
73 private final ByteArrayFactory baf;
74
75 private final int newComponentSize;
76
77
78 public ChunkedExpander( ByteArrayFactory baf, int newComponentSize )
79 {
80 this.baf = baf;
81 this.newComponentSize = newComponentSize;
82 }
83
84
85 public void expand( CompositeByteArray cba, int minSize )
86 {
87 int remaining = minSize;
88 while ( remaining > 0 )
89 {
90 ByteArray component = baf.create( newComponentSize );
91 cba.addLast( component );
92 remaining -= newComponentSize;
93 }
94 }
95
96 }
97
98 /**
99 * An object that knows how to flush a <code>ByteArray</code>.
100 */
101 public interface Flusher
102 {
103 // document free() behaviour
104 void flush( ByteArray ba );
105 }
106
107 /**
108 * The expander to use when the array underflows.
109 */
110 private final Expander expander;
111
112 /**
113 * The flusher to use when flushing component <code>ByteArray</code>s.
114 */
115 private final Flusher flusher;
116
117 /**
118 * Whether or not to automatically flush a component once the cursor moves
119 * past it.
120 */
121 private final boolean autoFlush;
122
123
124 /**
125 *
126 * Creates a new instance of CompositeByteArrayRelativeWriter.
127 *
128 * @param cba
129 * The CompositeByteArray to use to back this class
130 * @param expander
131 * The expander. Will increase the size of the internal ByteArray
132 * @param flusher
133 * Flushed the ByteArray when necessary
134 * @param autoFlush
135 * Should this class automatically flush?
136 */
137 public CompositeByteArrayRelativeWriter( CompositeByteArray cba, Expander expander, Flusher flusher,
138 boolean autoFlush )
139 {
140 super( cba );
141 this.expander = expander;
142 this.flusher = flusher;
143 this.autoFlush = autoFlush;
144 }
145
146
147 private void prepareForAccess( int size )
148 {
149 int underflow = cursor.getIndex() + size - last();
150 if ( underflow > 0 )
151 {
152 expander.expand( cba, underflow );
153 }
154 }
155
156
157 /**
158 * Flush to the current index.
159 */
160 public void flush()
161 {
162 flushTo( cursor.getIndex() );
163 }
164
165
166 /**
167 * Flush to the given index.
168 */
169 public void flushTo( int index )
170 {
171 ByteArray removed = cba.removeTo( index );
172 flusher.flush( removed );
173 }
174
175
176 /**
177 * @inheritDoc
178 */
179 public void skip( int length )
180 {
181 cursor.skip( length );
182 }
183
184
185 @Override
186 protected void cursorPassedFirstComponent()
187 {
188 if ( autoFlush )
189 {
190 flushTo( cba.first() + cba.getFirst().length() );
191 }
192 }
193
194
195 /**
196 * @inheritDoc
197 */
198 public void put( byte b )
199 {
200 prepareForAccess( 1 );
201 cursor.put( b );
202 }
203
204
205 /**
206 * @inheritDoc
207 */
208 public void put( IoBuffer bb )
209 {
210 prepareForAccess( bb.remaining() );
211 cursor.put( bb );
212 }
213
214
215 /**
216 * @inheritDoc
217 */
218 public void putShort( short s )
219 {
220 prepareForAccess( 2 );
221 cursor.putShort( s );
222 }
223
224
225 /**
226 * @inheritDoc
227 */
228 public void putInt( int i )
229 {
230 prepareForAccess( 4 );
231 cursor.putInt( i );
232 }
233
234
235 /**
236 * @inheritDoc
237 */
238 public void putLong( long l )
239 {
240 prepareForAccess( 8 );
241 cursor.putLong( l );
242 }
243
244
245 /**
246 * @inheritDoc
247 */
248 public void putFloat( float f )
249 {
250 prepareForAccess( 4 );
251 cursor.putFloat( f );
252 }
253
254
255 /**
256 * @inheritDoc
257 */
258 public void putDouble( double d )
259 {
260 prepareForAccess( 8 );
261 cursor.putDouble( d );
262 }
263
264
265 /**
266 * @inheritDoc
267 */
268 public void putChar( char c )
269 {
270 prepareForAccess( 2 );
271 cursor.putChar( c );
272 }
273 }