001package ball.activation; 002/*- 003 * ########################################################################## 004 * Utilities 005 * %% 006 * Copyright (C) 2008 - 2022 Allen D. Ball 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * ########################################################################## 020 */ 021import java.beans.ConstructorProperties; 022import java.io.BufferedReader; 023import java.io.IOException; 024import java.io.InputStreamReader; 025import java.io.OutputStreamWriter; 026import java.io.PrintStream; 027import java.io.PrintWriter; 028import java.io.Reader; 029import java.io.Writer; 030import java.nio.charset.Charset; 031 032import static java.nio.charset.StandardCharsets.UTF_8; 033import static java.util.stream.Collectors.joining; 034import static org.apache.commons.lang3.StringUtils.EMPTY; 035 036/** 037 * {@link javax.activation.DataSource} implementation that provides a 038 * {@link BufferedReader} wrapping the {@link javax.activation.DataSource} 039 * {@link java.io.InputStream} and a {@link PrintWriter} wrapping the 040 * {@link javax.activation.DataSource} {@link java.io.OutputStream}. 041 * 042 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 043 */ 044public class ReaderWriterDataSource extends FilterDataSource { 045 protected static final Charset CHARSET = UTF_8; 046 047 private final Charset charset; 048 049 /** 050 * @param name Initial {@code "Name"} attribute value. 051 * @param type Initial {@code "ContentType"} attribute 052 * value. 053 */ 054 @ConstructorProperties({ "name", "contentType" }) 055 public ReaderWriterDataSource(String name, String type) { 056 this(name, type, null); 057 } 058 059 /** 060 * @param name Initial {@code "Name"} attribute value. 061 * @param type Initial {@code "ContentType"} attribute 062 * value. 063 * @param charset The {@link Charset} used to encode the 064 * {@link java.io.OutputStream}. 065 */ 066 @ConstructorProperties({ "name", "contentType", "charset" }) 067 public ReaderWriterDataSource(String name, String type, Charset charset) { 068 this(name, type, charset, null); 069 } 070 071 /** 072 * @param name Initial {@code "Name"} attribute value. 073 * @param type Initial {@code "ContentType"} attribute 074 * value. 075 * @param charset The {@link Charset} used to encode the 076 * {@link java.io.OutputStream}. 077 * @param content The initial content {@link String}. 078 */ 079 @ConstructorProperties({ "name", "contentType", "charset", EMPTY }) 080 public ReaderWriterDataSource(String name, String type, Charset charset, String content) { 081 super(new ByteArrayDataSource(name, type)); 082 083 this.charset = (charset != null) ? charset : CHARSET; 084 085 if (content != null) { 086 try (Writer writer = getWriter()) { 087 writer.write(content); 088 } catch (IOException exception) { 089 throw new ExceptionInInitializerError(exception); 090 } 091 } 092 } 093 094 /** 095 * Private no-argument constructor (for JAXB annotated subclasses). 096 */ 097 private ReaderWriterDataSource() { this(null, null); } 098 099 /** 100 * Method to get the {@link Charset} used to create the 101 * {@link BufferedReader} and {@link PrintWriter}. 102 * 103 * @return The Charset. 104 */ 105 public Charset getCharset() { return charset; } 106 107 /** 108 * Method to return a new {@link Reader} to read the underlying 109 * {@link java.io.InputStream}. 110 * 111 * @see #getInputStream() 112 * 113 * @return A {@link Reader} wrapping the 114 * {@link javax.activation.DataSource} 115 * {@link java.io.InputStream}. 116 * 117 * @throws IOException If an I/O exception occurs. 118 */ 119 public Reader getReader() throws IOException { 120 return new InputStreamReader(getInputStream(), getCharset()); 121 } 122 123 /** 124 * Method to return a new {@link Writer} to write to the underlying 125 * {@link java.io.OutputStream}. 126 * 127 * @see #getOutputStream() 128 * 129 * @return A {@link Writer} wrapping the 130 * {@link javax.activation.DataSource} 131 * {@link java.io.OutputStream}. 132 * 133 * @throws IOException If an I/O exception occurs. 134 */ 135 public Writer getWriter() throws IOException { 136 return new OutputStreamWriter(getOutputStream(), getCharset()); 137 } 138 139 /** 140 * Method to return a new {@link BufferedReader} to read the underlying 141 * {@link java.io.InputStream}. 142 * 143 * @see #getInputStream() 144 * 145 * @return A {@link BufferedReader} wrapping the 146 * {@link javax.activation.DataSource} 147 * {@link java.io.InputStream}. 148 * 149 * @throws IOException If an I/O exception occurs. 150 */ 151 public BufferedReader getBufferedReader() throws IOException { 152 return new BufferedReader(getReader()); 153 } 154 155 /** 156 * Method to return a new {@link PrintWriter} to write to the underlying 157 * {@link java.io.OutputStream}. 158 * 159 * @see #getOutputStream() 160 * 161 * @return A {@link PrintWriter} wrapping the 162 * {@link javax.activation.DataSource} 163 * {@link java.io.OutputStream}. 164 * 165 * @throws IOException If an I/O exception occurs. 166 */ 167 public PrintWriter getPrintWriter() throws IOException { 168 return new PrintWriter(getWriter(), true); 169 } 170 171 /** 172 * Method to return a new {@link PrintStream} to write to the underlying 173 * {@link java.io.OutputStream}. 174 * 175 * @see #getOutputStream() 176 * 177 * @return A {@link PrintStream} wrapping the 178 * {@link javax.activation.DataSource} 179 * {@link java.io.OutputStream}. 180 * 181 * @throws IOException If an I/O exception occurs. 182 */ 183 public PrintStream getPrintStream() throws IOException { 184 return new PrintStream(getOutputStream(), true, getCharset().name()); 185 } 186 187 /** 188 * Method to write the contents of this 189 * {@link javax.activation.DataSource} to a {@link PrintWriter}. 190 * 191 * @see #getBufferedReader() 192 * 193 * @param writer The target {@link PrintWriter}. 194 * 195 * @throws IOException If a problem is encountered opening or 196 * reading the {@link BufferedReader} or 197 * writing to the {@link PrintWriter}. 198 */ 199 public void writeTo(PrintWriter writer) throws IOException { 200 getBufferedReader().lines().forEach(t -> writer.println(t)); 201 } 202 203 @Override 204 public String toString() { 205 String string = null; 206 207 try (BufferedReader reader = getBufferedReader()) { 208 string = reader.lines().collect(joining("\n")); 209 } catch (IOException exception) { 210 string = super.toString(); 211 } 212 213 return string; 214 } 215 216 /** 217 * Convenience method to get the name of a {@link Charset}. 218 * 219 * @param charset The {@link Charset}. 220 * 221 * @return The name of the {@link Charset} if non-{@code null}; 222 * {@code null} otherwise. 223 * 224 * @see Charset#name() 225 */ 226 protected static String nameOf(Charset charset) { 227 return (charset != null) ? charset.name() : null; 228 } 229}