001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.io.output; 018 019import java.io.FilterOutputStream; 020import java.io.IOException; 021import java.io.OutputStream; 022 023import org.apache.commons.io.IOUtils; 024 025/** 026 * A Proxy stream which acts as expected, that is it passes the method 027 * calls on to the proxied stream and doesn't change which methods are 028 * being called. It is an alternative base class to FilterOutputStream 029 * to increase reusability. 030 * <p> 031 * See the protected methods for ways in which a subclass can easily decorate 032 * a stream with custom pre-, post- or error processing functionality. 033 * 034 */ 035public class ProxyOutputStream extends FilterOutputStream { 036 037 /** 038 * Constructs a new ProxyOutputStream. 039 * 040 * @param proxy the OutputStream to delegate to 041 */ 042 public ProxyOutputStream(final OutputStream proxy) { 043 super(proxy); 044 // the proxy is stored in a protected superclass variable named 'out' 045 } 046 047 /** 048 * Invokes the delegate's <code>write(int)</code> method. 049 * @param idx the byte to write 050 * @throws IOException if an I/O error occurs 051 */ 052 @Override 053 public void write(final int idx) throws IOException { 054 try { 055 beforeWrite(1); 056 out.write(idx); 057 afterWrite(1); 058 } catch (final IOException e) { 059 handleIOException(e); 060 } 061 } 062 063 /** 064 * Invokes the delegate's <code>write(byte[])</code> method. 065 * @param bts the bytes to write 066 * @throws IOException if an I/O error occurs 067 */ 068 @Override 069 public void write(final byte[] bts) throws IOException { 070 try { 071 final int len = IOUtils.length(bts); 072 beforeWrite(len); 073 out.write(bts); 074 afterWrite(len); 075 } catch (final IOException e) { 076 handleIOException(e); 077 } 078 } 079 080 /** 081 * Invokes the delegate's <code>write(byte[])</code> method. 082 * @param bts the bytes to write 083 * @param st The start offset 084 * @param end The number of bytes to write 085 * @throws IOException if an I/O error occurs 086 */ 087 @Override 088 public void write(final byte[] bts, final int st, final int end) throws IOException { 089 try { 090 beforeWrite(end); 091 out.write(bts, st, end); 092 afterWrite(end); 093 } catch (final IOException e) { 094 handleIOException(e); 095 } 096 } 097 098 /** 099 * Invokes the delegate's <code>flush()</code> method. 100 * @throws IOException if an I/O error occurs 101 */ 102 @Override 103 public void flush() throws IOException { 104 try { 105 out.flush(); 106 } catch (final IOException e) { 107 handleIOException(e); 108 } 109 } 110 111 /** 112 * Invokes the delegate's <code>close()</code> method. 113 * @throws IOException if an I/O error occurs 114 */ 115 @Override 116 public void close() throws IOException { 117 IOUtils.close(out, e -> handleIOException(e)); 118 } 119 120 /** 121 * Invoked by the write methods before the call is proxied. The number 122 * of bytes to be written (1 for the {@link #write(int)} method, buffer 123 * length for {@link #write(byte[])}, etc.) is given as an argument. 124 * <p> 125 * Subclasses can override this method to add common pre-processing 126 * functionality without having to override all the write methods. 127 * The default implementation does nothing. 128 * 129 * @since 2.0 130 * @param n number of bytes to be written 131 * @throws IOException if the pre-processing fails 132 */ 133 protected void beforeWrite(final int n) throws IOException { 134 // noop 135 } 136 137 /** 138 * Invoked by the write methods after the proxied call has returned 139 * successfully. The number of bytes written (1 for the 140 * {@link #write(int)} method, buffer length for {@link #write(byte[])}, 141 * etc.) is given as an argument. 142 * <p> 143 * Subclasses can override this method to add common post-processing 144 * functionality without having to override all the write methods. 145 * The default implementation does nothing. 146 * 147 * @since 2.0 148 * @param n number of bytes written 149 * @throws IOException if the post-processing fails 150 */ 151 protected void afterWrite(final int n) throws IOException { 152 // noop 153 } 154 155 /** 156 * Handle any IOExceptions thrown. 157 * <p> 158 * This method provides a point to implement custom exception 159 * handling. The default behavior is to re-throw the exception. 160 * @param e The IOException thrown 161 * @throws IOException if an I/O error occurs 162 * @since 2.0 163 */ 164 protected void handleIOException(final IOException e) throws IOException { 165 throw e; 166 } 167 168}