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 }