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.FilterOutputStream; 019import java.io.IOException; 020import java.io.OutputStream; 021 022/** 023 * Provides the basic structure for implementing BufferedOutputStreams. Subclasses typically differ in terms of how they provide the buffer. 024 * Some of the functionality needs to be effectively reproduced from BufferedOutputStream - such methods reference the equivalents in that class. 025 */ 026public abstract class AbstractBufferedOutputStream extends FilterOutputStream { 027 028 /** The default buffer size in bytes */ 029 public static int DEFAULT_BUFFER_SIZE = 8192; 030 031 private int count; 032 033 /** 034 * A BufferedOutputStream where the buffer is provided by a byte array. Use this class as an alternative to {@link java.io.BufferedOutputStream} 035 * @param out OutputStream to be decorated 036 */ 037 public AbstractBufferedOutputStream(OutputStream out) { 038 this(out, DEFAULT_BUFFER_SIZE); 039 } 040 041 /** 042 * Creates a new instance with the given buffer size in bytes. 043 * @param out OutputStream to be decorated 044 * @param size The size of the buffer in bytes 045 * @see java.io.BufferedOutputStream#BufferedOutputStream(OutputStream, int) 046 */ 047 public AbstractBufferedOutputStream(OutputStream out, int size) { 048 super(out); 049 050 if (size <= 0) { 051 throw new IllegalArgumentException("Buffer size may not be less than or equal to zero"); 052 } 053 } 054 055 private void flushBuffer() throws IOException { 056 057 if (count > 0) { 058 out.write(bytes(), 0, count); 059 count = 0; 060 } 061 } 062 063 /** 064 * @see java.io.BufferedOutputStream#write(int) 065 */ 066 public void write(int b) throws IOException { 067 068 if (count >= limit()) { 069 flushBuffer(); 070 } 071 072 put((byte) b); 073 } 074 075 /** 076 * @see java.io.BufferedOutputStream#write(byte[], int, int) 077 */ 078 public void write(byte b[], int off, int len) throws IOException { 079 080 if (len >= limit()) { 081 flushBuffer(); 082 out.write(b, off, len); 083 return; 084 } 085 086 if (len > limit() - count) { 087 flushBuffer(); 088 } 089 090 put(count, b, off, len); 091 count += len; 092 } 093 094 /** 095 * @see java.io.BufferedOutputStream#flush 096 */ 097 public void flush() throws IOException { 098 099 flushBuffer(); 100 out.flush(); 101 } 102 103 @Override 104 public void close() throws IOException { 105 try { 106 super.close(); 107 } finally { 108 clean(); 109 } 110 } 111 112 /** 113 * Return the bytes in the buffer as a byte array 114 * @return The bytes 115 */ 116 protected abstract byte[] bytes(); 117 118 /** 119 * Put a single byte into the buffer 120 * @param b The byte 121 */ 122 protected abstract void put(byte b); 123 124 /** 125 * Puts bytes into the buffer 126 * @param count The number of bytes already written into the buffer 127 * @param b The byte array with the bytes to put 128 * @param off Offset to write from in the bytes, b 129 * @param len The number of bytes to write 130 */ 131 protected abstract void put(int count, byte[] b, int off, int len); 132 133 /** 134 * Returns the limit of the buffer 135 * @return The limit 136 */ 137 protected abstract int limit(); 138 139 /** 140 * Performs any necessary cleaning of the buffer and releasing of resources. 141 */ 142 protected abstract void clean(); 143}