001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028: package net.sf.jasperreports.engine.util;
029:
030: import java.io.BufferedOutputStream;
031: import java.io.ByteArrayOutputStream;
032: import java.io.File;
033: import java.io.FileInputStream;
034: import java.io.FileNotFoundException;
035: import java.io.FileOutputStream;
036: import java.io.IOException;
037: import java.io.OutputStream;
038:
039: import net.sf.jasperreports.engine.JRRuntimeException;
040:
041: import org.apache.commons.logging.Log;
042: import org.apache.commons.logging.LogFactory;
043:
044: /**
045: * @author Lucian Chirita (lucianc@users.sourceforge.net)
046: * @version $Id: FileBufferedOutputStream.java 1823 2007-08-22 14:04:56Z teodord $
047: */
048: public class FileBufferedOutputStream extends OutputStream {
049:
050: private static final Log log = LogFactory
051: .getLog(FileBufferedOutputStream.class);
052:
053: /**
054: * Property specifying the ResultSet fetch size.
055: */
056: public static final String PROPERTY_MEMORY_THRESHOLD = JRProperties.PROPERTY_PREFIX
057: + "file.buffer.os.memory.threshold";
058: //public static final int DEFAULT_MEMORY_THRESHOLD = 1 << 18;
059: public static final int INFINIT_MEMORY_THRESHOLD = -1;
060: public static final int DEFAULT_INITIAL_MEMORY_BUFFER_SIZE = 1 << 16;
061: public static final int DEFAULT_INPUT_BUFFER_LENGTH = 1 << 14;
062:
063: private final int memoryThreshold;
064: private final int initialMemoryBufferSize;
065: private final int inputBufferLength;
066:
067: private final ByteArrayOutputStream memoryOutput;
068: private int size;
069: private File file;
070: private BufferedOutputStream fileOutput;
071: private boolean closed;
072: private boolean disposed;
073:
074: public FileBufferedOutputStream() {
075: this (JRProperties.getIntegerProperty(PROPERTY_MEMORY_THRESHOLD,
076: INFINIT_MEMORY_THRESHOLD),
077: DEFAULT_INITIAL_MEMORY_BUFFER_SIZE,
078: DEFAULT_INPUT_BUFFER_LENGTH);
079: }
080:
081: public FileBufferedOutputStream(int memoryThreshold) {
082: this (memoryThreshold, DEFAULT_INITIAL_MEMORY_BUFFER_SIZE,
083: DEFAULT_INPUT_BUFFER_LENGTH);
084: }
085:
086: public FileBufferedOutputStream(int memoryThreshold,
087: int initialMemoryBufferSize) {
088: this (memoryThreshold, initialMemoryBufferSize,
089: DEFAULT_INPUT_BUFFER_LENGTH);
090: }
091:
092: public FileBufferedOutputStream(int memoryThreshold,
093: int initialMemoryBufferSize, int inputBufferLength) {
094: this .memoryThreshold = memoryThreshold;
095: this .initialMemoryBufferSize = initialMemoryBufferSize;
096: this .inputBufferLength = inputBufferLength;
097:
098: size = 0;
099: memoryOutput = this .memoryThreshold != 0 ? new ByteArrayOutputStream(
100: this .initialMemoryBufferSize)
101: : null;
102: }
103:
104: public void write(int b) throws IOException {
105: checkClosed();
106:
107: if (availableMemorySpace() > 0) {
108: memoryOutput.write(b);
109: } else {
110: ensureFileOutput().write(b);
111: }
112:
113: ++size;
114: }
115:
116: protected int availableMemorySpace() {
117: int availableMemorySpace;
118: if (memoryOutput != null
119: && (memoryThreshold < 0 || memoryOutput.size() < memoryThreshold)) {
120: availableMemorySpace = memoryThreshold
121: - memoryOutput.size();
122: } else {
123: availableMemorySpace = 0;
124: }
125: return availableMemorySpace;
126: }
127:
128: protected BufferedOutputStream ensureFileOutput()
129: throws IOException, FileNotFoundException {
130: if (fileOutput == null) {
131: file = File.createTempFile("file.buff.os.", ".tmp");
132: FileOutputStream fileOutputStream = new FileOutputStream(
133: file);
134: fileOutput = new BufferedOutputStream(fileOutputStream);
135: }
136: return fileOutput;
137: }
138:
139: public void write(byte[] b, int off, int len) throws IOException {
140: checkClosed();
141:
142: int memoryLen = availableMemorySpace();
143: if (len < memoryLen) {
144: memoryLen = len;
145: }
146:
147: if (memoryLen > 0) {
148: memoryOutput.write(b, off, memoryLen);
149: }
150:
151: if (memoryLen < len) {
152: ensureFileOutput().write(b, off + memoryLen,
153: len - memoryLen);
154: }
155:
156: size += len;
157: }
158:
159: public void checkClosed() {
160: if (closed) {
161: throw new JRRuntimeException(
162: "Output stream already closed.");
163: }
164: }
165:
166: public void close() throws IOException {
167: if (!closed && fileOutput != null) {
168: fileOutput.flush();
169: fileOutput.close();
170: }
171:
172: closed = true;
173: }
174:
175: public void flush() throws IOException {
176: if (fileOutput != null) {
177: fileOutput.flush();
178: }
179: }
180:
181: public int size() {
182: return size;
183: }
184:
185: public void writeData(OutputStream out) throws IOException {
186: if (!closed) {
187: close();
188: }
189:
190: if (memoryOutput != null) {
191: memoryOutput.writeTo(out);
192: }
193:
194: if (file != null) {
195: FileInputStream fileInput = new FileInputStream(file);
196: boolean inputClosed = false;
197: try {
198: byte[] buffer = new byte[inputBufferLength];
199: int read;
200: while ((read = fileInput.read(buffer)) > 0) {
201: out.write(buffer, 0, read);
202: }
203: fileInput.close();
204: inputClosed = true;
205: } finally {
206: if (!inputClosed) {
207: try {
208: fileInput.close();
209: } catch (IOException e) {
210: log
211: .warn(
212: "Could not close file input stream",
213: e);
214: }
215: }
216: }
217: }
218: }
219:
220: public void dispose() {
221: if (disposed) {
222: return;
223: }
224:
225: boolean success = true;
226: if (!closed && fileOutput != null) {
227: try {
228: fileOutput.close();
229: } catch (IOException e) {
230: log
231: .warn(
232: "Error while closing the temporary file output stream",
233: e);
234: success = false;
235: }
236: }
237:
238: if (file != null && !file.delete()) {
239: log.warn("Error while deleting the temporary file");
240: success = false;
241: }
242:
243: disposed = success;
244: }
245:
246: protected void finalize() throws Throwable {
247: dispose();
248: super.finalize();
249: }
250:
251: }
|