View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   */
19  package org.apache.rat.testhelpers;
20  
21  import static org.assertj.core.api.Assertions.assertThat;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.io.OutputStreamWriter;
28  import java.io.PrintStream;
29  import java.io.StringReader;
30  import java.lang.reflect.UndeclaredThrowableException;
31  import java.nio.charset.StandardCharsets;
32  import java.util.ArrayList;
33  import java.util.HashMap;
34  import java.util.List;
35  
36  import java.util.Map;
37  import javax.xml.parsers.DocumentBuilder;
38  import javax.xml.parsers.DocumentBuilderFactory;
39  import javax.xml.parsers.FactoryConfigurationError;
40  import javax.xml.parsers.ParserConfigurationException;
41  import javax.xml.parsers.SAXParserFactory;
42  import javax.xml.transform.OutputKeys;
43  import javax.xml.transform.Transformer;
44  import javax.xml.transform.TransformerException;
45  import javax.xml.transform.TransformerFactory;
46  import javax.xml.transform.dom.DOMSource;
47  import javax.xml.transform.stream.StreamResult;
48  import javax.xml.xpath.XPath;
49  import javax.xml.xpath.XPathConstants;
50  import javax.xml.xpath.XPathExpressionException;
51  
52  import org.apache.rat.report.xml.writer.IXmlWriter;
53  import org.apache.rat.utils.DefaultLog;
54  import org.w3c.dom.Document;
55  import org.w3c.dom.NamedNodeMap;
56  import org.w3c.dom.Node;
57  import org.w3c.dom.NodeList;
58  import org.xml.sax.InputSource;
59  import org.xml.sax.SAXException;
60  import org.xml.sax.XMLReader;
61  
62  public final class XmlUtils {
63      /**
64       * Private constructor, to prevent accidental instantiation.
65       */
66      private XmlUtils() {
67          // Does nothing
68      }
69  
70      public static XMLReader newXMLReader() throws SAXException, ParserConfigurationException {
71          final SAXParserFactory spf = SAXParserFactory.newInstance();
72          spf.setValidating(false);
73          spf.setNamespaceAware(true);
74          return spf.newSAXParser().getXMLReader();
75      }
76  
77      public static boolean isWellFormedXml(final String string) {
78          return isWellFormedXml(new InputSource(new StringReader(string)));
79      }
80  
81      public static boolean isWellFormedXml(final InputStream in) {
82          return isWellFormedXml(new InputSource(in));
83      }
84  
85      public static boolean isWellFormedXml(final InputSource isource) {
86          try {
87              newXMLReader().parse(isource);
88              return true;
89          } catch (SAXException e) {
90              DefaultLog.getInstance().error(e.getMessage(), e);
91              return false;
92          } catch (IOException | ParserConfigurationException e) {
93              throw new UndeclaredThrowableException(e);
94          }
95      }
96  
97      public static NodeList getNodeList(Object source, XPath xPath, String xpath) throws XPathExpressionException {
98          return (NodeList) xPath.compile(xpath).evaluate(source, XPathConstants.NODESET);
99      }
100 
101     public static boolean isPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException {
102         Object node = xPath.compile(xpath).evaluate(source, XPathConstants.NODE);
103         return node != null;
104     }
105 
106     public static List<Node> getNodes(Object source, XPath xPath, String xpath) throws XPathExpressionException {
107         NodeList nodeList = (NodeList) xPath.compile(xpath).evaluate(source, XPathConstants.NODESET);
108         List<Node> result = new ArrayList<>();
109         for (int i = 0; i < nodeList.getLength(); i++) {
110             result.add(nodeList.item(i));
111         }
112         return result;
113     }
114 
115     public static Node getNode(Object source, XPath xPath, String xpath) throws XPathExpressionException {
116         NodeList nodeList = getNodeList(source, xPath, xpath);
117         assertEquals(1, nodeList.getLength(), "Could not find exactly one" + xpath);
118         return nodeList.item(0);
119     }
120 
121     public static String printNodeList(NodeList nodeList) {
122         StringBuilder sb = new StringBuilder();
123         for (int i = 0; i < nodeList.getLength(); i++) {
124             Node n = nodeList.item(0);
125             sb.append(n.getNodeName()).append(" ");
126             NamedNodeMap nnm = n.getAttributes();
127             for (int j = 0; j < nnm.getLength(); j++) {
128                 Node a = nnm.item(j);
129                 sb.append(a.getNodeName()).append("=").append(a.getNodeValue()).append(" ");
130             }
131             sb.append("\n");
132         }
133         return sb.toString();
134     }
135 
136     public static Document toDom(final InputStream in)
137             throws SAXException, IOException, ParserConfigurationException, FactoryConfigurationError {
138         final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
139         Document result;
140         result = builder.parse(in);
141         return result;
142     }
143 
144     public static void writeAttribute(final IXmlWriter writer, final String name, final boolean booleanValue)
145             throws IOException {
146         final String value = Boolean.toString(booleanValue);
147         writer.attribute(name, value);
148     }
149 
150     /**
151      * Print the properties and XML document to the output stream
152      * 
153      * @param out the OutputStream to print the document to.
154      * @param document The XML DOM document to print
155      */
156     public static void printDocument(OutputStream out, Document document) {
157         TransformerFactory tf = TransformerFactory.newInstance();
158         Transformer transformer;
159         try {
160             transformer = tf.newTransformer();
161 
162             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
163             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
164             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
165             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
166             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
167 
168             transformer.transform(new DOMSource(document), new StreamResult(new OutputStreamWriter(out, StandardCharsets.UTF_8)));
169         } catch (TransformerException e) {
170             e.printStackTrace(new PrintStream(out));
171         }
172     }
173 
174     public static String getAttribute(Object source, XPath xPath, String xpath, String attribute) throws XPathExpressionException {
175         Node node = XmlUtils.getNode(source, xPath, xpath);
176         NamedNodeMap attr = node.getAttributes();
177         node = attr.getNamedItem(attribute);
178         assertThat(node).as(attribute + " was not found").isNotNull();
179         return node.getNodeValue();
180     }
181 
182     public static Map<String, String> mapOf(String... parts) {
183         Map<String, String> map = new HashMap<>();
184         for (int i = 0; i < parts.length; i += 2) {
185             map.put(parts[i], parts[i+1]);
186         }
187         return map;
188     }
189 
190     public static void assertAttributes(Object source, XPath xPath, String xpath, String... mapValues) throws XPathExpressionException {
191         assertAttributes(source, xPath, xpath, mapOf(mapValues));
192     }
193 
194     public static void assertAttributes(Object source, XPath xPath, String xpath, Map<String, String> attributes) throws XPathExpressionException {
195         Node node = XmlUtils.getNode(source, xPath, xpath);
196         NamedNodeMap attr = node.getAttributes();
197         for (Map.Entry<String, String> entry : attributes.entrySet()) {
198             node = attr.getNamedItem(entry.getKey());
199             assertThat(node).as(() -> entry.getKey() + " was not found on " + xpath).isNotNull();
200             assertThat(node.getNodeValue()).as(() -> entry.getKey() + " on " + xpath).isEqualTo(entry.getValue());
201         }
202     }
203 
204     public static void assertIsPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException {
205         assertThat(isPresent(source, xPath, xpath)).as("Presence of " + xpath).isTrue();
206     }
207 
208     public static void assertIsNotPresent(Object source, XPath xPath, String xpath) throws XPathExpressionException {
209         assertThat(isPresent(source, xPath, xpath)).as("Non-presence of " + xpath).isFalse();
210     }
211 
212     public static void assertIsPresent(String identifier, Object source, XPath xPath, String xpath) throws XPathExpressionException {
213         assertThat(isPresent(source, xPath, xpath)).as(identifier + ": Presence of " + xpath).isTrue();
214     }
215 
216     public static void assertIsNotPresent(String identifier, Object source, XPath xPath, String xpath) throws XPathExpressionException {
217         assertThat(isPresent(source, xPath, xpath)).as(identifier + ": Non-presence of " + xpath).isFalse();
218     }
219 }