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.common.internal.IOUtils.*; 016import static org.apache.juneau.common.internal.ThrowableUtils.*; 017import static org.apache.juneau.internal.ClassUtils.*; 018 019import java.io.*; 020import java.nio.charset.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.common.internal.*; 024import org.apache.juneau.internal.*; 025 026/** 027 * A wrapper around an object that a serializer sends its output to. 028 * 029 * <p> 030 * For character-based serializers, the output object can be any of the following: 031 * <ul> 032 * <li>{@link Writer} 033 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 034 * <li>{@link File} - Output will be written as system-default encoded stream. 035 * <li>{@link StringBuilder} 036 * </ul> 037 * 038 * <p> 039 * For stream-based serializers, the output object can be any of the following: 040 * <ul> 041 * <li>{@link OutputStream} 042 * <li>{@link File} 043 * </ul> 044 * 045 * <h5 class='section'>See Also:</h5><ul> 046 * <li class='link'><a class="doclink" href="../../../../index.html#jm.SerializersAndParsers">Serializers and Parsers</a> 047 * </ul> 048 */ 049public final class SerializerPipe implements Closeable { 050 051 private final Object output; 052 private final boolean autoClose; 053 054 private OutputStream outputStream; 055 private Writer writer; 056 private Charset charset; 057 058 /** 059 * Writer-based constructor. 060 * 061 * @param output The object to pipe the serializer output to. 062 */ 063 SerializerPipe(Object output, Charset streamCharset, Charset fileCharset) { 064 boolean isFile = (output instanceof File); 065 this.output = output; 066 this.autoClose = isFile; 067 Charset cs = isFile ? fileCharset : streamCharset; 068 if (cs == null) 069 cs = isFile ? Charset.defaultCharset() : UTF8; 070 this.charset = cs; 071 } 072 073 /** 074 * Stream-based constructor. 075 * 076 * @param output The object to pipe the serializer output to. 077 */ 078 SerializerPipe(Object output) { 079 this.output = output; 080 this.autoClose = false; 081 this.charset = null; 082 } 083 084 /** 085 * Wraps the specified output object inside an output stream. 086 * 087 * <p> 088 * Subclasses can override this method to implement their own specialized output streams. 089 * 090 * <p> 091 * This method can be used if the output object is any of the following class types: 092 * <ul> 093 * <li>{@link OutputStream} 094 * <li>{@link File} 095 * </ul> 096 * 097 * @return 098 * The output object wrapped in an output stream. 099 * Calling {@link OutputStream#close()} on the returned object simply flushes the response and does not close 100 * the underlying stream. 101 * @throws IOException If object could not be converted to an output stream. 102 */ 103 public OutputStream getOutputStream() throws IOException { 104 if (output == null) 105 throw new IOException("Output cannot be null."); 106 107 if (output instanceof OutputStream) 108 outputStream = (OutputStream)output; 109 else if (output instanceof File) 110 outputStream = new BufferedOutputStream(new FileOutputStream((File)output)); 111 else 112 throw new IOException("Cannot convert object of type "+className(output)+" to an OutputStream."); 113 114 return new NoCloseOutputStream(outputStream); 115 } 116 117 118 /** 119 * Wraps the specified output object inside a writer. 120 * 121 * <p> 122 * Subclasses can override this method to implement their own specialized writers. 123 * 124 * <p> 125 * This method can be used if the output object is any of the following class types: 126 * <ul> 127 * <li>{@link Writer} 128 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 129 * <li>{@link File} - Output will be written as system-default encoded stream. 130 * </ul> 131 * 132 * @return 133 * The output object wrapped in a writer. 134 * Calling {@link Writer#close()} on the returned object simply flushes the response and does not close 135 * the underlying writer. 136 * @throws SerializeException If object could not be converted to a writer. 137 */ 138 public Writer getWriter() throws SerializeException { 139 if (output == null) 140 throw new SerializeException("Output cannot be null."); 141 142 try { 143 if (output instanceof Writer) 144 writer = (Writer)output; 145 else if (output instanceof OutputStream) 146 writer = new OutputStreamWriter((OutputStream)output, charset); 147 else if (output instanceof File) 148 writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream((File)output))); 149 else if (output instanceof StringBuilder) 150 writer = new StringBuilderWriter((StringBuilder)output); 151 else 152 throw new SerializeException("Cannot convert object of type "+className(output)+" to a Writer."); 153 } catch (FileNotFoundException e) { 154 throw cast(SerializeException.class, e); 155 } 156 157 return new NoCloseWriter(writer); 158 } 159 160 /** 161 * Overwrites the writer in this pipe. 162 * 163 * <p> 164 * Used when wrapping the writer returned by {@link #getWriter()} so that the wrapped writer will be flushed 165 * and closed when {@link #close()} is called. 166 * 167 * @param writer The wrapped writer. 168 */ 169 public void setWriter(Writer writer) { 170 this.writer = writer; 171 } 172 173 /** 174 * Overwrites the output stream in this pipe. 175 * 176 * <p> 177 * Used when wrapping the stream returned by {@link #getOutputStream()} so that the wrapped stream will be flushed 178 * when {@link #close()} is called. 179 * 180 * @param outputStream The wrapped stream. 181 */ 182 public void setOutputStream(OutputStream outputStream) { 183 this.outputStream = outputStream; 184 } 185 186 /** 187 * Returns the raw output object passed into this session. 188 * 189 * @return The raw output object passed into this session. 190 */ 191 public Object getRawOutput() { 192 return output; 193 } 194 195 /** 196 * Closes the output pipe. 197 */ 198 @Override /* Closeable */ 199 public void close() { 200 try { 201 IOUtils.flush(writer, outputStream); 202 if (autoClose) 203 IOUtils.close(writer, outputStream); 204 } catch (IOException e) { 205 throw new BeanRuntimeException(e); 206 } 207 } 208}