1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.xml;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.xml.Attribute;
28  import com.liferay.portal.kernel.xml.Document;
29  import com.liferay.portal.kernel.xml.DocumentException;
30  import com.liferay.portal.kernel.xml.Element;
31  import com.liferay.portal.kernel.xml.Entity;
32  import com.liferay.portal.kernel.xml.Namespace;
33  import com.liferay.portal.kernel.xml.Node;
34  import com.liferay.portal.kernel.xml.ProcessingInstruction;
35  import com.liferay.portal.kernel.xml.QName;
36  import com.liferay.portal.kernel.xml.SAXReader;
37  import com.liferay.portal.kernel.xml.Text;
38  import com.liferay.portal.kernel.xml.XPath;
39  import com.liferay.portal.util.EntityResolver;
40  import com.liferay.util.xml.XMLSafeReader;
41  
42  import java.io.File;
43  import java.io.InputStream;
44  import java.io.Reader;
45  
46  import java.net.MalformedURLException;
47  import java.net.URL;
48  
49  import java.util.ArrayList;
50  import java.util.List;
51  import java.util.Map;
52  
53  import org.dom4j.DocumentFactory;
54  import org.dom4j.DocumentHelper;
55  
56  /**
57   * <a href="SAXReaderImpl.java.html"><b><i>View Source</i></b></a>
58   *
59   * @author Brian Wing Shun Chan
60   *
61   */
62  public class SAXReaderImpl implements SAXReader {
63  
64      public static List<Attribute> toNewAttributes(
65          List<org.dom4j.Attribute> oldAttributes) {
66  
67          List<Attribute> newAttributes = new ArrayList<Attribute>(
68              oldAttributes.size());
69  
70          for (org.dom4j.Attribute oldAttribute : oldAttributes) {
71              newAttributes.add(new AttributeImpl(oldAttribute));
72          }
73  
74          return new NodeList<Attribute, org.dom4j.Attribute>(
75              newAttributes, oldAttributes);
76      }
77  
78      public static List<Element> toNewElements(
79          List<org.dom4j.Element> oldElements) {
80  
81          List<Element> newElements = new ArrayList<Element>(oldElements.size());
82  
83          for (org.dom4j.Element oldElement : oldElements) {
84              newElements.add(new ElementImpl(oldElement));
85          }
86  
87          return new NodeList<Element, org.dom4j.Element>(
88              newElements, oldElements);
89      }
90  
91      public static List<Namespace> toNewNamespaces(
92          List<org.dom4j.Namespace> oldNamespaces) {
93  
94          List<Namespace> newNamespaces = new ArrayList<Namespace>(
95              oldNamespaces.size());
96  
97          for (org.dom4j.Namespace oldNamespace : oldNamespaces) {
98              newNamespaces.add(new NamespaceImpl(oldNamespace));
99          }
100 
101         return new NodeList<Namespace, org.dom4j.Namespace>(
102             newNamespaces, oldNamespaces);
103     }
104 
105     public static List<Node> toNewNodes(List<org.dom4j.Node> oldNodes) {
106         List<Node> newNodes = new ArrayList<Node>(oldNodes.size());
107 
108         for (org.dom4j.Node oldNode : oldNodes) {
109             if (oldNode instanceof org.dom4j.Element) {
110                 newNodes.add(new ElementImpl((org.dom4j.Element)oldNode));
111             }
112             else {
113                 newNodes.add(new NodeImpl(oldNode));
114             }
115         }
116 
117         return new NodeList<Node, org.dom4j.Node>(newNodes, oldNodes);
118     }
119 
120     public static List<ProcessingInstruction> toNewProcessingInstructions(
121         List<org.dom4j.ProcessingInstruction> oldProcessingInstructions) {
122 
123         List<ProcessingInstruction> newProcessingInstructions =
124             new ArrayList<ProcessingInstruction>(
125                 oldProcessingInstructions.size());
126 
127         for (org.dom4j.ProcessingInstruction oldProcessingInstruction :
128                 oldProcessingInstructions) {
129 
130             newProcessingInstructions.add(
131                 new ProcessingInstructionImpl(oldProcessingInstruction));
132         }
133 
134         return new NodeList
135             <ProcessingInstruction, org.dom4j.ProcessingInstruction>(
136                 newProcessingInstructions, oldProcessingInstructions);
137     }
138 
139     public static List<org.dom4j.Attribute> toOldAttributes(
140         List<Attribute> newAttributes) {
141 
142         List<org.dom4j.Attribute> oldAttributes =
143             new ArrayList<org.dom4j.Attribute>(newAttributes.size());
144 
145         for (Attribute newAttribute : newAttributes) {
146             AttributeImpl newAttributeImpl = (AttributeImpl)newAttribute;
147 
148             oldAttributes.add(newAttributeImpl.getWrappedAttribute());
149         }
150 
151         return oldAttributes;
152     }
153 
154     public static List<org.dom4j.Node> toOldNodes(List<Node> newNodes) {
155         List<org.dom4j.Node> oldNodes = new ArrayList<org.dom4j.Node>(
156             newNodes.size());
157 
158         for (Node newNode : newNodes) {
159             NodeImpl newNodeImpl = (NodeImpl)newNode;
160 
161             oldNodes.add(newNodeImpl.getWrappedNode());
162         }
163 
164         return oldNodes;
165     }
166 
167     public static List<org.dom4j.ProcessingInstruction>
168         toOldProcessingInstructions(
169             List<ProcessingInstruction> newProcessingInstructions) {
170 
171         List<org.dom4j.ProcessingInstruction> oldProcessingInstructions =
172             new ArrayList<org.dom4j.ProcessingInstruction>(
173                 newProcessingInstructions.size());
174 
175         for (ProcessingInstruction newProcessingInstruction :
176                 newProcessingInstructions) {
177 
178             ProcessingInstructionImpl newProcessingInstructionImpl =
179                 (ProcessingInstructionImpl)newProcessingInstruction;
180 
181             oldProcessingInstructions.add(
182                 newProcessingInstructionImpl.getWrappedProcessingInstruction());
183         }
184 
185         return oldProcessingInstructions;
186     }
187 
188     public Attribute createAttribute(
189         Element element, QName qName, String value) {
190 
191         ElementImpl elementImpl = (ElementImpl)element;
192         QNameImpl qNameImpl = (QNameImpl)qName;
193 
194         DocumentFactory documentFactory = DocumentFactory.getInstance();
195 
196         return new AttributeImpl(
197             documentFactory.createAttribute(
198                 elementImpl.getWrappedElement(), qNameImpl.getWrappedQName(),
199                 value));
200     }
201 
202     public Attribute createAttribute(
203         Element element, String name, String value) {
204 
205         ElementImpl elementImpl = (ElementImpl)element;
206 
207         DocumentFactory documentFactory = DocumentFactory.getInstance();
208 
209         return new AttributeImpl(
210             documentFactory.createAttribute(
211                 elementImpl.getWrappedElement(), name, value));
212     }
213 
214     public Document createDocument() {
215         return new DocumentImpl(DocumentHelper.createDocument());
216     }
217 
218     public Document createDocument(Element rootElement) {
219         ElementImpl rootElementImpl = (ElementImpl)rootElement;
220 
221         return new DocumentImpl(
222             DocumentHelper.createDocument(rootElementImpl.getWrappedElement()));
223     }
224 
225     public Document createDocument(String encoding) {
226         DocumentFactory documentFactory = DocumentFactory.getInstance();
227 
228         return new DocumentImpl(documentFactory.createDocument(encoding));
229     }
230 
231     public Element createElement(QName qName) {
232         QNameImpl qNameImpl = (QNameImpl)qName;
233 
234         return new ElementImpl(
235             DocumentHelper.createElement(qNameImpl.getWrappedQName()));
236     }
237 
238     public Element createElement(String name) {
239         return new ElementImpl(DocumentHelper.createElement(name));
240     }
241 
242     public Entity createEntity(String name, String text) {
243         return new EntityImpl(DocumentHelper.createEntity(name, text));
244     }
245 
246     public Namespace createNamespace(String uri) {
247         return new NamespaceImpl(org.dom4j.Namespace.get(uri));
248     }
249 
250     public Namespace createNamespace(String prefix, String uri) {
251         return new NamespaceImpl(DocumentHelper.createNamespace(prefix, uri));
252     }
253 
254     public ProcessingInstruction createProcessingInstruction(
255         String target, Map<String, String> data) {
256 
257         org.dom4j.ProcessingInstruction processingInstruction =
258             DocumentHelper.createProcessingInstruction(target, data);
259 
260         if (processingInstruction == null) {
261             return null;
262         }
263         else {
264             return new ProcessingInstructionImpl(processingInstruction);
265         }
266     }
267 
268     public ProcessingInstruction createProcessingInstruction(
269         String target, String data) {
270 
271         org.dom4j.ProcessingInstruction processingInstruction =
272             DocumentHelper.createProcessingInstruction(target, data);
273 
274         if (processingInstruction == null) {
275             return null;
276         }
277         else {
278             return new ProcessingInstructionImpl(processingInstruction);
279         }
280     }
281 
282     public QName createQName(String localName) {
283         return new QNameImpl(DocumentHelper.createQName(localName));
284     }
285 
286     public QName createQName(String localName, Namespace namespace) {
287         NamespaceImpl namespaceImpl = (NamespaceImpl)namespace;
288 
289         return new QNameImpl(
290             DocumentHelper.createQName(
291                 localName, namespaceImpl.getWrappedNamespace()));
292     }
293 
294     public Text createText(String text) {
295         return new TextImpl(DocumentHelper.createText(text));
296     }
297 
298     public XPath createXPath(String xpathExpression) {
299         return new XPathImpl(DocumentHelper.createXPath(xpathExpression));
300     }
301 
302     public List<Node> selectNodes(
303         String xpathFilterExpression, List<Node> nodes) {
304 
305         return toNewNodes(
306             DocumentHelper.selectNodes(
307                 xpathFilterExpression, toOldNodes(nodes)));
308     }
309 
310     public List<Node> selectNodes(
311         String xpathFilterExpression, Node node) {
312 
313         NodeImpl nodeImpl = (NodeImpl)node;
314 
315         return toNewNodes(
316             DocumentHelper.selectNodes(
317                 xpathFilterExpression, nodeImpl.getWrappedNode()));
318     }
319 
320     public void sort(List<Node> nodes, String xpathExpression) {
321         DocumentHelper.sort(toOldNodes(nodes), xpathExpression);
322     }
323 
324     public void sort(
325         List<Node> nodes, String xpathExpression, boolean distinct) {
326 
327         DocumentHelper.sort(toOldNodes(nodes), xpathExpression, distinct);
328     }
329 
330     public Document read(File file) throws DocumentException {
331         return read(file, false);
332     }
333 
334     public Document read(File file, boolean validate)
335         throws DocumentException {
336 
337         try {
338             org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
339 
340             return new DocumentImpl(saxReader.read(file));
341         }
342         catch (org.dom4j.DocumentException de) {
343             throw new DocumentException(de.getMessage());
344         }
345     }
346 
347     public Document read(InputStream is) throws DocumentException {
348         return read(is, false);
349     }
350 
351     public Document read(InputStream is, boolean validate)
352         throws DocumentException {
353 
354         try {
355             org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
356 
357             return new DocumentImpl(saxReader.read(is));
358         }
359         catch (org.dom4j.DocumentException de) {
360             throw new DocumentException(de.getMessage());
361         }
362     }
363 
364     public Document read(Reader reader) throws DocumentException {
365         return read(reader, false);
366     }
367 
368     public Document read(Reader reader, boolean validate)
369         throws DocumentException {
370 
371         try {
372             org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
373 
374             return new DocumentImpl(saxReader.read(reader));
375         }
376         catch (org.dom4j.DocumentException de) {
377             throw new DocumentException(de.getMessage());
378         }
379     }
380 
381     public Document read(String xml) throws DocumentException {
382         return read(new XMLSafeReader(xml));
383     }
384 
385     public Document read(String xml, boolean validate)
386         throws DocumentException {
387 
388         return read(new XMLSafeReader(xml), validate);
389     }
390 
391     public Document read(URL url) throws DocumentException {
392         return read(url, false);
393     }
394 
395     public Document read(URL url, boolean validate) throws DocumentException {
396         try {
397             org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
398 
399             return new DocumentImpl(saxReader.read(url));
400         }
401         catch (org.dom4j.DocumentException de) {
402             throw new DocumentException(de.getMessage());
403         }
404     }
405 
406     public Document readURL(String url)
407         throws DocumentException, MalformedURLException {
408 
409         return read(new URL(url), false);
410     }
411 
412     public Document readURL(String url, boolean validate)
413         throws DocumentException, MalformedURLException {
414 
415         return read(new URL(url), validate);
416     }
417 
418     protected org.dom4j.io.SAXReader getSAXReader(boolean validate) {
419 
420         // Crimson cannot do XSD validation. See the following links:
421         //
422         // http://www.geocities.com/herong_yang/jdk/xsd_validation.html
423         // http://www.burnthacker.com/archives/000086.html
424         // http://www.theserverside.com/news/thread.tss?thread_id=22525
425 
426         org.dom4j.io.SAXReader reader = null;
427 
428         try {
429             reader = new org.dom4j.io.SAXReader(_SAX_PARSER_IMPL, validate);
430 
431             reader.setEntityResolver(new EntityResolver());
432 
433             reader.setFeature(_FEATURES_VALIDATION, validate);
434             reader.setFeature(_FEATURES_VALIDATION_SCHEMA, validate);
435             reader.setFeature(
436                 _FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, validate);
437             reader.setFeature(_FEATURES_DYNAMIC, validate);
438         }
439         catch (Exception e) {
440             if (_log.isWarnEnabled()) {
441                 _log.warn(
442                     "XSD validation is diasabled because " + e.getMessage());
443             }
444 
445             reader = new org.dom4j.io.SAXReader(validate);
446 
447             reader.setEntityResolver(new EntityResolver());
448         }
449 
450         return reader;
451     }
452 
453     private static final String _SAX_PARSER_IMPL =
454         "org.apache.xerces.parsers.SAXParser";
455 
456     private static final String _FEATURES_VALIDATION =
457         "http://xml.org/sax/features/validation";
458 
459     private static final String _FEATURES_VALIDATION_SCHEMA =
460         "http://apache.org/xml/features/validation/schema";
461 
462     private static final String _FEATURES_VALIDATION_SCHEMA_FULL_CHECKING =
463         "http://apache.org/xml/features/validation/schema-full-checking";
464 
465     private static final String _FEATURES_DYNAMIC =
466         "http://apache.org/xml/features/validation/dynamic";
467 
468     private static Log _log = LogFactoryUtil.getLog(SAXReaderImpl.class);
469 
470 }