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