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