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, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.hadoop.io;
020
021 import java.io.DataOutputStream;
022 import java.io.OutputStream;
023 import java.nio.ByteBuffer;
024 import java.util.List;
025 import java.util.ArrayList;
026 import java.util.LinkedList;
027
028 public class DataOutputByteBuffer extends DataOutputStream {
029
030 static class Buffer extends OutputStream {
031
032 final byte[] b = new byte[1];
033 final boolean direct;
034 final List<ByteBuffer> active = new ArrayList<ByteBuffer>();
035 final List<ByteBuffer> inactive = new LinkedList<ByteBuffer>();
036 int size;
037 int length;
038 ByteBuffer current;
039
040 Buffer(int size, boolean direct) {
041 this.direct = direct;
042 this.size = size;
043 current = direct
044 ? ByteBuffer.allocateDirect(size)
045 : ByteBuffer.allocate(size);
046 }
047 @Override
048 public void write(int b) {
049 this.b[0] = (byte)(b & 0xFF);
050 write(this.b);
051 }
052 @Override
053 public void write(byte[] b) {
054 write(b, 0, b.length);
055 }
056 @Override
057 public void write(byte[] b, int off, int len) {
058 int rem = current.remaining();
059 while (len > rem) {
060 current.put(b, off, rem);
061 length += rem;
062 current.flip();
063 active.add(current);
064 off += rem;
065 len -= rem;
066 rem = getBuffer(len);
067 }
068 current.put(b, off, len);
069 length += len;
070 }
071 int getBuffer(int newsize) {
072 if (inactive.isEmpty()) {
073 size = Math.max(size << 1, newsize);
074 current = direct
075 ? ByteBuffer.allocateDirect(size)
076 : ByteBuffer.allocate(size);
077 } else {
078 current = inactive.remove(0);
079 }
080 return current.remaining();
081 }
082 ByteBuffer[] getData() {
083 ByteBuffer[] ret = active.toArray(new ByteBuffer[active.size() + 1]);
084 ByteBuffer tmp = current.duplicate();
085 tmp.flip();
086 ret[ret.length - 1] = tmp.slice();
087 return ret;
088 }
089 int getLength() {
090 return length;
091 }
092 void reset() {
093 length = 0;
094 current.rewind();
095 inactive.add(0, current);
096 for (int i = active.size() - 1; i >= 0; --i) {
097 ByteBuffer b = active.remove(i);
098 b.rewind();
099 inactive.add(0, b);
100 }
101 current = inactive.remove(0);
102 }
103 }
104
105 private final Buffer buffers;
106
107 public DataOutputByteBuffer() {
108 this(32);
109 }
110
111 public DataOutputByteBuffer(int size) {
112 this(size, false);
113 }
114
115 public DataOutputByteBuffer(int size, boolean direct) {
116 this(new Buffer(size, direct));
117 }
118
119 private DataOutputByteBuffer(Buffer buffers) {
120 super(buffers);
121 this.buffers = buffers;
122 }
123
124 public ByteBuffer[] getData() {
125 return buffers.getData();
126 }
127
128 public int getLength() {
129 return buffers.getLength();
130 }
131
132 public void reset() {
133 this.written = 0;
134 buffers.reset();
135 }
136
137 }