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