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