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