1/*
2 * Copyright (c) 2002 World Wide Web Consortium,
3 * (Massachusetts Institute of Technology, Institut National de
4 * Recherche en Informatique et en Automatique, Keio University). All
5 * Rights Reserved. This program is distributed under the W3C's Software
6 * Intellectual Property License. This program is distributed in the
7 * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
8 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9 * PURPOSE.
10 * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
11 */
12
13package org.w3c.domts;
14
15import java.lang.reflect.Constructor;
16import java.lang.reflect.InvocationTargetException;
17import java.lang.reflect.Method;
18
19import javax.xml.parsers.ParserConfigurationException;
20import javax.xml.parsers.SAXParser;
21import javax.xml.parsers.SAXParserFactory;
22
23import org.w3c.dom.DOMImplementation;
24import org.w3c.dom.Document;
25import org.xml.sax.AttributeList;
26import org.xml.sax.Attributes;
27import org.xml.sax.DocumentHandler;
28import org.xml.sax.SAXException;
29import org.xml.sax.helpers.DefaultHandler;
30
31/**
32 *   This class implements the generic parser and configuation
33 *   abstract class the HTML DOM implementation in Xerces-J
34 */
35public class XercesHTMLDocumentBuilderFactory
36    extends DOMTestDocumentBuilderFactory {
37
38  private SAXParserFactory factory;
39  private Constructor htmlBuilderConstructor;
40  private Method getHTMLDocumentMethod;
41  private DOMImplementation domImpl;
42  private static final Class[] NO_CLASSES = new Class[0];
43  private static final Object[] NO_OBJECTS = new Object[0];
44
45  /**
46   * Creates a implementation of DOMTestDocumentBuilderFactory
47   * using org.apache.html.dom.HTMLBuilder
48   * @param settings array of settings, may be null.
49   */
50  public XercesHTMLDocumentBuilderFactory(DocumentBuilderSetting[] settings) throws
51      DOMTestIncompatibleException {
52    super(settings);
53
54    try {
55      ClassLoader classLoader = ClassLoader.getSystemClassLoader();
56      Class htmlBuilderClass =
57          classLoader.loadClass("org.apache.html.dom.HTMLBuilder");
58
59      htmlBuilderConstructor =
60          htmlBuilderClass.getConstructor(NO_CLASSES);
61
62      getHTMLDocumentMethod =
63          htmlBuilderClass.getMethod("getHTMLDocument", NO_CLASSES);
64
65      Class htmlDOMImpl =
66          classLoader.loadClass(
67          "org.apache.html.dom.HTMLDOMImplementationImpl");
68      Method method =
69          htmlDOMImpl.getMethod("getHTMLDOMImplementation", NO_CLASSES);
70      domImpl = (DOMImplementation) method.invoke(null, NO_OBJECTS);
71
72      Class saxFactoryClass =
73          classLoader.loadClass(
74          "org.apache.xerces.jaxp.SAXParserFactoryImpl");
75      factory = (SAXParserFactory) saxFactoryClass.newInstance();
76    }
77    catch (InvocationTargetException ex) {
78      throw new DOMTestIncompatibleException(
79          ex.getTargetException(),
80          null);
81    }
82    catch (Exception ex) {
83      throw new DOMTestIncompatibleException(ex, null);
84    }
85
86    //
87    //    apply settings to selected document builder
88    //         may throw exception if incompatible
89    if (settings != null) {
90      for (int i = 0; i < settings.length; i++) {
91        //        settings[i].applySetting(factory);
92      }
93    }
94    try {
95      factory.newSAXParser();
96    }
97    catch (ParserConfigurationException ex) {
98      throw new DOMTestIncompatibleException(ex, null);
99    }
100    catch (SAXException ex) {
101      throw new DOMTestIncompatibleException(ex, null);
102    }
103  }
104
105  public DOMTestDocumentBuilderFactory newInstance(DocumentBuilderSetting[]
106      newSettings) throws DOMTestIncompatibleException {
107    if (newSettings == null) {
108      return this;
109    }
110    DocumentBuilderSetting[] mergedSettings = mergeSettings(newSettings);
111    return new XercesHTMLDocumentBuilderFactory(mergedSettings);
112  }
113
114  private class HTMLHandler
115      extends DefaultHandler
116      implements AttributeList {
117    private final DocumentHandler htmlBuilder;
118    private final Method getHTMLDocumentMethod;
119    private Attributes currentAttributes;
120
121    public HTMLHandler(
122        Constructor htmlBuilderConstructor,
123        Method getHTMLDocumentMethod) throws Exception {
124      htmlBuilder =
125          (DocumentHandler) htmlBuilderConstructor.newInstance(
126          new Object[0]);
127      this.getHTMLDocumentMethod = getHTMLDocumentMethod;
128    }
129
130    public void startDocument() throws SAXException {
131      htmlBuilder.startDocument();
132    }
133
134    public void endDocument() throws SAXException {
135      htmlBuilder.endDocument();
136    }
137
138    public void startElement(
139        String uri,
140        String localName,
141        String qName,
142        Attributes attributes) throws SAXException {
143      currentAttributes = attributes;
144      htmlBuilder.startElement(qName, this);
145    }
146
147    public void endElement(String uri, String localName, String qName) throws
148        SAXException {
149      htmlBuilder.endElement(qName);
150    }
151
152    public void characters(char ch[], int start, int length) throws
153        SAXException {
154      htmlBuilder.characters(ch, start, length);
155    }
156
157    public void ignorableWhitespace(char ch[], int start, int length) throws
158        SAXException {
159      htmlBuilder.ignorableWhitespace(ch, start, length);
160    }
161
162    public void processingInstruction(String target, String data) throws
163        SAXException {
164      htmlBuilder.processingInstruction(target, data);
165    }
166
167    public Document getHTMLDocument() throws Exception {
168      return (Document) getHTMLDocumentMethod.invoke(
169          htmlBuilder,
170          NO_OBJECTS);
171    }
172
173    public int getLength() {
174      return currentAttributes.getLength();
175    }
176
177    public String getName(int i) {
178      return currentAttributes.getQName(i);
179    }
180
181    public String getType(int i) {
182      return currentAttributes.getType(i);
183    }
184
185    public String getValue(int i) {
186      return currentAttributes.getValue(i);
187    }
188
189    public String getType(String name) {
190      return currentAttributes.getType(name);
191    }
192
193    public String getValue(String name) {
194      return currentAttributes.getValue(name);
195    }
196
197  }
198
199  public Document load(java.net.URL url) throws DOMTestLoadException {
200    Document doc = null;
201    try {
202      SAXParser parser = factory.newSAXParser();
203      HTMLHandler handler =
204          new HTMLHandler(htmlBuilderConstructor, getHTMLDocumentMethod);
205      parser.parse(url.toString(), handler);
206      doc = handler.getHTMLDocument();
207    }
208    catch (Exception ex) {
209      throw new DOMTestLoadException(ex);
210    }
211    return doc;
212  }
213
214  public DOMImplementation getDOMImplementation() {
215    return domImpl;
216  }
217
218  public boolean hasFeature(String feature, String version) {
219    return domImpl.hasFeature(feature, version);
220  }
221
222  public boolean isCoalescing() {
223    return false;
224  }
225
226  public boolean isExpandEntityReferences() {
227    return false;
228  }
229
230  public boolean isIgnoringElementContentWhitespace() {
231    return false;
232  }
233
234  public boolean isNamespaceAware() {
235    return factory.isNamespaceAware();
236  }
237
238  public boolean isValidating() {
239    return factory.isValidating();
240  }
241
242  public static DocumentBuilderSetting[] getConfiguration1() {
243    return new DocumentBuilderSetting[] {
244        DocumentBuilderSetting.notCoalescing,
245        DocumentBuilderSetting.notExpandEntityReferences,
246        DocumentBuilderSetting.notIgnoringElementContentWhitespace,
247        DocumentBuilderSetting.notNamespaceAware,
248        DocumentBuilderSetting.notValidating};
249  }
250
251  public static DocumentBuilderSetting[] getConfiguration2() {
252    return new DocumentBuilderSetting[] {
253        DocumentBuilderSetting.notCoalescing,
254        DocumentBuilderSetting.expandEntityReferences,
255        DocumentBuilderSetting.ignoringElementContentWhitespace,
256        DocumentBuilderSetting.namespaceAware,
257        DocumentBuilderSetting.validating};
258
259  }
260
261}
262