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