View Javadoc
1   /*
2    * The MIT License (MIT)
3    *
4    * Copyright (c) 2013-2026 The Coveralls Maven Plugin Project Contributors:
5    *     https://github.com/hazendaz/coveralls-maven-plugin/graphs/contributors
6    *
7    * Permission is hereby granted, free of charge, to any person obtaining a copy
8    * of this software and associated documentation files (the "Software"), to deal
9    * in the Software without restriction, including without limitation the rights
10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11   * copies of the Software, and to permit persons to whom the Software is
12   * furnished to do so, subject to the following conditions:
13   *
14   * The above copyright notice and this permission notice shall be included in
15   * all copies or substantial portions of the Software.
16   *
17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23   * THE SOFTWARE.
24   */
25  package org.eluder.coveralls.maven.plugin.parser;
26  
27  import java.io.BufferedInputStream;
28  import java.io.File;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.nio.file.Files;
32  
33  import javax.xml.stream.FactoryConfigurationError;
34  import javax.xml.stream.XMLInputFactory;
35  import javax.xml.stream.XMLStreamConstants;
36  import javax.xml.stream.XMLStreamException;
37  import javax.xml.stream.XMLStreamReader;
38  
39  import org.eluder.coveralls.maven.plugin.CoverageParser;
40  import org.eluder.coveralls.maven.plugin.ProcessingException;
41  import org.eluder.coveralls.maven.plugin.domain.Source;
42  import org.eluder.coveralls.maven.plugin.source.SourceCallback;
43  import org.eluder.coveralls.maven.plugin.source.SourceLoader;
44  
45  /**
46   * The Class AbstractXmlEventParser.
47   */
48  public abstract class AbstractXmlEventParser implements CoverageParser {
49  
50      /** The coverage file. */
51      private final File coverageFile;
52  
53      /** The source loader. */
54      private final SourceLoader sourceLoader;
55  
56      /**
57       * Instantiates a new abstract xml event parser.
58       *
59       * @param coverageFile
60       *            the coverage file
61       * @param sourceLoader
62       *            the source loader
63       */
64      protected AbstractXmlEventParser(final File coverageFile, final SourceLoader sourceLoader) {
65          this.coverageFile = coverageFile;
66          this.sourceLoader = sourceLoader;
67      }
68  
69      @Override
70      public final void parse(final SourceCallback callback) throws ProcessingException, IOException {
71          XMLStreamReader xml = null;
72          try (var is = Files.newInputStream(this.coverageFile.toPath());
73                  var bis = new BufferedInputStream(is)) {
74              xml = this.createEventReader(bis);
75              while (xml.hasNext()) {
76                  xml.next();
77                  this.onEvent(xml, callback);
78              }
79          } catch (final XMLStreamException e) {
80              throw new ProcessingException(e);
81          } finally {
82              this.close(xml);
83          }
84      }
85  
86      @Override
87      public final File getCoverageFile() {
88          return this.coverageFile;
89      }
90  
91      /**
92       * Creates the event reader.
93       *
94       * @param inputStream
95       *            the input stream
96       *
97       * @return the XML stream reader
98       *
99       * @throws ProcessingException
100      *             the processing exception
101      */
102     protected XMLStreamReader createEventReader(final InputStream inputStream) throws ProcessingException {
103         try {
104             final var xmlif = XMLInputFactory.newInstance();
105             xmlif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
106             xmlif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
107             xmlif.setProperty(XMLInputFactory.IS_VALIDATING, false);
108             xmlif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
109             return xmlif.createXMLStreamReader(inputStream);
110         } catch (final FactoryConfigurationError e) {
111             throw new IllegalArgumentException(e);
112         } catch (final XMLStreamException e) {
113             throw new ProcessingException(e);
114         }
115     }
116 
117     /**
118      * Close.
119      *
120      * @param xml
121      *            the xml
122      *
123      * @throws ProcessingException
124      *             the processing exception
125      */
126     private void close(final XMLStreamReader xml) throws ProcessingException {
127         if (xml != null) {
128             try {
129                 xml.close();
130             } catch (final XMLStreamException e) {
131                 throw new ProcessingException(e);
132             }
133         }
134     }
135 
136     /**
137      * On event.
138      *
139      * @param xml
140      *            the xml
141      * @param callback
142      *            the callback
143      *
144      * @throws XMLStreamException
145      *             the XML stream exception
146      * @throws ProcessingException
147      *             the processing exception
148      * @throws IOException
149      *             Signals that an I/O exception has occurred.
150      */
151     protected abstract void onEvent(final XMLStreamReader xml, SourceCallback callback)
152             throws XMLStreamException, ProcessingException, IOException;
153 
154     /**
155      * Load source.
156      *
157      * @param sourceFile
158      *            the source file
159      *
160      * @return the source
161      *
162      * @throws IOException
163      *             Signals that an I/O exception has occurred.
164      */
165     protected final Source loadSource(final String sourceFile) throws IOException {
166         return this.sourceLoader.load(sourceFile);
167     }
168 
169     /**
170      * Checks if is start element.
171      *
172      * @param xml
173      *            the xml
174      * @param name
175      *            the name
176      *
177      * @return true, if is start element
178      */
179     protected final boolean isStartElement(final XMLStreamReader xml, final String name) {
180         return XMLStreamConstants.START_ELEMENT == xml.getEventType() && xml.getLocalName().equals(name);
181     }
182 
183     /**
184      * Checks if is end element.
185      *
186      * @param xml
187      *            the xml
188      * @param name
189      *            the name
190      *
191      * @return true, if is end element
192      */
193     protected final boolean isEndElement(final XMLStreamReader xml, final String name) {
194         return XMLStreamConstants.END_ELEMENT == xml.getEventType() && xml.getLocalName().equals(name);
195     }
196 }