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.OutputStream;
019import java.nio.ByteBuffer;
020import java.nio.ByteOrder;
021
022/**
023 * A BufferedOutputStream where the buffer is provided by a NIO DirectByteBuffer. Use this class as an alternative to {@link java.io.BufferedOutputStream}
024 */
025public class DirectBytesBufferedOutputStream extends AbstractBufferedOutputStream {
026
027    private ByteBuffer buf;
028
029    /**
030     * Creates a new instance with the default buffer size
031     * @param out OutputStream to be decorated
032     * @see java.io.BufferedOutputStream#BufferedOutputStream(OutputStream)
033     */
034    public DirectBytesBufferedOutputStream(OutputStream out) {
035        this(out, DEFAULT_BUFFER_SIZE);
036    }
037
038    /**
039     * Creates a new instance with the given buffer size in bytes.
040     * @param out OutputStream to be decorated
041     * @param size The size of the buffer in bytes
042     * @see java.io.BufferedOutputStream#BufferedOutputStream(OutputStream, int)
043     */
044    public DirectBytesBufferedOutputStream(OutputStream out, int size) {
045        super(out);
046        if (size <= 0) {
047            throw new IllegalArgumentException("Buffer size may not be less than or equal to zero");
048        }
049        buf = ByteBuffer.allocateDirect(size);
050    }
051
052    /**
053     * Creates a new instance with the given buffer size in bytes.
054     * @param out OutputStream to be decorated
055     * @param size The size of the buffer in bytes
056     * @param useNativeByteOrder If true, native byte ordering will be used
057     * @see java.io.BufferedOutputStream#BufferedOutputStream(OutputStream, int)
058     */
059    public DirectBytesBufferedOutputStream(OutputStream out, int size, boolean useNativeByteOrder) {
060        this(out, size);
061        buf.order(ByteOrder.nativeOrder());
062    }
063
064    /**
065     * Creates a new instance with the given buffer size in bytes.
066     * @param out OutputStream to be decorated
067     * @param size The size of the buffer in bytes
068     * @param byteOrder Indicates the byte order to be used.
069     * @see java.io.BufferedOutputStream#BufferedOutputStream(OutputStream, int)
070     */
071    public DirectBytesBufferedOutputStream(OutputStream out, int size, ByteOrder byteOrder) {
072        this(out, size);
073        buf.order(byteOrder);
074    }
075
076    @Override
077    protected byte[] bytes() {
078        return buf.array();
079    }
080
081    @Override
082    protected void put(byte b) {
083        put(b);
084    }
085
086    @Override
087    protected void put(int count, byte[] b, int off, int len) {
088        if (off == 0) {
089            buf.put(b, count, len);
090        } else {
091            byte[] bc = new byte[len];
092            System.arraycopy(b, off, bc, 0, len);
093            buf.put(bc, count, len);
094        }
095    }
096
097    @Override
098    protected int limit() {
099        return buf.limit();
100    }
101
102    @SuppressWarnings("restriction")
103    @Override
104    protected void clean() {
105
106        if (buf == null) {
107            return;
108        }
109
110        sun.misc.Cleaner cleaner = ((sun.nio.ch.DirectBuffer) buf).cleaner();
111
112        if (cleaner != null) {
113            cleaner.clean();
114        }
115    }
116}