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 */ 017 package org.apache.logging.log4j.core.appender; 018 019 import java.io.IOException; 020 import java.io.OutputStream; 021 022 /** 023 * Manage an OutputStream so that it can be shared by multiple Appenders and will 024 * allow appenders to reconfigure without requiring a new stream. 025 */ 026 public class OutputStreamManager extends AbstractManager { 027 028 private OutputStream os; 029 030 private byte[] footer = null; 031 032 protected OutputStreamManager(final OutputStream os, final String streamName) { 033 super(streamName); 034 this.os = os; 035 } 036 037 /** 038 * Create a Manager. 039 * 040 * @param name The name of the stream to manage. 041 * @param data The data to pass to the Manager. 042 * @param factory The factory to use to create the Manager. 043 * @param <T> The type of the OutputStreamManager. 044 * @return An OutputStreamManager. 045 */ 046 public static <T> OutputStreamManager getManager(final String name, final T data, 047 final ManagerFactory<? extends OutputStreamManager, T> factory) { 048 return AbstractManager.getManager(name, factory, data); 049 } 050 051 /** 052 * Set the header to write when the stream is opened. 053 * @param header The header. 054 */ 055 public synchronized void setHeader(final byte[] header) { 056 if (header != null) { 057 try { 058 this.os.write(header, 0, header.length); 059 } catch (final IOException ioe) { 060 LOGGER.error("Unable to write header", ioe); 061 } 062 } 063 } 064 065 /** 066 * Set the footer to write when the stream is closed. 067 * @param footer The footer. 068 */ 069 public synchronized void setFooter(final byte[] footer) { 070 if (footer != null) { 071 this.footer = footer; 072 } 073 } 074 075 /** 076 * Default hook to write footer during close. 077 */ 078 @Override 079 public void releaseSub() { 080 if (footer != null) { 081 write(footer); 082 } 083 close(); 084 } 085 086 /** 087 * Returns the status of the stream. 088 * @return true if the stream is open, false if it is not. 089 */ 090 public boolean isOpen() { 091 return getCount() > 0; 092 } 093 094 protected OutputStream getOutputStream() { 095 return os; 096 } 097 098 protected void setOutputStream(final OutputStream os) { 099 this.os = os; 100 } 101 102 /** 103 * Some output streams synchronize writes while others do not. Synchronizing here insures that 104 * log events won't be intertwined. 105 * @param bytes The serialized Log event. 106 * @param offset The offset into the byte array. 107 * @param length The number of bytes to write. 108 * @throws AppenderRuntimeException if an error occurs. 109 */ 110 protected synchronized void write(final byte[] bytes, final int offset, final int length) { 111 //System.out.println("write " + count); 112 try { 113 os.write(bytes, offset, length); 114 } catch (final IOException ex) { 115 final String msg = "Error writing to stream " + getName(); 116 throw new AppenderRuntimeException(msg, ex); 117 } 118 } 119 120 /** 121 * Some output streams synchronize writes while others do not. Synchronizing here insures that 122 * log events won't be intertwined. 123 * @param bytes The serialized Log event. 124 * @throws AppenderRuntimeException if an error occurs. 125 */ 126 protected void write(final byte[] bytes) { 127 write(bytes, 0, bytes.length); 128 } 129 130 protected void close() { 131 if (os == System.out || os == System.err) { 132 return; 133 } 134 try { 135 os.close(); 136 } catch (final IOException ex) { 137 LOGGER.error("Unable to close stream " + getName() + ". " + ex); 138 } 139 } 140 141 /** 142 * Flush any buffers. 143 */ 144 public void flush() { 145 try { 146 os.flush(); 147 } catch (final IOException ex) { 148 final String msg = "Error flushing stream " + getName(); 149 throw new AppenderRuntimeException(msg, ex); 150 } 151 } 152 }