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