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