001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.serializer; 014 015import static org.apache.juneau.internal.IOUtils.*; 016 017import java.io.*; 018import java.nio.charset.*; 019 020import org.apache.juneau.*; 021import org.apache.juneau.internal.*; 022 023/** 024 * A wrapper around an object that a serializer sends its output to. 025 * 026 * <p> 027 * For character-based serializers, the output object can be any of the following: 028 * <ul> 029 * <li>{@link Writer} 030 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 031 * <li>{@link File} - Output will be written as system-default encoded stream. 032 * <li>{@link StringBuilder} 033 * </ul> 034 * 035 * <p> 036 * For stream-based serializers, the output object can be any of the following: 037 * <ul> 038 * <li>{@link OutputStream} 039 * <li>{@link File} 040 * </ul> 041 */ 042public final class SerializerPipe implements Closeable { 043 044 private final Object output; 045 private final boolean autoClose; 046 047 private OutputStream outputStream; 048 private Writer writer; 049 private Charset charset; 050 051 /** 052 * Writer-based constructor. 053 * 054 * @param output The object to pipe the serializer output to. 055 */ 056 SerializerPipe(Object output, Charset streamCharset, Charset fileCharset) { 057 boolean isFile = (output instanceof File); 058 this.output = output; 059 this.autoClose = isFile; 060 Charset cs = isFile ? fileCharset : streamCharset; 061 if (cs == null) 062 cs = isFile ? Charset.defaultCharset() : UTF8; 063 this.charset = cs; 064 } 065 066 /** 067 * Stream-based constructor. 068 * 069 * @param output The object to pipe the serializer output to. 070 */ 071 SerializerPipe(Object output) { 072 this.output = output; 073 this.autoClose = false; 074 this.charset = null; 075 } 076 077 /** 078 * Wraps the specified output object inside an output stream. 079 * 080 * <p> 081 * Subclasses can override this method to implement their own specialized output streams. 082 * 083 * <p> 084 * This method can be used if the output object is any of the following class types: 085 * <ul> 086 * <li>{@link OutputStream} 087 * <li>{@link File} 088 * </ul> 089 * 090 * @return 091 * The output object wrapped in an output stream. 092 * Calling {@link OutputStream#close()} on the returned object simply flushes the response and does not close 093 * the underlying stream. 094 * @throws IOException If object could not be converted to an output stream. 095 */ 096 public OutputStream getOutputStream() throws IOException { 097 if (output == null) 098 throw new IOException("Output cannot be null."); 099 100 if (output instanceof OutputStream) 101 outputStream = (OutputStream)output; 102 else if (output instanceof File) 103 outputStream = new BufferedOutputStream(new FileOutputStream((File)output)); 104 else 105 throw new IOException("Cannot convert object of type "+output.getClass().getName()+" to an OutputStream."); 106 107 return new NoCloseOutputStream(outputStream); 108 } 109 110 111 /** 112 * Wraps the specified output object inside a writer. 113 * 114 * <p> 115 * Subclasses can override this method to implement their own specialized writers. 116 * 117 * <p> 118 * This method can be used if the output object is any of the following class types: 119 * <ul> 120 * <li>{@link Writer} 121 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 122 * <li>{@link File} - Output will be written as system-default encoded stream. 123 * </ul> 124 * 125 * @return 126 * The output object wrapped in a writer. 127 * Calling {@link Writer#close()} on the returned object simply flushes the response and does not close 128 * the underlying writer. 129 * @throws IOException If object could not be converted to a writer. 130 */ 131 public Writer getWriter() throws IOException { 132 if (output == null) 133 throw new IOException("Output cannot be null."); 134 135 if (output instanceof Writer) 136 writer = (Writer)output; 137 else if (output instanceof OutputStream) 138 writer = new OutputStreamWriter((OutputStream)output, charset); 139 else if (output instanceof File) 140 writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream((File)output))); 141 else if (output instanceof StringBuilder) 142 writer = new StringBuilderWriter((StringBuilder)output); 143 else 144 throw new IOException("Cannot convert object of type "+output.getClass().getName()+" to a Writer."); 145 146 return new NoCloseWriter(writer); 147 } 148 149 /** 150 * Overwrites the writer in this pipe. 151 * 152 * <p> 153 * Used when wrapping the writer returned by {@link #getWriter()} so that the wrapped writer will be flushed 154 * and closed when {@link #close()} is called. 155 * 156 * @param writer The wrapped writer. 157 */ 158 public void setWriter(Writer writer) { 159 this.writer = writer; 160 } 161 162 /** 163 * Overwrites the output stream in this pipe. 164 * 165 * <p> 166 * Used when wrapping the stream returned by {@link #getOutputStream()} so that the wrapped stream will be flushed 167 * when {@link #close()} is called. 168 * 169 * @param outputStream The wrapped stream. 170 */ 171 public void setOutputStream(OutputStream outputStream) { 172 this.outputStream = outputStream; 173 } 174 175 /** 176 * Returns the raw output object passed into this session. 177 * 178 * @return The raw output object passed into this session. 179 */ 180 public Object getRawOutput() { 181 return output; 182 } 183 184 /** 185 * Closes the output pipe. 186 */ 187 @Override /* Closeable */ 188 public void close() { 189 try { 190 IOUtils.flush(writer, outputStream); 191 if (autoClose) 192 IOUtils.close(writer, outputStream); 193 } catch (IOException e) { 194 throw new BeanRuntimeException(e); 195 } 196 } 197}