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   */
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 }