001/* 002 * Copyright 2013 Chris Pheby 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.jadira.lang.io.buffered; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.nio.ByteBuffer; 021import java.nio.ByteOrder; 022 023/** 024 * A BufferedInputStream where the buffer is provided by a NIO DirectByteBuffer. Use this class as an alternative to {@link java.io.BufferedInputStream} 025 */ 026public class DirectBytesBufferedInputStream extends AbstractBufferedInputStream { 027 028 private ByteBuffer buf; 029 030 /** 031 * Create a new instance with the default buffer size 032 * @param in InputStream to be wrapped 033 * @see java.io.BufferedInputStream#BufferedInputStream(InputStream) 034 */ 035 public DirectBytesBufferedInputStream(InputStream in) { 036 this(in, DEFAULT_BUFFER_SIZE); 037 } 038 039 /** 040 * Creates a new instance with the given buffer size in bytes. 041 * @param in InputStream to be wrapped 042 * @param size The size of the buffer in bytes 043 * @see java.io.BufferedInputStream#BufferedInputStream(InputStream, int) 044 */ 045 public DirectBytesBufferedInputStream(InputStream in, int size) { 046 super(in, size); 047 buf = ByteBuffer.allocateDirect(size); 048 } 049 050 /** 051 * Creates a new instance with the given buffer size in bytes. 052 * @param in InputStream to be wrapped 053 * @param size The size of the buffer in bytes 054 * @param useNativeByteOrder If true, native byte ordering will be used 055 * @see java.io.BufferedInputStream#BufferedInputStream(InputStream, int) 056 */ 057 public DirectBytesBufferedInputStream(InputStream in, int size, boolean useNativeByteOrder) { 058 this(in, size); 059 buf.order(ByteOrder.nativeOrder()); 060 } 061 062 /** 063 * Creates a new instance with the given buffer size in bytes. 064 * @param in InputStream to be wrapped 065 * @param size The size of the buffer in bytes 066 * @param byteOrder Explicitly configure the byte order to be used. 067 * @see java.io.BufferedInputStream#BufferedInputStream(InputStream, int) 068 */ 069 public DirectBytesBufferedInputStream(InputStream in, int size, ByteOrder byteOrder) { 070 this(in, size); 071 buf.order(byteOrder); 072 } 073 074 @Override 075 protected void assertBufferOpen() throws IOException { 076 if (buf == null) { 077 throw new IOException("Buffer was closed"); 078 } 079 } 080 081 @Override 082 protected void compact(int markPos, int size) { 083 buf.position(markPos); 084 buf.compact(); 085 } 086 087 @Override 088 protected byte[] toArray() { 089 return buf.array(); 090 } 091 092 @Override 093 protected void resizeBuffer(int position, int newSize) throws IOException { 094 095 if (newSize > getMarkLimit()) { 096 newSize = getMarkLimit(); 097 } 098 099 ByteBuffer nbuf = ByteBuffer.allocateDirect(newSize); 100 101 buf.rewind(); 102 nbuf.put(buf); 103 nbuf.position(position); 104 105 if (buf == null) { 106 throw new IOException("Stream closed"); 107 } 108 109 doClean(buf); 110 buf = nbuf; 111 } 112 113 @Override 114 protected int limit() { 115 return buf.limit(); 116 } 117 118 @Override 119 protected int getInt(int position) throws IOException { 120 assertBufferOpen(); 121 return buf.getInt(position); 122 } 123 124 @Override 125 protected void get(byte[] b, int pos, int cnt) { 126 buf.get(b, pos, cnt); 127 } 128 129 @Override 130 protected void clean() { 131 132 if (buf == null) { 133 return; 134 } 135 136 doClean(buf); 137 138 buf = null; 139 } 140 141 @SuppressWarnings("restriction") 142 private void doClean(ByteBuffer buf) { 143 144 if (buf == null) { 145 return; 146 } 147 148 sun.misc.Cleaner cleaner = ((sun.nio.ch.DirectBuffer) buf).cleaner(); 149 150 if (cleaner != null) { 151 cleaner.clean(); 152 } 153 } 154}