001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.util.byteaccess; 021 022import org.apache.mina.core.buffer.IoBuffer; 023 024/** 025 * Provides restricted, relative, write-only access to the bytes in a 026 * <code>CompositeByteArray</code>. 027 * 028 * Using this interface has the advantage that it can be automatically 029 * determined when a component <code>ByteArray</code> can no longer be written 030 * to, and thus components can be automatically flushed. This makes it easier to 031 * use pooling for underlying <code>ByteArray</code>s. 032 * 033 * By providing an appropriate <code>Expander</code> it is also possible to 034 * automatically add more backing storage as more data is written. 035 *<br> 036 *<br> 037 * TODO: Get flushing working. 038 * 039 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 040 */ 041public class CompositeByteArrayRelativeWriter extends CompositeByteArrayRelativeBase implements IoRelativeWriter { 042 043 /** 044 * An object that knows how to expand a <code>CompositeByteArray</code>. 045 */ 046 public interface Expander { 047 void expand(CompositeByteArray cba, int minSize); 048 } 049 050 /** 051 * No-op expander. The overridden method does nothing. 052 * 053 */ 054 public static class NopExpander implements Expander { 055 public void expand(CompositeByteArray cba, int minSize) { 056 // Do nothing. 057 } 058 } 059 060 /** 061 * Expands the supplied {@link CompositeByteArray} by the number of 062 * bytes provided in the constructor 063 * 064 */ 065 public static class ChunkedExpander implements Expander { 066 067 private final ByteArrayFactory baf; 068 069 private final int newComponentSize; 070 071 public ChunkedExpander(ByteArrayFactory baf, int newComponentSize) { 072 this.baf = baf; 073 this.newComponentSize = newComponentSize; 074 } 075 076 public void expand(CompositeByteArray cba, int minSize) { 077 int remaining = minSize; 078 while (remaining > 0) { 079 ByteArray component = baf.create(newComponentSize); 080 cba.addLast(component); 081 remaining -= newComponentSize; 082 } 083 } 084 085 } 086 087 /** 088 * An object that knows how to flush a <code>ByteArray</code>. 089 */ 090 public interface Flusher { 091 // document free() behaviour 092 void flush(ByteArray ba); 093 } 094 095 /** 096 * The expander to use when the array underflows. 097 */ 098 private final Expander expander; 099 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}