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.parser;
014
015import java.nio.charset.*;
016
017import org.apache.juneau.*;
018
019/**
020 * Subclass of {@link Parser} for characters-based parsers.
021 *
022 * <h5 class='topic'>Description</h5>
023 *
024 * This class is typically the parent class of all character-based parsers.
025 * It has 1 abstract method to implement...
026 * <ul>
027 *    <li><code>parse(ParserSession, ClassMeta)</code>
028 * </ul>
029 */
030public abstract class ReaderParser extends Parser {
031
032   //-------------------------------------------------------------------------------------------------------------------
033   // Configurable properties
034   //-------------------------------------------------------------------------------------------------------------------
035
036   private static final String PREFIX = "ReaderParser.";
037
038   /**
039    * Configuration property:  File charset.
040    *
041    * <h5 class='section'>Property:</h5>
042    * <ul>
043    *    <li><b>Name:</b>  <js>"ReaderParser.fileCharset.s"</js>
044    *    <li><b>Data type:</b>  <code>String</code>
045    *    <li><b>Default:</b>  <js>"DEFAULT"</js>
046    *    <li><b>Session property:</b>  <jk>false</jk>
047    *    <li><b>Methods:</b>
048    *       <ul>
049    *          <li class='jm'>{@link ReaderParserBuilder#fileCharset(String)}
050    *          <li class='jm'>{@link ReaderParserBuilder#fileCharset(Charset)}
051    *       </ul>
052    * </ul>
053    *
054    * <h5 class='section'>Description:</h5>
055    * <p>
056    * The character set to use for reading <code>Files</code> from the file system.
057    *
058    * <p>
059    * Used when passing in files to {@link Parser#parse(Object, Class)}.
060    *
061    * <p>
062    * <js>"DEFAULT"</js> can be used to indicate the JVM default file system charset.
063    *
064    * <h5 class='section'>Example:</h5>
065    * <p class='bcode w800'>
066    *    <jc>// Create a parser that reads UTF-8 files.</jc>
067    *    ReaderParser p = JsonParser.
068    *       .<jsm>create</jsm>()
069    *       .fileCharset(<js>"UTF-8"</js>)
070    *       .build();
071    *
072    *    <jc>// Same, but use property.</jc>
073    *    ReaderParser p = JsonParser.
074    *       .<jsm>create</jsm>()
075    *       .set(<jsf>PARSER_fileCharset</jsf>, <js>"UTF-8"</js>)
076    *       .build();
077    *
078    *    <jc>// Use it to read a UTF-8 encoded file.</jc>
079    *    MyBean myBean = p.parse(<jk>new</jk> File(<js>"MyBean.txt"</js>), MyBean.<jk>class</jk>);
080    * </p>
081    */
082   public static final String RPARSER_fileCharset = PREFIX + "fileCharset.s";
083
084   /**
085    * Configuration property:  Input stream charset.
086    *
087    * <h5 class='section'>Property:</h5>
088    * <ul>
089    *    <li><b>Name:</b>  <js>"ReaderParser.inputStreamCharset.s"</js>
090    *    <li><b>Data type:</b>  <code>String</code>
091    *    <li><b>Default:</b>  <js>"UTF-8"</js>
092    *    <li><b>Session property:</b>  <jk>false</jk>
093    *    <li><b>Methods:</b>
094    *       <ul>
095    *          <li class='jm'>{@link ReaderParserBuilder#inputStreamCharset(String)}
096    *          <li class='jm'>{@link ReaderParserBuilder#inputStreamCharset(Charset)}
097    *       </ul>
098    * </ul>
099    *
100    * <h5 class='section'>Description:</h5>
101    * <p>
102    * The character set to use for converting <code>InputStreams</code> and byte arrays to readers.
103    *
104    * <p>
105    * Used when passing in input streams and byte arrays to {@link Parser#parse(Object, Class)}.
106    *
107    * <h5 class='section'>Example:</h5>
108    * <p class='bcode w800'>
109    *    <jc>// Create a parser that reads UTF-8 files.</jc>
110    *    ReaderParser p = JsonParser.
111    *       .<jsm>create</jsm>()
112    *       .inputStreamCharset(<js>"UTF-8"</js>)
113    *       .build();
114    *
115    *    <jc>// Same, but use property.</jc>
116    *    ReaderParser p = JsonParser.
117    *       .<jsm>create</jsm>()
118    *       .set(<jsf>PARSER_inputStreamCharset</jsf>, <js>"UTF-8"</js>)
119    *       .build();
120    *
121    *    <jc>// Use it to read a UTF-8 encoded input stream.</jc>
122    *    MyBean myBean = p.parse(<jk>new</jk> FileInputStream(<js>"MyBean.txt"</js>), MyBean.<jk>class</jk>);
123    * </p>
124    */
125   public static final String RPARSER_inputStreamCharset = PREFIX + "inputStreamCharset.s";
126
127   static final ReaderParser DEFAULT = new ReaderParser(PropertyStore.create().build(), "") {
128      @Override
129      public ReaderParserSession createSession(ParserSessionArgs args) {
130         throw new NoSuchMethodError();
131      }
132   };
133
134   //-------------------------------------------------------------------------------------------------------------------
135   // Instance
136   //-------------------------------------------------------------------------------------------------------------------
137
138   private final String inputStreamCharset, fileCharset;
139
140   /**
141    * Constructor.
142    *
143    * @param ps The property store containing all the settings for this object.
144    * @param consumes The list of media types that this parser consumes (e.g. <js>"application/json"</js>, <js>"*&#8203;/json"</js>).
145    */
146   protected ReaderParser(PropertyStore ps, String...consumes) {
147      super(ps, consumes);
148
149      inputStreamCharset = getStringProperty(RPARSER_inputStreamCharset, "UTF-8");
150      fileCharset = getStringProperty(RPARSER_fileCharset, "DEFAULT");
151   }
152
153   @Override /* Parser */
154   public final boolean isReaderParser() {
155      return true;
156   }
157
158   //-----------------------------------------------------------------------------------------------------------------
159   // Properties
160   //-----------------------------------------------------------------------------------------------------------------
161
162   /**
163    * Configuration property:  Input stream charset.
164    *
165    * @see #RPARSER_inputStreamCharset
166    * @return
167    *    The character set to use for converting <code>InputStreams</code> and byte arrays to readers.
168    */
169   protected final String getInputStreamCharset() {
170      return inputStreamCharset;
171   }
172
173   /**
174    * Configuration property:  File charset.
175    *
176    * @see #RPARSER_fileCharset
177    * @return
178    *    The character set to use for reading <code>Files</code> from the file system.
179    */
180   protected final String getFileCharset() {
181      return fileCharset;
182   }
183
184   @Override /* Context */
185   public ObjectMap asMap() {
186      return super.asMap()
187         .append("ReaderParser", new ObjectMap()
188            .append("inputStreamCharset", inputStreamCharset)
189            .append("fileCharset", fileCharset)
190         );
191   }
192}