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