001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.xml;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.xml.Attribute;
020    import com.liferay.portal.kernel.xml.Document;
021    import com.liferay.portal.kernel.xml.DocumentException;
022    import com.liferay.portal.kernel.xml.Element;
023    import com.liferay.portal.kernel.xml.Entity;
024    import com.liferay.portal.kernel.xml.Namespace;
025    import com.liferay.portal.kernel.xml.Node;
026    import com.liferay.portal.kernel.xml.ProcessingInstruction;
027    import com.liferay.portal.kernel.xml.QName;
028    import com.liferay.portal.kernel.xml.SAXReader;
029    import com.liferay.portal.kernel.xml.Text;
030    import com.liferay.portal.kernel.xml.XPath;
031    import com.liferay.portal.util.ClassLoaderUtil;
032    import com.liferay.portal.util.EntityResolver;
033    import com.liferay.portal.util.PropsValues;
034    import com.liferay.util.xml.XMLSafeReader;
035    
036    import java.io.File;
037    import java.io.InputStream;
038    import java.io.Reader;
039    
040    import java.net.MalformedURLException;
041    import java.net.URL;
042    
043    import java.util.ArrayList;
044    import java.util.HashMap;
045    import java.util.List;
046    import java.util.Map;
047    
048    import org.apache.xerces.parsers.SAXParser;
049    
050    import org.dom4j.DocumentFactory;
051    import org.dom4j.DocumentHelper;
052    
053    /**
054     * @author Brian Wing Shun Chan
055     */
056    public class SAXReaderImpl implements SAXReader {
057    
058            public static SAXReaderImpl getInstance() {
059                    return _instance;
060            }
061    
062            public static List<Attribute> toNewAttributes(
063                    List<org.dom4j.Attribute> oldAttributes) {
064    
065                    List<Attribute> newAttributes = new ArrayList<Attribute>(
066                            oldAttributes.size());
067    
068                    for (org.dom4j.Attribute oldAttribute : oldAttributes) {
069                            newAttributes.add(new AttributeImpl(oldAttribute));
070                    }
071    
072                    return new NodeList<Attribute, org.dom4j.Attribute>(
073                            newAttributes, oldAttributes);
074            }
075    
076            public static List<Element> toNewElements(
077                    List<org.dom4j.Element> oldElements) {
078    
079                    List<Element> newElements = new ArrayList<Element>(oldElements.size());
080    
081                    for (org.dom4j.Element oldElement : oldElements) {
082                            newElements.add(new ElementImpl(oldElement));
083                    }
084    
085                    return new NodeList<Element, org.dom4j.Element>(
086                            newElements, oldElements);
087            }
088    
089            public static List<Namespace> toNewNamespaces(
090                    List<org.dom4j.Namespace> oldNamespaces) {
091    
092                    List<Namespace> newNamespaces = new ArrayList<Namespace>(
093                            oldNamespaces.size());
094    
095                    for (org.dom4j.Namespace oldNamespace : oldNamespaces) {
096                            newNamespaces.add(new NamespaceImpl(oldNamespace));
097                    }
098    
099                    return new NodeList<Namespace, org.dom4j.Namespace>(
100                            newNamespaces, oldNamespaces);
101            }
102    
103            public static List<Node> toNewNodes(List<org.dom4j.Node> oldNodes) {
104                    List<Node> newNodes = new ArrayList<Node>(oldNodes.size());
105    
106                    for (org.dom4j.Node oldNode : oldNodes) {
107                            if (oldNode instanceof org.dom4j.Element) {
108                                    newNodes.add(new ElementImpl((org.dom4j.Element)oldNode));
109                            }
110                            else {
111                                    newNodes.add(new NodeImpl(oldNode));
112                            }
113                    }
114    
115                    return new NodeList<Node, org.dom4j.Node>(newNodes, oldNodes);
116            }
117    
118            public static List<ProcessingInstruction> toNewProcessingInstructions(
119                    List<org.dom4j.ProcessingInstruction> oldProcessingInstructions) {
120    
121                    List<ProcessingInstruction> newProcessingInstructions =
122                            new ArrayList<ProcessingInstruction>(
123                                    oldProcessingInstructions.size());
124    
125                    for (org.dom4j.ProcessingInstruction oldProcessingInstruction :
126                                    oldProcessingInstructions) {
127    
128                            newProcessingInstructions.add(
129                                    new ProcessingInstructionImpl(oldProcessingInstruction));
130                    }
131    
132                    return new NodeList
133                            <ProcessingInstruction, org.dom4j.ProcessingInstruction>(
134                                    newProcessingInstructions, oldProcessingInstructions);
135            }
136    
137            public static List<org.dom4j.Attribute> toOldAttributes(
138                    List<Attribute> newAttributes) {
139    
140                    List<org.dom4j.Attribute> oldAttributes =
141                            new ArrayList<org.dom4j.Attribute>(newAttributes.size());
142    
143                    for (Attribute newAttribute : newAttributes) {
144                            AttributeImpl newAttributeImpl = (AttributeImpl)newAttribute;
145    
146                            oldAttributes.add(newAttributeImpl.getWrappedAttribute());
147                    }
148    
149                    return oldAttributes;
150            }
151    
152            public static List<org.dom4j.Node> toOldNodes(List<Node> newNodes) {
153                    List<org.dom4j.Node> oldNodes = new ArrayList<org.dom4j.Node>(
154                            newNodes.size());
155    
156                    for (Node newNode : newNodes) {
157                            NodeImpl newNodeImpl = (NodeImpl)newNode;
158    
159                            oldNodes.add(newNodeImpl.getWrappedNode());
160                    }
161    
162                    return oldNodes;
163            }
164    
165            public static List<org.dom4j.ProcessingInstruction>
166                    toOldProcessingInstructions(
167                            List<ProcessingInstruction> newProcessingInstructions) {
168    
169                    List<org.dom4j.ProcessingInstruction> oldProcessingInstructions =
170                            new ArrayList<org.dom4j.ProcessingInstruction>(
171                                    newProcessingInstructions.size());
172    
173                    for (ProcessingInstruction newProcessingInstruction :
174                                    newProcessingInstructions) {
175    
176                            ProcessingInstructionImpl newProcessingInstructionImpl =
177                                    (ProcessingInstructionImpl)newProcessingInstruction;
178    
179                            oldProcessingInstructions.add(
180                                    newProcessingInstructionImpl.getWrappedProcessingInstruction());
181                    }
182    
183                    return oldProcessingInstructions;
184            }
185    
186            public Attribute createAttribute(
187                    Element element, QName qName, String value) {
188    
189                    ElementImpl elementImpl = (ElementImpl)element;
190                    QNameImpl qNameImpl = (QNameImpl)qName;
191    
192                    DocumentFactory documentFactory = DocumentFactory.getInstance();
193    
194                    return new AttributeImpl(
195                            documentFactory.createAttribute(
196                                    elementImpl.getWrappedElement(), qNameImpl.getWrappedQName(),
197                                    value));
198            }
199    
200            public Attribute createAttribute(
201                    Element element, String name, String value) {
202    
203                    ElementImpl elementImpl = (ElementImpl)element;
204    
205                    DocumentFactory documentFactory = DocumentFactory.getInstance();
206    
207                    return new AttributeImpl(
208                            documentFactory.createAttribute(
209                                    elementImpl.getWrappedElement(), name, value));
210            }
211    
212            public Document createDocument() {
213                    return new DocumentImpl(DocumentHelper.createDocument());
214            }
215    
216            public Document createDocument(Element rootElement) {
217                    ElementImpl rootElementImpl = (ElementImpl)rootElement;
218    
219                    return new DocumentImpl(
220                            DocumentHelper.createDocument(rootElementImpl.getWrappedElement()));
221            }
222    
223            public Document createDocument(String encoding) {
224                    DocumentFactory documentFactory = DocumentFactory.getInstance();
225    
226                    return new DocumentImpl(documentFactory.createDocument(encoding));
227            }
228    
229            public Element createElement(QName qName) {
230                    QNameImpl qNameImpl = (QNameImpl)qName;
231    
232                    return new ElementImpl(
233                            DocumentHelper.createElement(qNameImpl.getWrappedQName()));
234            }
235    
236            public Element createElement(String name) {
237                    return new ElementImpl(DocumentHelper.createElement(name));
238            }
239    
240            public Entity createEntity(String name, String text) {
241                    return new EntityImpl(DocumentHelper.createEntity(name, text));
242            }
243    
244            public Namespace createNamespace(String uri) {
245                    return new NamespaceImpl(org.dom4j.Namespace.get(uri));
246            }
247    
248            public Namespace createNamespace(String prefix, String uri) {
249                    return new NamespaceImpl(DocumentHelper.createNamespace(prefix, uri));
250            }
251    
252            public ProcessingInstruction createProcessingInstruction(
253                    String target, Map<String, String> data) {
254    
255                    org.dom4j.ProcessingInstruction processingInstruction =
256                            DocumentHelper.createProcessingInstruction(target, data);
257    
258                    if (processingInstruction == null) {
259                            return null;
260                    }
261                    else {
262                            return new ProcessingInstructionImpl(processingInstruction);
263                    }
264            }
265    
266            public ProcessingInstruction createProcessingInstruction(
267                    String target, String data) {
268    
269                    org.dom4j.ProcessingInstruction processingInstruction =
270                            DocumentHelper.createProcessingInstruction(target, data);
271    
272                    if (processingInstruction == null) {
273                            return null;
274                    }
275                    else {
276                            return new ProcessingInstructionImpl(processingInstruction);
277                    }
278            }
279    
280            public QName createQName(String localName) {
281                    return new QNameImpl(DocumentHelper.createQName(localName));
282            }
283    
284            public QName createQName(String localName, Namespace namespace) {
285                    NamespaceImpl namespaceImpl = (NamespaceImpl)namespace;
286    
287                    return new QNameImpl(
288                            DocumentHelper.createQName(
289                                    localName, namespaceImpl.getWrappedNamespace()));
290            }
291    
292            public Text createText(String text) {
293                    return new TextImpl(DocumentHelper.createText(text));
294            }
295    
296            public XPath createXPath(String xPathExpression) {
297                    return createXPath(xPathExpression, null);
298            }
299    
300            public XPath createXPath(
301                    String xPathExpression, Map<String, String> namespaceContextMap) {
302    
303                    return new XPathImpl(
304                            DocumentHelper.createXPath(xPathExpression), namespaceContextMap);
305            }
306    
307            public XPath createXPath(
308                    String xPathExpression, String prefix, String namespace) {
309    
310                    Map<String, String> namespaceContextMap = new HashMap<String, String>();
311    
312                    namespaceContextMap.put(prefix, namespace);
313    
314                    return createXPath(xPathExpression, namespaceContextMap);
315            }
316    
317            public Document read(File file) throws DocumentException {
318                    return read(file, false);
319            }
320    
321            public Document read(File file, boolean validate) throws DocumentException {
322                    ClassLoader classLoader = getClass().getClassLoader();
323    
324                    ClassLoader contextClassLoader =
325                            ClassLoaderUtil.getContextClassLoader();
326    
327                    try {
328                            if (contextClassLoader != classLoader) {
329                                    ClassLoaderUtil.setContextClassLoader(classLoader);
330                            }
331    
332                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
333    
334                            return new DocumentImpl(saxReader.read(file));
335                    }
336                    catch (org.dom4j.DocumentException de) {
337                            throw new DocumentException(de.getMessage(), de);
338                    }
339                    finally {
340                            if (contextClassLoader != classLoader) {
341                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
342                            }
343                    }
344            }
345    
346            public Document read(InputStream is) throws DocumentException {
347                    return read(is, false);
348            }
349    
350            public Document read(InputStream is, boolean validate)
351                    throws DocumentException {
352    
353                    ClassLoader classLoader = getClass().getClassLoader();
354    
355                    ClassLoader contextClassLoader =
356                            ClassLoaderUtil.getContextClassLoader();
357    
358                    try {
359                            if (contextClassLoader != classLoader) {
360                                    ClassLoaderUtil.setContextClassLoader(classLoader);
361                            }
362    
363                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
364    
365                            return new DocumentImpl(saxReader.read(is));
366                    }
367                    catch (org.dom4j.DocumentException de) {
368                            throw new DocumentException(de.getMessage(), de);
369                    }
370                    finally {
371                            if (contextClassLoader != classLoader) {
372                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
373                            }
374                    }
375            }
376    
377            public Document read(Reader reader) throws DocumentException {
378                    return read(reader, false);
379            }
380    
381            public Document read(Reader reader, boolean validate)
382                    throws DocumentException {
383    
384                    ClassLoader classLoader = getClass().getClassLoader();
385    
386                    ClassLoader contextClassLoader =
387                            ClassLoaderUtil.getContextClassLoader();
388    
389                    try {
390                            if (contextClassLoader != classLoader) {
391                                    ClassLoaderUtil.setContextClassLoader(classLoader);
392                            }
393    
394                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
395    
396                            return new DocumentImpl(saxReader.read(reader));
397                    }
398                    catch (org.dom4j.DocumentException de) {
399                            throw new DocumentException(de.getMessage(), de);
400                    }
401                    finally {
402                            if (contextClassLoader != classLoader) {
403                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
404                            }
405                    }
406            }
407    
408            public Document read(String xml) throws DocumentException {
409                    return read(new XMLSafeReader(xml));
410            }
411    
412            public Document read(String xml, boolean validate)
413                    throws DocumentException {
414    
415                    return read(new XMLSafeReader(xml), validate);
416            }
417    
418            public Document read(URL url) throws DocumentException {
419                    return read(url, false);
420            }
421    
422            public Document read(URL url, boolean validate) throws DocumentException {
423                    ClassLoader classLoader = getClass().getClassLoader();
424    
425                    ClassLoader contextClassLoader =
426                            ClassLoaderUtil.getContextClassLoader();
427    
428                    try {
429                            if (contextClassLoader != classLoader) {
430                                    ClassLoaderUtil.setContextClassLoader(classLoader);
431                            }
432    
433                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
434    
435                            return new DocumentImpl(saxReader.read(url));
436                    }
437                    catch (org.dom4j.DocumentException de) {
438                            throw new DocumentException(de.getMessage(), de);
439                    }
440                    finally {
441                            if (contextClassLoader != classLoader) {
442                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
443                            }
444                    }
445            }
446    
447            public Document readURL(String url)
448                    throws DocumentException, MalformedURLException {
449    
450                    return read(new URL(url), false);
451            }
452    
453            public Document readURL(String url, boolean validate)
454                    throws DocumentException, MalformedURLException {
455    
456                    return read(new URL(url), validate);
457            }
458    
459            public List<Node> selectNodes(
460                    String xPathFilterExpression, List<Node> nodes) {
461    
462                    return toNewNodes(
463                            DocumentHelper.selectNodes(
464                                    xPathFilterExpression, toOldNodes(nodes)));
465            }
466    
467            public List<Node> selectNodes(String xPathFilterExpression, Node node) {
468                    NodeImpl nodeImpl = (NodeImpl)node;
469    
470                    return toNewNodes(
471                            DocumentHelper.selectNodes(
472                                    xPathFilterExpression, nodeImpl.getWrappedNode()));
473            }
474    
475            public void sort(List<Node> nodes, String xPathExpression) {
476                    DocumentHelper.sort(toOldNodes(nodes), xPathExpression);
477            }
478    
479            public void sort(
480                    List<Node> nodes, String xPathExpression, boolean distinct) {
481    
482                    DocumentHelper.sort(toOldNodes(nodes), xPathExpression, distinct);
483            }
484    
485            protected org.dom4j.io.SAXReader getSAXReader(boolean validate) {
486                    org.dom4j.io.SAXReader reader = null;
487    
488                    if (!PropsValues.XML_VALIDATION_ENABLED) {
489                            validate = false;
490                    }
491    
492                    try {
493                            reader = new org.dom4j.io.SAXReader(new SAXParser(), validate);
494    
495                            reader.setEntityResolver(new EntityResolver());
496    
497                            reader.setFeature(_FEATURES_DYNAMIC, validate);
498                            reader.setFeature(_FEATURES_EXTERNAL_GENERAL_ENTITIES, validate);
499                            reader.setFeature(_FEATURES_LOAD_DTD_GRAMMAR, validate);
500                            reader.setFeature(_FEATURES_LOAD_EXTERNAL_DTD, validate);
501                            reader.setFeature(_FEATURES_VALIDATION, validate);
502                            reader.setFeature(_FEATURES_VALIDATION_SCHEMA, validate);
503                            reader.setFeature(
504                                    _FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, validate);
505                    }
506                    catch (Exception e) {
507                            if (_log.isWarnEnabled()) {
508                                    _log.warn(
509                                            "XSD validation is disabled because " + e.getMessage());
510                            }
511    
512                            reader = new org.dom4j.io.SAXReader(false);
513    
514                            reader.setEntityResolver(new EntityResolver());
515                    }
516    
517                    return reader;
518            }
519    
520            private static final String _FEATURES_DYNAMIC =
521                    "http://apache.org/xml/features/validation/dynamic";
522    
523            private static final String _FEATURES_EXTERNAL_GENERAL_ENTITIES =
524                    "http://xml.org/sax/features/external-general-entities";
525    
526            private static final String _FEATURES_LOAD_DTD_GRAMMAR =
527                    "http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
528    
529            private static final String _FEATURES_LOAD_EXTERNAL_DTD =
530                    "http://apache.org/xml/features/nonvalidating/load-external-dtd";
531    
532            private static final String _FEATURES_VALIDATION =
533                    "http://xml.org/sax/features/validation";
534    
535            private static final String _FEATURES_VALIDATION_SCHEMA =
536                    "http://apache.org/xml/features/validation/schema";
537    
538            private static final String _FEATURES_VALIDATION_SCHEMA_FULL_CHECKING =
539                    "http://apache.org/xml/features/validation/schema-full-checking";
540    
541            private static Log _log = LogFactoryUtil.getLog(SAXReaderImpl.class);
542    
543            private static SAXReaderImpl _instance = new SAXReaderImpl();
544    
545    }