1 /*
2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xerces.internal.parsers;
22 
23 import com.sun.org.apache.xerces.internal.impl.Constants;
24 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
25 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
26 import com.sun.org.apache.xerces.internal.util.SymbolTable;
27 import com.sun.org.apache.xerces.internal.utils.ObjectFactory;
28 import com.sun.org.apache.xerces.internal.xni.XNIException;
29 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
30 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
31 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarLoader;
32 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
33 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
34 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
35 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
36 import java.io.IOException;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.Locale;
40 import java.util.Map;
41 
42 /**
43  * <p> This class provides an easy way for a user to preparse grammars
44  * of various types.  By default, it knows how to preparse external
45  * DTD's and schemas; it provides an easy way for user applications to
46  * register classes that know how to parse additional grammar types.
47  * By default, it does no grammar caching; but it provides ways for
48  * user applications to do so.
49  *
50  * @author Neil Graham, IBM
51  *
52  * @LastModified: Oct 2017
53  */
54 public class XMLGrammarPreparser {
55 
56     //
57     // Constants
58     //
59 
60     // feature:  continue-after-fatal-error
61     private final static String CONTINUE_AFTER_FATAL_ERROR =
62         Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
63 
64     /** Property identifier: symbol table. */
65     protected static final String SYMBOL_TABLE =
66         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
67 
68     /** Property identifier: error reporter. */
69     protected static final String ERROR_REPORTER =
70         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
71 
72     /** Property identifier: error handler. */
73     protected static final String ERROR_HANDLER =
74         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
75 
76     /** Property identifier: entity resolver. */
77     protected static final String ENTITY_RESOLVER =
78         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
79 
80     /** Property identifier: grammar pool . */
81     protected static final String GRAMMAR_POOL =
82         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
83 
84     // the "built-in" grammar loaders
85     private static final Map<String, String> KNOWN_LOADERS;
86 
87     static {
88         Map<String, String> loaders = new HashMap<>();
loaders.put(XMLGrammarDescription.XML_SCHEMA, R)89         loaders.put(XMLGrammarDescription.XML_SCHEMA,
90             "com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader");
loaders.put(XMLGrammarDescription.XML_DTD, R)91         loaders.put(XMLGrammarDescription.XML_DTD,
92             "com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDLoader");
93         KNOWN_LOADERS = Collections.unmodifiableMap(loaders);
94     }
95 
96     /** Recognized properties. */
97     private static final String[] RECOGNIZED_PROPERTIES = {
98         SYMBOL_TABLE,
99         ERROR_REPORTER,
100         ERROR_HANDLER,
101         ENTITY_RESOLVER,
102         GRAMMAR_POOL,
103     };
104 
105     // Data
106     protected SymbolTable fSymbolTable;
107     protected XMLErrorReporter fErrorReporter;
108     protected XMLEntityResolver fEntityResolver;
109     protected XMLGrammarPool fGrammarPool;
110 
111     protected Locale fLocale;
112 
113     // Map holding our loaders
114     private Map<String, XMLGrammarLoader> fLoaders;
115 
116     //
117     // Constructors
118     //
119 
120     /** Default constructor. */
XMLGrammarPreparser()121     public XMLGrammarPreparser() {
122         this(new SymbolTable());
123     } // <init>()
124 
125     /**
126      * Constructs a preparser using the specified symbol table.
127      *
128      * @param symbolTable The symbol table to use.
129      */
XMLGrammarPreparser(SymbolTable symbolTable)130     public XMLGrammarPreparser (SymbolTable symbolTable) {
131         fSymbolTable = symbolTable;
132 
133         fLoaders = new HashMap<>();
134         fErrorReporter = new XMLErrorReporter();
135         setLocale(Locale.getDefault());
136         fEntityResolver = new XMLEntityManager();
137         // those are all the basic properties...
138     } // <init>(SymbolTable)
139 
140     //
141     // Public methods
142     //
143 
144     /*
145     * Register a type of grammar to make it preparsable.   If
146     * the second parameter is null, the parser will use its  built-in
147     * facilities for that grammar type.
148     * This should be called by the application immediately
149     * after creating this object and before initializing any properties/features.
150     * @param type   URI identifying the type of the grammar
151     * @param loader an object capable of preparsing that type; null if the ppreparser should use built-in knowledge.
152     * @return true if successful; false if no built-in knowledge of
153     *       the type or if unable to instantiate the string we know about
154     */
registerPreparser(String grammarType, XMLGrammarLoader loader)155     public boolean registerPreparser(String grammarType, XMLGrammarLoader loader) {
156         if(loader == null) { // none specified!
157             if(KNOWN_LOADERS.containsKey(grammarType)) {
158                 // got one; just instantiate it...
159                 String loaderName = KNOWN_LOADERS.get(grammarType);
160                 try {
161                     XMLGrammarLoader gl = (XMLGrammarLoader)(ObjectFactory.newInstance(loaderName, true));
162                     fLoaders.put(grammarType, gl);
163                 } catch (Exception e) {
164                     return false;
165                 }
166                 return true;
167             }
168             return false;
169         }
170         // were given one
171         fLoaders.put(grammarType, loader);
172         return true;
173     } // registerPreparser(String, XMLGrammarLoader):  boolean
174 
175     /**
176      * Parse a grammar from a location identified by an
177      * XMLInputSource.
178      * This method also adds this grammar to the XMLGrammarPool
179      *
180      * @param type The type of the grammar to be constructed
181      * @param is The XMLInputSource containing this grammar's
182      * information
183      * <strong>If a URI is included in the systemId field, the parser will not expand this URI or make it
184      * available to the EntityResolver</strong>
185      * @return The newly created <code>Grammar</code>.
186      * @exception XNIException thrown on an error in grammar
187      * construction
188      * @exception IOException thrown if an error is encountered
189      * in reading the file
190      */
preparseGrammar(String type, XMLInputSource is)191     public Grammar preparseGrammar(String type, XMLInputSource
192                 is) throws XNIException, IOException {
193         if(fLoaders.containsKey(type)) {
194             XMLGrammarLoader gl = fLoaders.get(type);
195             // make sure gl's been set up with all the "basic" properties:
196             gl.setProperty(SYMBOL_TABLE, fSymbolTable);
197             gl.setProperty(ENTITY_RESOLVER, fEntityResolver);
198             gl.setProperty(ERROR_REPORTER, fErrorReporter);
199             // potentially, not all will support this one...
200             if(fGrammarPool != null) {
201                 try {
202                     gl.setProperty(GRAMMAR_POOL, fGrammarPool);
203                 } catch(Exception e) {
204                     // too bad...
205                 }
206             }
207             return gl.loadGrammar(is);
208         }
209         return null;
210     } // preparseGrammar(String, XMLInputSource):  Grammar
211 
212     /**
213      * Set the locale to use for messages.
214      *
215      * @param locale The locale object to use for localization of messages.
216      *
217      * @exception XNIException Thrown if the parser does not support the
218      *                         specified locale.
219      */
setLocale(Locale locale)220     public void setLocale(Locale locale) {
221         fLocale = locale;
222         fErrorReporter.setLocale(locale);
223     } // setLocale(Locale)
224 
225     /** Return the Locale the XMLGrammarLoader is using. */
getLocale()226     public Locale getLocale() {
227         return fLocale;
228     } // getLocale():  Locale
229 
230 
231     /**
232      * Sets the error handler.
233      *
234      * @param errorHandler The error handler.
235      */
setErrorHandler(XMLErrorHandler errorHandler)236     public void setErrorHandler(XMLErrorHandler errorHandler) {
237         fErrorReporter.setProperty(ERROR_HANDLER, errorHandler);
238     } // setErrorHandler(XMLErrorHandler)
239 
240     /** Returns the registered error handler.  */
getErrorHandler()241     public XMLErrorHandler getErrorHandler() {
242         return fErrorReporter.getErrorHandler();
243     } // getErrorHandler():  XMLErrorHandler
244 
245     /**
246      * Sets the entity resolver.
247      *
248      * @param entityResolver The new entity resolver.
249      */
setEntityResolver(XMLEntityResolver entityResolver)250     public void setEntityResolver(XMLEntityResolver entityResolver) {
251         fEntityResolver = entityResolver;
252     } // setEntityResolver(XMLEntityResolver)
253 
254     /** Returns the registered entity resolver.  */
getEntityResolver()255     public XMLEntityResolver getEntityResolver() {
256         return fEntityResolver;
257     } // getEntityResolver():  XMLEntityResolver
258 
259     /**
260      * Sets the grammar pool.
261      *
262      * @param grammarPool The new grammar pool.
263      */
setGrammarPool(XMLGrammarPool grammarPool)264     public void setGrammarPool(XMLGrammarPool grammarPool) {
265         fGrammarPool = grammarPool;
266     } // setGrammarPool(XMLGrammarPool)
267 
268     /** Returns the registered grammar pool.  */
getGrammarPool()269     public XMLGrammarPool getGrammarPool() {
270         return fGrammarPool;
271     } // getGrammarPool():  XMLGrammarPool
272 
273     // it's possible the application may want access to a certain loader to do
274     // some custom work.
getLoader(String type)275     public XMLGrammarLoader getLoader(String type) {
276         return fLoaders.get(type);
277     } // getLoader(String):  XMLGrammarLoader
278 
279     // set a feature.  This method tries to set it on all
280     // registered loaders; it eats any resulting exceptions.  If
281     // an app needs to know if a particular feature is supported
282     // by a grammar loader of a particular type, it will have
283     // to retrieve that loader and use the loader's setFeature method.
setFeature(String featureId, boolean value)284     public void setFeature(String featureId, boolean value) {
285         for (Map.Entry<String, XMLGrammarLoader> entry : fLoaders.entrySet()) {
286             try {
287                 XMLGrammarLoader gl = entry.getValue();
288                 gl.setFeature(featureId, value);
289             } catch(Exception e) {
290                 // eat it up...
291             }
292         }
293         // since our error reporter is a property we set later,
294         // make sure features it understands are also set.
295         if(featureId.equals(CONTINUE_AFTER_FATAL_ERROR)) {
296             fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, value);
297         }
298     } //setFeature(String, boolean)
299 
300     // set a property.  This method tries to set it on all
301     // registered loaders; it eats any resulting exceptions.  If
302     // an app needs to know if a particular property is supported
303     // by a grammar loader of a particular type, it will have
304     // to retrieve that loader and use the loader's setProperty method.
305     // <p> <strong>An application should use the explicit method
306     // in this class to set "standard" properties like error handler etc.</strong>
setProperty(String propId, Object value)307     public void setProperty(String propId, Object value) {
308         for (Map.Entry<String, XMLGrammarLoader> entry : fLoaders.entrySet()) {
309             try {
310                 XMLGrammarLoader gl = entry.getValue();
311                 gl.setProperty(propId, value);
312             } catch(Exception e) {
313                 // eat it up...
314             }
315         }
316     } //setProperty(String, Object)
317 
318     // get status of feature in a particular loader.  This
319     // catches no exceptions--including NPE's--so the application had
320     // better make sure the loader exists and knows about this feature.
321     // @param type type of grammar to look for the feature in.
322     // @param featureId the feature string to query.
323     // @return the value of the feature.
getFeature(String type, String featureId)324     public boolean getFeature(String type, String featureId) {
325         XMLGrammarLoader gl = fLoaders.get(type);
326         return gl.getFeature(featureId);
327     } // getFeature (String, String):  boolean
328 
329     // get status of property in a particular loader.  This
330     // catches no exceptions--including NPE's--so the application had
331     // better make sure the loader exists and knows about this property.
332     // <strong>For standard properties--that will be supported
333     // by all loaders--the specific methods should be queried!</strong>
334     // @param type type of grammar to look for the property in.
335     // @param propertyId the property string to query.
336     // @return the value of the property.
getProperty(String type, String propertyId)337     public Object getProperty(String type, String propertyId) {
338         XMLGrammarLoader gl = fLoaders.get(type);
339         return gl.getProperty(propertyId);
340     } // getProperty(String, String):  Object
341 } // class XMLGrammarPreparser
342