1 /* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
2 // for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
3 
4 package org.xmlpull.v1;
5 
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.Map;
9 
10 /**
11  * This class is used to create implementations of XML Pull Parser defined in XMPULL V1 API.
12  *
13  * @see XmlPullParser
14  *
15  * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
16  * @author Stefan Haustein
17  */
18 
19 public class XmlPullParserFactory {
20 
21     public static final String PROPERTY_NAME = "org.xmlpull.v1.XmlPullParserFactory";
22     protected ArrayList parserClasses;
23     protected ArrayList serializerClasses;
24 
25     /** Unused, but we have to keep it because it's public API. */
26     protected String classNamesLocation = null;
27 
28     // features are kept there
29     // TODO: This can't be made final because it's a public API.
30     protected HashMap<String, Boolean> features = new HashMap<String, Boolean>();
31 
32     /**
33      * Protected constructor to be called by factory implementations.
34      */
XmlPullParserFactory()35     protected XmlPullParserFactory() {
36         parserClasses = new ArrayList<String>();
37         serializerClasses = new ArrayList<String>();
38 
39         try {
40             parserClasses.add(Class.forName("org.kxml2.io.KXmlParser"));
41             serializerClasses.add(Class.forName("org.kxml2.io.KXmlSerializer"));
42         } catch (ClassNotFoundException e) {
43             throw new AssertionError();
44         }
45     }
46 
47     /**
48      * Set the features to be set when XML Pull Parser is created by this factory.
49      * <p><b>NOTE:</b> factory features are not used for XML Serializer.
50      *
51      * @param name string with URI identifying feature
52      * @param state if true feature will be set; if false will be ignored
53      */
setFeature(String name, boolean state)54     public void setFeature(String name, boolean state) throws XmlPullParserException {
55         features.put(name, state);
56     }
57 
58 
59     /**
60      * Return the current value of the feature with given name.
61      * <p><b>NOTE:</b> factory features are not used for XML Serializer.
62      *
63      * @param name The name of feature to be retrieved.
64      * @return The value of named feature.
65      *     Unknown features are <string>always</strong> returned as false
66      */
getFeature(String name)67     public boolean getFeature(String name) {
68         Boolean value = features.get(name);
69         return value != null ? value.booleanValue() : false;
70     }
71 
72     /**
73      * Specifies that the parser produced by this factory will provide
74      * support for XML namespaces.
75      * By default the value of this is set to false.
76      *
77      * @param awareness true if the parser produced by this code
78      *    will provide support for XML namespaces;  false otherwise.
79      */
setNamespaceAware(boolean awareness)80     public void setNamespaceAware(boolean awareness) {
81         features.put (XmlPullParser.FEATURE_PROCESS_NAMESPACES, awareness);
82     }
83 
84     /**
85      * Indicates whether or not the factory is configured to produce
86      * parsers which are namespace aware
87      * (it simply set feature XmlPullParser.FEATURE_PROCESS_NAMESPACES to true or false).
88      *
89      * @return  true if the factory is configured to produce parsers
90      *    which are namespace aware; false otherwise.
91      */
isNamespaceAware()92     public boolean isNamespaceAware() {
93         return getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
94     }
95 
96     /**
97      * Specifies that the parser produced by this factory will be validating
98      * (it simply set feature XmlPullParser.FEATURE_VALIDATION to true or false).
99      *
100      * By default the value of this is set to false.
101      *
102      * @param validating - if true the parsers created by this factory  must be validating.
103      */
setValidating(boolean validating)104     public void setValidating(boolean validating) {
105         features.put(XmlPullParser.FEATURE_VALIDATION, validating);
106     }
107 
108     /**
109      * Indicates whether or not the factory is configured to produce parsers
110      * which validate the XML content during parse.
111      *
112      * @return   true if the factory is configured to produce parsers
113      * which validate the XML content during parse; false otherwise.
114      */
115 
isValidating()116     public boolean isValidating() {
117         return getFeature(XmlPullParser.FEATURE_VALIDATION);
118     }
119 
120     /**
121      * Creates a new instance of a XML Pull Parser
122      * using the currently configured factory features.
123      *
124      * @return A new instance of a XML Pull Parser.
125      */
newPullParser()126     public XmlPullParser newPullParser() throws XmlPullParserException {
127         final XmlPullParser pp = getParserInstance();
128         for (Map.Entry<String, Boolean> entry : features.entrySet()) {
129             // NOTE: This test is needed for compatibility reasons. We guarantee
130             // that we only set a feature on a parser if its value is true.
131             if (entry.getValue()) {
132                 pp.setFeature(entry.getKey(), entry.getValue());
133             }
134         }
135 
136         return pp;
137     }
138 
getParserInstance()139     private XmlPullParser getParserInstance() throws XmlPullParserException {
140         ArrayList<Exception> exceptions = null;
141 
142         if (parserClasses != null && !parserClasses.isEmpty()) {
143             exceptions = new ArrayList<Exception>();
144             for (Object o : parserClasses) {
145                 try {
146                     if (o != null) {
147                         Class<?> parserClass = (Class<?>) o;
148                         return (XmlPullParser) parserClass.newInstance();
149                     }
150                 } catch (InstantiationException e) {
151                     exceptions.add(e);
152                 } catch (IllegalAccessException e) {
153                     exceptions.add(e);
154                 } catch (ClassCastException e) {
155                     exceptions.add(e);
156                 }
157             }
158         }
159 
160         throw newInstantiationException("Invalid parser class list", exceptions);
161     }
162 
getSerializerInstance()163     private XmlSerializer getSerializerInstance() throws XmlPullParserException {
164         ArrayList<Exception> exceptions = null;
165 
166         if (serializerClasses != null && !serializerClasses.isEmpty()) {
167             exceptions = new ArrayList<Exception>();
168             for (Object o : serializerClasses) {
169                 try {
170                     if (o != null) {
171                         Class<?> serializerClass = (Class<?>) o;
172                         return (XmlSerializer) serializerClass.newInstance();
173                     }
174                 } catch (InstantiationException e) {
175                     exceptions.add(e);
176                 } catch (IllegalAccessException e) {
177                     exceptions.add(e);
178                 } catch (ClassCastException e) {
179                     exceptions.add(e);
180                 }
181             }
182         }
183 
184         throw newInstantiationException("Invalid serializer class list", exceptions);
185     }
186 
newInstantiationException(String message, ArrayList<Exception> exceptions)187     private static XmlPullParserException newInstantiationException(String message,
188             ArrayList<Exception> exceptions) {
189         if (exceptions == null || exceptions.isEmpty()) {
190             return new XmlPullParserException(message);
191         } else {
192             XmlPullParserException exception = new XmlPullParserException(message);
193             for (Exception ex : exceptions) {
194                 exception.addSuppressed(ex);
195             }
196 
197             return exception;
198         }
199     }
200 
201     /**
202      * Creates a new instance of a XML Serializer.
203      *
204      * <p><b>NOTE:</b> factory features are not used for XML Serializer.
205      *
206      * @return A new instance of a XML Serializer.
207      * @throws XmlPullParserException if a parser cannot be created which satisfies the
208      * requested configuration.
209      */
210 
newSerializer()211     public XmlSerializer newSerializer() throws XmlPullParserException {
212         return getSerializerInstance();
213     }
214 
215     /**
216      * Creates a new instance of a PullParserFactory that can be used
217      * to create XML pull parsers. The factory will always return instances
218      * of Android's built-in {@link XmlPullParser} and {@link XmlSerializer}.
219      */
newInstance()220     public static XmlPullParserFactory newInstance () throws XmlPullParserException {
221         return new XmlPullParserFactory();
222     }
223 
224     /**
225      * Creates a factory that always returns instances of Android's built-in
226      * {@link XmlPullParser} and {@link XmlSerializer} implementation. This
227      * <b>does not</b> support factories capable of creating arbitrary parser
228      * and serializer implementations. Both arguments to this method are unused.
229      */
newInstance(String unused, Class unused2)230     public static XmlPullParserFactory newInstance (String unused, Class unused2)
231         throws XmlPullParserException {
232         return newInstance();
233     }
234 }
235