1 /*
2  * Copyright (c) 2010, 2019, 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.util;
22 
23 import com.sun.org.apache.xerces.internal.impl.Constants;
24 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
25 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 
32 /**
33  * This class implements the basic operations for managing parser
34  * configuration features and properties. This utility class can
35  * be used as a base class for parser configurations or separately
36  * to encapsulate a number of parser settings as a component
37  * manager.
38  * <p>
39  * This class can be constructed with a "parent" settings object
40  * (in the form of an <code>XMLComponentManager</code>) that allows
41  * parser configuration settings to be "chained" together.
42  *
43  * @author Andy Clark, IBM
44  *
45  * @LastModified: Apr 2019
46  */
47 public class ParserConfigurationSettings
48     implements XMLComponentManager {
49 
50         protected static final String PARSER_SETTINGS =
51                         Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
52 
53     //
54     // Data
55     //
56 
57     // data
58 
59     /** Recognized properties. */
60     protected List<String> fRecognizedProperties;
61 
62     /** Properties. */
63     protected Map<String, Object> fProperties;
64 
65     /** Recognized features. */
66     protected List<String> fRecognizedFeatures;
67 
68     /** Features. */
69     protected Map<String, Boolean> fFeatures;
70 
71     /** Parent parser configuration settings. */
72     protected XMLComponentManager fParentSettings;
73 
74     //
75     // Constructors
76     //
77 
78     /** Default Constructor. */
ParserConfigurationSettings()79     public ParserConfigurationSettings() {
80         this(null);
81     } // <init>()
82 
83     /**
84      * Constructs a parser configuration settings object with a
85      * parent settings object.
86      */
ParserConfigurationSettings(XMLComponentManager parent)87     public ParserConfigurationSettings(XMLComponentManager parent) {
88 
89         // create storage for recognized features and properties
90         fRecognizedFeatures = new ArrayList<>();
91         fRecognizedProperties = new ArrayList<>();
92 
93         // create table for features and properties
94         fFeatures = new HashMap<>();
95         fProperties = new HashMap<>();
96 
97         // save parent
98         fParentSettings = parent;
99 
100     } // <init>(XMLComponentManager)
101 
102     //
103     // XMLParserConfiguration methods
104     //
105 
106     /**
107      * Allows a parser to add parser specific features to be recognized
108      * and managed by the parser configuration.
109      *
110      * @param featureIds An array of the additional feature identifiers
111      *                   to be recognized.
112      */
addRecognizedFeatures(String[] featureIds)113     public void addRecognizedFeatures(String[] featureIds) {
114 
115         // add recognized features
116         int featureIdsCount = featureIds != null ? featureIds.length : 0;
117         for (int i = 0; i < featureIdsCount; i++) {
118             String featureId = featureIds[i];
119             if (!fRecognizedFeatures.contains(featureId)) {
120                 fRecognizedFeatures.add(featureId);
121             }
122         }
123 
124     } // addRecognizedFeatures(String[])
125 
126     /**
127      * Set the state of a feature.
128      *
129      * Set the state of any feature in a SAX2 parser.  The parser
130      * might not recognize the feature, and if it does recognize
131      * it, it might not be able to fulfill the request.
132      *
133      * @param featureId The unique identifier (URI) of the feature.
134      * @param state The requested state of the feature (true or false).
135      *
136      * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the
137      *            requested feature is not known.
138      */
setFeature(String featureId, boolean state)139     public void setFeature(String featureId, boolean state)
140         throws XMLConfigurationException {
141 
142         // check and store
143         FeatureState checkState = checkFeature(featureId);
144         if (checkState.isExceptional()) {
145             throw new XMLConfigurationException(checkState.status, featureId);
146         }
147 
148         fFeatures.put(featureId, state);
149     } // setFeature(String,boolean)
150 
151     /**
152      * Allows a parser to add parser specific properties to be recognized
153      * and managed by the parser configuration.
154      *
155      * @param propertyIds An array of the additional property identifiers
156      *                    to be recognized.
157      */
addRecognizedProperties(String[] propertyIds)158     public void addRecognizedProperties(String[] propertyIds) {
159         fRecognizedProperties.addAll(Arrays.asList(propertyIds));
160     } // addRecognizedProperties(String[])
161 
162     /**
163      * setProperty
164      *
165      * @param propertyId
166      * @param value
167      * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the
168      *            requested feature is not known.
169      */
setProperty(String propertyId, Object value)170     public void setProperty(String propertyId, Object value)
171         throws XMLConfigurationException {
172 
173         // check and store
174         PropertyState checkState = checkProperty(propertyId);
175         if (checkState.isExceptional()) {
176             throw new XMLConfigurationException(checkState.status, propertyId);
177         }
178         fProperties.put(propertyId, value);
179 
180     } // setProperty(String,Object)
181 
182     //
183     // XMLComponentManager methods
184     //
185 
186     /**
187      * Returns the state of a feature.
188      *
189      * @param featureId The feature identifier.
190                  * @return true if the feature is supported
191      *
192      * @throws XMLConfigurationException Thrown for configuration error.
193      *                                   In general, components should
194      *                                   only throw this exception if
195      *                                   it is <strong>really</strong>
196      *                                   a critical error.
197      */
198     @Override
getFeature(String featureId)199     public boolean getFeature(String featureId)
200         throws XMLConfigurationException {
201 
202         FeatureState state = getFeatureState(featureId);
203         if (state.isExceptional()) {
204             throw new XMLConfigurationException(state.status, featureId);
205         }
206         return state.state;
207     } // getFeature(String):boolean
208 
209     @Override
getFeature(String featureId, boolean defaultValue)210     public final boolean getFeature(String featureId, boolean defaultValue) {
211         FeatureState state = getFeatureState(featureId);
212         if (state.isExceptional()) {
213             return defaultValue;
214         }
215         return state.state;
216     }
217 
218     @Override
getFeatureState(String featureId)219     public FeatureState getFeatureState(String featureId) {
220         Boolean state = fFeatures.get(featureId);
221 
222         if (state == null) {
223             FeatureState checkState = checkFeature(featureId);
224             if (checkState.isExceptional()) {
225                 return checkState;
226         }
227             return FeatureState.is(false);
228         }
229         return FeatureState.is(state);
230     }
231 
232     /**
233      * Returns the value of a property.
234      *
235      * @param propertyId The property identifier.
236                  * @return the value of the property
237      *
238      * @throws XMLConfigurationException Thrown for configuration error.
239      *                                   In general, components should
240      *                                   only throw this exception if
241      *                                   it is <strong>really</strong>
242      *                                   a critical error.
243      */
244     @Override
getProperty(String propertyId)245     public Object getProperty(String propertyId)
246         throws XMLConfigurationException {
247 
248         PropertyState state = getPropertyState(propertyId);
249         if (state.isExceptional()) {
250             throw new XMLConfigurationException(state.status, propertyId);
251         }
252 
253         return state.state;
254     } // getProperty(String):Object
255 
256     @Override
getProperty(String propertyId, Object defaultValue)257     public final Object getProperty(String propertyId, Object defaultValue) {
258         PropertyState state = getPropertyState(propertyId);
259         if (state.isExceptional()) {
260             return defaultValue;
261         }
262 
263         return state.state;
264     }
265 
266     @Override
getPropertyState(String propertyId)267     public PropertyState getPropertyState(String propertyId) {
268         Object propertyValue = fProperties.get(propertyId);
269 
270         if (propertyValue == null) {
271             PropertyState state = checkProperty(propertyId);
272             if (state.isExceptional()) {
273                 return state;
274         }
275         }
276 
277         return PropertyState.is(propertyValue);
278     }
279 
280     //
281     // Protected methods
282     //
283 
284     /**
285      * Check a feature. If feature is known and supported, this method simply
286      * returns. Otherwise, the appropriate exception is thrown.
287      *
288      * @param featureId The unique identifier (URI) of the feature.
289      *
290      * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the
291      *            requested feature is not known.
292      */
checkFeature(String featureId)293     protected FeatureState checkFeature(String featureId)
294         throws XMLConfigurationException {
295 
296         // check feature
297         if (!fRecognizedFeatures.contains(featureId)) {
298             if (fParentSettings != null) {
299                 return fParentSettings.getFeatureState(featureId);
300             }
301             else {
302                 return FeatureState.NOT_RECOGNIZED;
303             }
304         }
305 
306         // TODO: reasonable default?
307         return FeatureState.RECOGNIZED;
308     } // checkFeature(String)
309 
310     /**
311      * Check a property. If the property is known and supported, this method
312      * simply returns. Otherwise, the appropriate exception is thrown.
313      *
314      * @param propertyId The unique identifier (URI) of the property
315      *                   being set.
316      * @return the PropertyState
317      * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the
318      *            requested feature is not known.
319      */
checkProperty(String propertyId)320     protected PropertyState checkProperty(String propertyId)
321         throws XMLConfigurationException {
322 
323         // check property
324         if (!fRecognizedProperties.contains(propertyId)) {
325             if (fParentSettings != null) {
326                 PropertyState state = fParentSettings.getPropertyState(propertyId);
327                 if (state.isExceptional()) {
328                     return state;
329             }
330             }
331             else {
332                 return PropertyState.NOT_RECOGNIZED;
333             }
334         }
335         return PropertyState.RECOGNIZED;
336     } // checkProperty(String)
337 
338 } // class ParserConfigurationSettings
339