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.marshall.parser;
018
019
020import java.io.*;
021import java.nio.charset.*;
022
023import org.apache.juneau.commons.collections.*;
024import static org.apache.juneau.commons.utils.Shorts.*;
025
026/**
027 * Subclass of parser session objects for character-based parsers.
028 *
029 * <h5 class='section'>Notes:</h5><ul>
030 *    <li class='warn'>This class is not thread safe and is typically discarded after one use.
031 * </ul>
032 *
033 * <h5 class='section'>See Also:</h5><ul>
034 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a>
035 * </ul>
036 */
037@SuppressWarnings({
038   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
039})
040public class ReaderParserSession extends ParserSession {
041
042   /**
043    * Builder class.
044    */
045   @SuppressWarnings({
046      "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
047   })
048   public abstract static class Builder<SELF extends Builder<SELF>> extends ParserSession.Builder<SELF> {
049
050      private Charset streamCharset;
051      private final ReaderParser ctx;
052
053      /**
054       * Constructor
055       *
056       * @param ctx The context creating this session.
057       *    <br>Cannot be <jk>null</jk>.
058       */
059      protected Builder(ReaderParser ctx) {
060         super(reqnn("ctx", ctx));
061         this.ctx = ctx;
062         streamCharset = ctx.getStreamCharset();
063      }
064
065      @Override
066      public ReaderParserSession build() {
067         return new ReaderParserSession(this);
068      }
069
070      @Override /* Overridden from Builder */
071      public SELF property(String key, Object value) {
072         if (key == null) {
073            super.property(key, value);
074            return self();
075         }
076         switch (key) {
077            case "streamCharset", "ReaderParserSession.streamCharset":
078               return streamCharset(cvt(value, Charset.class));
079            default:
080               super.property(key, value);
081               return self();
082         }
083      }
084
085      /**
086       * Input stream charset.
087       *
088       * <p>
089       * The character set to use for converting InputStreams and byte arrays to readers.
090       *
091       * <p>
092       * Used when passing in input streams and byte arrays to {@link Parser#read(Object, Class)}.
093       *
094       * <p>
095       * If not specified, defaults to UTF-8.
096       *
097       * @param value
098       *    The new property value.
099       *    <br>Can be <jk>null</jk> (defaults to UTF-8).
100       * @return This object.
101       */
102      public SELF streamCharset(Charset value) {
103         streamCharset = value;
104         return self();
105      }
106
107   }
108
109   /**
110    * Concrete default builder leaf for the non-subclassed {@code create()} path (CRTP terminal).
111    */
112   public static final class DefaultBuilder extends Builder<DefaultBuilder> {
113
114      DefaultBuilder(ReaderParser ctx) {
115         super(ctx);
116      }
117   }
118
119   /**
120    * Creates a new builder for this object.
121    *
122    * @param ctx The context creating this session.
123    *    <br>Cannot be <jk>null</jk>.
124    * @return A new builder.
125    */
126   @SuppressWarnings({
127      "java:S1452" // Builder<?> wildcard return intentional; callers use it to construct session instances polymorphically
128   })
129   public static Builder<?> create(ReaderParser ctx) {
130      return new DefaultBuilder(reqnn("ctx", ctx));
131   }
132
133   private final ReaderParser ctx;
134   private final Charset streamCharset;
135
136   /**
137    * Constructor.
138    *
139    * @param builder The builder for this object.
140    *    <br>Cannot be <jk>null</jk>.
141    */
142   protected ReaderParserSession(Builder<?> builder) {
143      super(builder);
144      ctx = builder.ctx;
145      streamCharset = builder.streamCharset;
146   }
147
148   /**
149    * Wraps the specified input object into a {@link ParserPipe} object so that it can be easily converted into
150    * a stream or reader.
151    *
152    * @param input
153    *    The input.
154    *    <br>This can be any of the following types:
155    *    <ul>
156    *       <li><jk>null</jk>
157    *       <li>{@link Reader}
158    *       <li>{@link CharSequence}
159    *       <li>{@link InputStream} containing UTF-8 encoded text (or whatever the encoding specified by
160    *          {@link ReaderParser.Builder#streamCharset(Charset)}).
161    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or whatever the encoding specified by
162    *          {@link ReaderParser.Builder#streamCharset(Charset)}).
163    *    </ul>
164    * @return
165    *    A new {@link ParserPipe} wrapper around the specified input object.
166    */
167   @SuppressWarnings({
168      "resource" // Resource management handled by ParserPipe
169   })
170   @Override /* Overridden from ParserSesson */
171   public final ParserPipe createPipe(Object input) {
172      return setPipe(new ParserPipe(input, isDebug(), true, ctx.isAutoCloseStreams(), ctx.isUnbuffered(), streamCharset));
173   }
174
175   /**
176    * Returns the stream charset defined on this session.
177    *
178    * @return the stream charset defined on this session.
179    */
180   public Charset getStreamCharset() { return streamCharset; }
181
182   @Override /* Overridden from ParserSession */
183   public final boolean isReaderParser() { return true; }
184
185   @Override /* Overridden from ParserSession */
186   protected FluentMap<String,Object> properties() {
187      return super.properties()
188         .a("streamCharset", streamCharset);
189   }
190}