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 * </p> 034 * 035 */ 036public class ProxyOutputStream extends FilterOutputStream { 037 038 /** 039 * Constructs a new ProxyOutputStream. 040 * 041 * @param proxy the OutputStream to delegate to 042 */ 043 public ProxyOutputStream(final OutputStream proxy) { 044 super(proxy); 045 // the proxy is stored in a protected superclass variable named 'out' 046 } 047 048 /** 049 * Invokes the delegate's {@code write(int)} method. 050 * @param idx the byte to write 051 * @throws IOException if an I/O error occurs. 052 */ 053 @Override 054 public void write(final int idx) throws IOException { 055 try { 056 beforeWrite(1); 057 out.write(idx); 058 afterWrite(1); 059 } catch (final IOException e) { 060 handleIOException(e); 061 } 062 } 063 064 /** 065 * Invokes the delegate's {@code write(byte[])} method. 066 * @param bts the bytes to write 067 * @throws IOException if an I/O error occurs. 068 */ 069 @Override 070 public void write(final byte[] bts) throws IOException { 071 try { 072 final int len = IOUtils.length(bts); 073 beforeWrite(len); 074 out.write(bts); 075 afterWrite(len); 076 } catch (final IOException e) { 077 handleIOException(e); 078 } 079 } 080 081 /** 082 * Invokes the delegate's {@code write(byte[])} method. 083 * @param bts the bytes to write 084 * @param st The start offset 085 * @param end The number of bytes to write 086 * @throws IOException if an I/O error occurs. 087 */ 088 @Override 089 public void write(final byte[] bts, final int st, final int end) throws IOException { 090 try { 091 beforeWrite(end); 092 out.write(bts, st, end); 093 afterWrite(end); 094 } catch (final IOException e) { 095 handleIOException(e); 096 } 097 } 098 099 /** 100 * Invokes the delegate's {@code flush()} method. 101 * @throws IOException if an I/O error occurs. 102 */ 103 @Override 104 public void flush() throws IOException { 105 try { 106 out.flush(); 107 } catch (final IOException e) { 108 handleIOException(e); 109 } 110 } 111 112 /** 113 * Invokes the delegate's {@code close()} method. 114 * @throws IOException if an I/O error occurs. 115 */ 116 @Override 117 public void close() throws IOException { 118 IOUtils.close(out, this::handleIOException); 119 } 120 121 /** 122 * Invoked by the write methods before the call is proxied. The number 123 * of bytes to be written (1 for the {@link #write(int)} method, buffer 124 * length for {@link #write(byte[])}, etc.) is given as an argument. 125 * <p> 126 * Subclasses can override this method to add common pre-processing 127 * functionality without having to override all the write methods. 128 * The default implementation does nothing. 129 * 130 * @since 2.0 131 * @param n number of bytes to be written 132 * @throws IOException if the pre-processing fails 133 */ 134 @SuppressWarnings("unused") // Possibly thrown from subclasses. 135 protected void beforeWrite(final int n) throws IOException { 136 // noop 137 } 138 139 /** 140 * Invoked by the write methods after the proxied call has returned 141 * successfully. The number of bytes written (1 for the 142 * {@link #write(int)} method, buffer length for {@link #write(byte[])}, 143 * etc.) is given as an argument. 144 * <p> 145 * Subclasses can override this method to add common post-processing 146 * functionality without having to override all the write methods. 147 * The default implementation does nothing. 148 * 149 * @since 2.0 150 * @param n number of bytes written 151 * @throws IOException if the post-processing fails 152 */ 153 @SuppressWarnings("unused") // Possibly thrown from subclasses. 154 protected void afterWrite(final int n) throws IOException { 155 // noop 156 } 157 158 /** 159 * Handle any IOExceptions thrown. 160 * <p> 161 * This method provides a point to implement custom exception 162 * handling. The default behavior is to re-throw the exception. 163 * @param e The IOException thrown 164 * @throws IOException if an I/O error occurs. 165 * @since 2.0 166 */ 167 protected void handleIOException(final IOException e) throws IOException { 168 throw e; 169 } 170 171}