2 * Copyright (c) 2004 World Wide Web Consortium,
4 * (Massachusetts Institute of Technology, European Research Consortium for
5 * Informatics and Mathematics, Keio University). All Rights Reserved. This
6 * work is distributed under the W3C(r) Software License [1] in the hope that
7 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
8 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
14 package org.w3c.dom.bootstrap;
16 import java.util.StringTokenizer;
17 import java.util.Vector;
18 import org.w3c.dom.DOMImplementationSource;
19 import org.w3c.dom.DOMImplementationList;
20 import org.w3c.dom.DOMImplementation;
21 import java.io.InputStream;
22 import java.io.BufferedReader;
23 import java.io.InputStreamReader;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
28 * A factory that enables applications to obtain instances of
29 * <code>DOMImplementation</code>.
35 * <pre class='example'>
36 * // get an instance of the DOMImplementation registry
37 * DOMImplementationRegistry registry =
38 * DOMImplementationRegistry.newInstance();
39 * // get a DOM implementation the Level 3 XML module
40 * DOMImplementation domImpl =
41 * registry.getDOMImplementation("XML 3.0");
45 * This provides an application with an implementation-independent starting
46 * point. DOM implementations may modify this class to meet new security
47 * standards or to provide *additional* fallbacks for the list of
48 * DOMImplementationSources.
51 * @see DOMImplementation
52 * @see DOMImplementationSource
55 public final class DOMImplementationRegistry {
57 * The system property to specify the
58 * DOMImplementationSource class names.
60 public static final String PROPERTY =
61 "org.w3c.dom.DOMImplementationSourceList";
64 * Default columns per line.
66 private static final int DEFAULT_LINE_LENGTH = 80;
69 * The list of DOMImplementationSources.
71 private Vector sources;
74 * Private constructor.
75 * @param srcs Vector List of DOMImplementationSources
77 private DOMImplementationRegistry(final Vector srcs) {
82 * Obtain a new instance of a <code>DOMImplementationRegistry</code>.
85 * The <code>DOMImplementationRegistry</code> is initialized by the
86 * application or the implementation, depending on the context, by
87 * first checking the value of the Java system property
88 * <code>org.w3c.dom.DOMImplementationSourceList</code> and
89 * the the service provider whose contents are at
90 * "<code>META_INF/services/org.w3c.dom.DOMImplementationSourceList</code>"
91 * The value of this property is a white-space separated list of
92 * names of availables classes implementing the
93 * <code>DOMImplementationSource</code> interface. Each class listed
94 * in the class name list is instantiated and any exceptions
95 * encountered are thrown to the application.
97 * @return an initialized instance of DOMImplementationRegistry
98 * @throws ClassNotFoundException
99 * If any specified class can not be found
100 * @throws InstantiationException
101 * If any specified class is an interface or abstract class
102 * @throws IllegalAccessException
103 * If the default constructor of a specified class is not accessible
104 * @throws ClassCastException
105 * If any specified class does not implement
106 * <code>DOMImplementationSource</code>
108 public static DOMImplementationRegistry newInstance()
110 ClassNotFoundException,
111 InstantiationException,
112 IllegalAccessException,
114 Vector sources = new Vector();
116 ClassLoader classLoader = getClassLoader();
117 // fetch system property:
118 String p = getSystemProperty(PROPERTY);
121 // if property is not specified then use contents of
122 // META_INF/org.w3c.dom.DOMImplementationSourceList from classpath
124 p = getServiceValue(classLoader);
128 // DOM Implementations can modify here to add *additional* fallback
129 // mechanisms to access a list of default DOMImplementationSources.
130 p = "gnu.xml.dom.ImplementationSource";
133 StringTokenizer st = new StringTokenizer(p);
134 while (st.hasMoreTokens()) {
135 String sourceName = st.nextToken();
136 // Use context class loader, falling back to Class.forName
137 // if and only if this fails...
138 Class sourceClass = null;
139 if (classLoader != null) {
140 sourceClass = classLoader.loadClass(sourceName);
142 sourceClass = Class.forName(sourceName);
144 DOMImplementationSource source =
145 (DOMImplementationSource) sourceClass.newInstance();
146 sources.addElement(source);
149 return new DOMImplementationRegistry(sources);
153 * Return the first implementation that has the desired
154 * features, or <code>null</code> if none is found.
157 * A string that specifies which features are required. This is
158 * a space separated list in which each feature is specified by
159 * its name optionally followed by a space and a version number.
160 * This is something like: "XML 1.0 Traversal +Events 2.0"
161 * @return An implementation that has the desired features,
162 * or <code>null</code> if none found.
164 public DOMImplementation getDOMImplementation(final String features) {
165 int size = sources.size();
167 for (int i = 0; i < size; i++) {
168 DOMImplementationSource source =
169 (DOMImplementationSource) sources.elementAt(i);
170 DOMImplementation impl = source.getDOMImplementation(features);
179 * Return a list of implementations that support the
183 * A string that specifies which features are required. This is
184 * a space separated list in which each feature is specified by
185 * its name optionally followed by a space and a version number.
186 * This is something like: "XML 1.0 Traversal +Events 2.0"
187 * @return A list of DOMImplementations that support the desired features.
189 public DOMImplementationList getDOMImplementationList(final String features) {
190 final Vector implementations = new Vector();
191 int size = sources.size();
192 for (int i = 0; i < size; i++) {
193 DOMImplementationSource source =
194 (DOMImplementationSource) sources.elementAt(i);
195 DOMImplementationList impls =
196 source.getDOMImplementationList(features);
197 for (int j = 0; j < impls.getLength(); j++) {
198 DOMImplementation impl = impls.item(j);
199 implementations.addElement(impl);
202 return new DOMImplementationList() {
203 public DOMImplementation item(final int index) {
204 if (index >= 0 && index < implementations.size()) {
206 return (DOMImplementation)
207 implementations.elementAt(index);
208 } catch (ArrayIndexOutOfBoundsException e) {
215 public int getLength() {
216 return implementations.size();
222 * Register an implementation.
224 * @param s The source to be registered, may not be <code>null</code>
226 public void addSource(final DOMImplementationSource s) {
228 throw new NullPointerException();
230 if (!sources.contains(s)) {
231 sources.addElement(s);
237 * Gets a class loader.
239 * @return A class loader, possibly <code>null</code>
241 private static ClassLoader getClassLoader() {
243 ClassLoader contextClassLoader = getContextClassLoader();
245 if (contextClassLoader != null) {
246 return contextClassLoader;
248 } catch (Exception e) {
249 // Assume that the DOM application is in a JRE 1.1, use the
250 // current ClassLoader
251 return DOMImplementationRegistry.class.getClassLoader();
253 return DOMImplementationRegistry.class.getClassLoader();
257 * This method attempts to return the first line of the resource
258 * META_INF/services/org.w3c.dom.DOMImplementationSourceList
259 * from the provided ClassLoader.
261 * @param classLoader classLoader, may not be <code>null</code>.
262 * @return first line of resource, or <code>null</code>
264 private static String getServiceValue(final ClassLoader classLoader) {
265 String serviceId = "META-INF/services/" + PROPERTY;
266 // try to find services in CLASSPATH
268 InputStream is = getResourceAsStream(classLoader, serviceId);
274 new BufferedReader(new InputStreamReader(is, "UTF-8"),
275 DEFAULT_LINE_LENGTH);
276 } catch (java.io.UnsupportedEncodingException e) {
278 new BufferedReader(new InputStreamReader(is),
279 DEFAULT_LINE_LENGTH);
281 String serviceValue = rd.readLine();
283 if (serviceValue != null && serviceValue.length() > 0) {
287 } catch (Exception ex) {
294 * A simple JRE (Java Runtime Environment) 1.1 test
296 * @return <code>true</code> if JRE 1.1
298 private static boolean isJRE11() {
300 Class c = Class.forName("java.security.AccessController");
301 // java.security.AccessController existed since 1.2 so, if no
302 // exception was thrown, the DOM application is running in a JRE
305 } catch (Exception ex) {
312 * This method returns the ContextClassLoader or <code>null</code> if
313 * running in a JRE 1.1
315 * @return The Context Classloader
317 private static ClassLoader getContextClassLoader() {
321 AccessController.doPrivileged(new PrivilegedAction() {
322 public Object run() {
323 ClassLoader classLoader = null;
326 Thread.currentThread().getContextClassLoader();
327 } catch (SecurityException ex) {
335 * This method returns the system property indicated by the specified name
336 * after checking access control privileges. For a JRE 1.1, this check is
339 * @param name the name of the system property
340 * @return the system property
342 private static String getSystemProperty(final String name) {
344 ? (String) System.getProperty(name)
345 : (String) AccessController.doPrivileged(new PrivilegedAction() {
346 public Object run() {
347 return System.getProperty(name);
353 * This method returns an Inputstream for the reading resource
354 * META_INF/services/org.w3c.dom.DOMImplementationSourceList after checking
355 * access control privileges. For a JRE 1.1, this check is not done.
357 * @param classLoader classLoader
358 * @param name the resource
359 * @return an Inputstream for the resource specified
361 private static InputStream getResourceAsStream(final ClassLoader classLoader,
365 if (classLoader == null) {
366 ris = ClassLoader.getSystemResourceAsStream(name);
368 ris = classLoader.getResourceAsStream(name);
373 AccessController.doPrivileged(new PrivilegedAction() {
374 public Object run() {
376 if (classLoader == null) {
378 ClassLoader.getSystemResourceAsStream(name);
380 ris = classLoader.getResourceAsStream(name);