View Javadoc

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