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