001    /**
002     * Copyright (c) 2000-2011 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 List<Node> selectNodes(
317                    String xPathFilterExpression, List<Node> nodes) {
318    
319                    return toNewNodes(
320                            DocumentHelper.selectNodes(
321                                    xPathFilterExpression, toOldNodes(nodes)));
322            }
323    
324            public List<Node> selectNodes(String xPathFilterExpression, Node node) {
325                    NodeImpl nodeImpl = (NodeImpl)node;
326    
327                    return toNewNodes(
328                            DocumentHelper.selectNodes(
329                                    xPathFilterExpression, nodeImpl.getWrappedNode()));
330            }
331    
332            public void sort(List<Node> nodes, String xPathExpression) {
333                    DocumentHelper.sort(toOldNodes(nodes), xPathExpression);
334            }
335    
336            public void sort(
337                    List<Node> nodes, String xPathExpression, boolean distinct) {
338    
339                    DocumentHelper.sort(toOldNodes(nodes), xPathExpression, distinct);
340            }
341    
342            public Document read(File file) throws DocumentException {
343                    return read(file, false);
344            }
345    
346            public Document read(File file, boolean validate)
347                    throws DocumentException {
348    
349                    ClassLoader classLoader = getClass().getClassLoader();
350    
351                    Thread currentThread = Thread.currentThread();
352    
353                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
354    
355                    try {
356                            if (contextClassLoader != classLoader) {
357                                    currentThread.setContextClassLoader(classLoader);
358                            }
359    
360                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
361    
362                            return new DocumentImpl(saxReader.read(file));
363                    }
364                    catch (org.dom4j.DocumentException de) {
365                            throw new DocumentException(de.getMessage(), de);
366                    }
367                    finally {
368                            if (contextClassLoader != classLoader) {
369                                    currentThread.setContextClassLoader(contextClassLoader);
370                            }
371                    }
372            }
373    
374            public Document read(InputStream is) throws DocumentException {
375                    return read(is, false);
376            }
377    
378            public Document read(InputStream is, boolean validate)
379                    throws DocumentException {
380    
381                    ClassLoader classLoader = getClass().getClassLoader();
382    
383                    Thread currentThread = Thread.currentThread();
384    
385                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
386    
387                    try {
388                            if (contextClassLoader != classLoader) {
389                                    currentThread.setContextClassLoader(classLoader);
390                            }
391    
392                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
393    
394                            return new DocumentImpl(saxReader.read(is));
395                    }
396                    catch (org.dom4j.DocumentException de) {
397                            throw new DocumentException(de.getMessage(), de);
398                    }
399                    finally {
400                            if (contextClassLoader != classLoader) {
401                                    currentThread.setContextClassLoader(contextClassLoader);
402                            }
403                    }
404            }
405    
406            public Document read(Reader reader) throws DocumentException {
407                    return read(reader, false);
408            }
409    
410            public Document read(Reader reader, boolean validate)
411                    throws DocumentException {
412    
413                    ClassLoader classLoader = getClass().getClassLoader();
414    
415                    Thread currentThread = Thread.currentThread();
416    
417                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
418    
419                    try {
420                            if (contextClassLoader != classLoader) {
421                                    currentThread.setContextClassLoader(classLoader);
422                            }
423    
424                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
425    
426                            return new DocumentImpl(saxReader.read(reader));
427                    }
428                    catch (org.dom4j.DocumentException de) {
429                            throw new DocumentException(de.getMessage(), de);
430                    }
431                    finally {
432                            if (contextClassLoader != classLoader) {
433                                    currentThread.setContextClassLoader(contextClassLoader);
434                            }
435                    }
436            }
437    
438            public Document read(String xml) throws DocumentException {
439                    return read(new XMLSafeReader(xml));
440            }
441    
442            public Document read(String xml, boolean validate)
443                    throws DocumentException {
444    
445                    return read(new XMLSafeReader(xml), validate);
446            }
447    
448            public Document read(URL url) throws DocumentException {
449                    return read(url, false);
450            }
451    
452            public Document read(URL url, boolean validate) throws DocumentException {
453                    ClassLoader classLoader = getClass().getClassLoader();
454    
455                    Thread currentThread = Thread.currentThread();
456    
457                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
458    
459                    try {
460                            if (contextClassLoader != classLoader) {
461                                    currentThread.setContextClassLoader(classLoader);
462                            }
463    
464                            org.dom4j.io.SAXReader saxReader = getSAXReader(validate);
465    
466                            return new DocumentImpl(saxReader.read(url));
467                    }
468                    catch (org.dom4j.DocumentException de) {
469                            throw new DocumentException(de.getMessage(), de);
470                    }
471                    finally {
472                            if (contextClassLoader != classLoader) {
473                                    currentThread.setContextClassLoader(contextClassLoader);
474                            }
475                    }
476            }
477    
478            public Document readURL(String url)
479                    throws DocumentException, MalformedURLException {
480    
481                    return read(new URL(url), false);
482            }
483    
484            public Document readURL(String url, boolean validate)
485                    throws DocumentException, MalformedURLException {
486    
487                    return read(new URL(url), validate);
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_VALIDATION, validate);
504                            reader.setFeature(_FEATURES_VALIDATION_SCHEMA, validate);
505                            reader.setFeature(
506                                    _FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, validate);
507    
508                            if (!validate) {
509                                    reader.setFeature(_FEATURES_LOAD_DTD_GRAMMAR, validate);
510                                    reader.setFeature(_FEATURES_LOAD_EXTERNAL_DTD, validate);
511                            }
512                    }
513                    catch (Exception e) {
514                            if (_log.isWarnEnabled()) {
515                                    _log.warn(
516                                            "XSD validation is disabled because " + e.getMessage());
517                            }
518    
519                            reader = new org.dom4j.io.SAXReader(false);
520    
521                            reader.setEntityResolver(new EntityResolver());
522                    }
523    
524                    return reader;
525            }
526    
527            private static final String _FEATURES_DYNAMIC =
528                    "http://apache.org/xml/features/validation/dynamic";
529    
530            private static final String _FEATURES_LOAD_DTD_GRAMMAR =
531                    "http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
532    
533            private static final String _FEATURES_LOAD_EXTERNAL_DTD =
534                    "http://apache.org/xml/features/nonvalidating/load-external-dtd";
535    
536            private static final String _FEATURES_VALIDATION =
537                    "http://xml.org/sax/features/validation";
538    
539            private static final String _FEATURES_VALIDATION_SCHEMA =
540                    "http://apache.org/xml/features/validation/schema";
541    
542            private static final String _FEATURES_VALIDATION_SCHEMA_FULL_CHECKING =
543                    "http://apache.org/xml/features/validation/schema-full-checking";
544    
545            private static Log _log = LogFactoryUtil.getLog(SAXReaderImpl.class);
546    
547            private static SAXReaderImpl _instance = new SAXReaderImpl();
548    
549    }