Skip to content

Commit befa879

Browse files
committedDec 5, 2024
feat(#277): fix most of the code offences
1 parent a457fb2 commit befa879

File tree

3 files changed

+98
-99
lines changed

3 files changed

+98
-99
lines changed
 

‎src/main/java/com/jcabi/xml/DomParser.java

+28-6
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,9 @@
3131

3232
import com.jcabi.log.Logger;
3333
import java.io.ByteArrayInputStream;
34-
import java.io.ByteArrayOutputStream;
3534
import java.io.File;
3635
import java.io.IOException;
37-
import java.io.InputStream;
3836
import java.nio.charset.StandardCharsets;
39-
import java.nio.file.Path;
40-
import javax.print.Doc;
4137
import javax.xml.parsers.DocumentBuilder;
4238
import javax.xml.parsers.DocumentBuilderFactory;
4339
import javax.xml.parsers.ParserConfigurationException;
@@ -100,18 +96,33 @@ final class DomParser {
10096
this(fct, new BytesSource(bytes));
10197
}
10298

103-
99+
/**
100+
* Public ctor.
101+
*
102+
* <p>An {@link IllegalArgumentException} may be thrown if the parameter
103+
* passed is not in XML format. It doesn't perform a strict validation
104+
* and is not guaranteed that an exception will be thrown whenever
105+
* the parameter is not XML.
106+
*
107+
* @param fct Document builder factory to use
108+
* @param file The XML as a file
109+
*/
104110
DomParser(final DocumentBuilderFactory fct, final File file) {
105111
this(fct, new FileSource(file));
106112
}
107113

114+
/**
115+
* Private ctor.
116+
* @param factory Document builder factory to use
117+
* @param source Source of XML
118+
*/
108119
private DomParser(final DocumentBuilderFactory factory, final DocSource source) {
109120
this.factory = factory;
110121
this.source = source;
111122
}
112123

113124
/**
114-
* Get document of body.
125+
* Get the document body.
115126
* @return The document
116127
*/
117128
public Document document() {
@@ -158,8 +169,19 @@ public Document document() {
158169
*/
159170
private interface DocSource {
160171

172+
/**
173+
* Parse XML by the builder.
174+
* @param builder The builder to use during parsing.
175+
* @return The document.
176+
* @throws IOException If fails.
177+
* @throws SAXException If fails.
178+
*/
161179
Document apply(DocumentBuilder builder) throws IOException, SAXException;
162180

181+
/**
182+
* The length of the source.
183+
* @return The length.
184+
*/
163185
long length();
164186
}
165187

‎src/main/java/com/jcabi/xml/SaxonDocument.java

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
*
6060
* @since 0.28
6161
*/
62+
@SuppressWarnings("PMD.TooManyMethods")
6263
public final class SaxonDocument implements XML {
6364

6465
/**

‎src/test/java/com/jcabi/xml/XMLDocumentTest.java

+69-93
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
package com.jcabi.xml;
3131

3232
import com.google.common.collect.Iterables;
33-
import com.jcabi.log.Logger;
3433
import com.jcabi.matchers.XhtmlMatchers;
3534
import java.io.ByteArrayInputStream;
3635
import java.io.File;
@@ -50,9 +49,9 @@
5049
import java.util.concurrent.Executors;
5150
import java.util.concurrent.TimeUnit;
5251
import java.util.concurrent.atomic.AtomicInteger;
52+
import java.util.stream.Collectors;
5353
import java.util.stream.IntStream;
5454
import javax.xml.parsers.DocumentBuilderFactory;
55-
import javax.xml.parsers.ParserConfigurationException;
5655
import org.apache.commons.lang3.RandomStringUtils;
5756
import org.apache.commons.lang3.StringUtils;
5857
import org.cactoos.io.ResourceOf;
@@ -69,8 +68,6 @@
6968
import org.w3c.dom.Document;
7069
import org.w3c.dom.Element;
7170
import org.w3c.dom.Node;
72-
import org.xml.sax.InputSource;
73-
import org.xml.sax.SAXException;
7471
import org.xml.sax.SAXParseException;
7572

7673
/**
@@ -680,102 +677,81 @@ void validatesMultipleXmlsInThreads() throws Exception {
680677
service.shutdownNow();
681678
}
682679

683-
684-
@Test
685-
@Disabled
686-
void createsManyXmlDocuments() throws ParserConfigurationException, IOException, SAXException {
687-
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
688-
String xml = this.large();
689-
final long startSimple = System.nanoTime();
690-
final String expected = "root";
691-
for (int i = 0; i < 10_000; ++i) {
692-
final Document parse = factory.newDocumentBuilder()
693-
.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
694-
final String actual = parse.getFirstChild().getNodeName();
695-
MatcherAssert.assertThat(
696-
actual,
697-
Matchers.equalTo(expected)
698-
);
699-
}
700-
final long endSimple = System.nanoTime();
701-
System.out.println(
702-
"Default approach to create XML timing: " + (endSimple - startSimple) / 1_000_000 + " ms");
703-
Logger.info(this, "Time: %[ms]s", (endSimple - startSimple) / 1000);
704-
final long start = System.nanoTime();
705-
for (int i = 0; i < 10_000; ++i) {
706-
;
707-
final String actual = new XMLDocument(
708-
new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)))
709-
.node()
710-
.getFirstChild().getNodeName();
711-
MatcherAssert.assertThat(
712-
actual,
713-
Matchers.equalTo(expected)
714-
);
715-
}
716-
final long end = System.nanoTime();
717-
System.out.println(
718-
"jcabi-xml approach to create XML timing: " + (end - start) / 1_000_000 + " ms"
719-
);
720-
}
721-
722-
723-
// ~ 1.6
680+
/**
681+
* This test is disabled because it is a performance test that might be flaky.
682+
* @param temp Temporary directory.
683+
* @throws IOException If something goes wrong.
684+
*/
724685
@RepeatedTest(10)
725686
@Disabled
726-
void createsXmlFromFile(
727-
@TempDir final Path temp
728-
) throws IOException, ParserConfigurationException, SAXException {
687+
void createsXmlFromFile(@TempDir final Path temp) throws IOException {
729688
final Path xml = temp.resolve("test.xml");
730-
String content = this.large();
731-
Files.write(xml, content.getBytes(StandardCharsets.UTF_8));
732-
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
733-
final long startSimple = System.nanoTime();
734-
final String expected = "root";
735-
for (int i = 0; i < 10_000; ++i) {
736-
final Document parse = factory.newDocumentBuilder().parse(xml.toFile());
737-
final String actual = parse.getFirstChild().getNodeName();
738-
MatcherAssert.assertThat(
739-
actual,
740-
Matchers.equalTo(expected)
741-
);
742-
}
743-
final long endSimple = System.nanoTime();
744-
final double simple = (endSimple - startSimple) / 1_000_000.0d;
745-
System.out.println(
746-
"Default approach to create XML timing: " + simple + " ms");
747-
final long start = System.nanoTime();
748-
for (int i = 0; i < 10_000; ++i) {
749-
final String actual = new XMLDocument(xml).node()
750-
.getFirstChild().getNodeName();
751-
MatcherAssert.assertThat(
752-
actual,
753-
Matchers.equalTo(expected)
754-
);
755-
}
756-
final long end = System.nanoTime();
757-
final double actual = (end - start) / 1_000_000.0d;
758-
System.out.println(
759-
"jcabi-xml approach to create XML timing: " + actual + " ms"
689+
Files.write(xml, XMLDocumentTest.large().getBytes(StandardCharsets.UTF_8));
690+
final long clear = XMLDocumentTest.measure(
691+
() -> DocumentBuilderFactory.newInstance()
692+
.newDocumentBuilder()
693+
.parse(xml.toFile())
694+
.getFirstChild()
695+
.getNodeName()
760696
);
761-
System.out.println(
762-
"Simple approach is " + (actual / simple) + " times faster"
697+
final long wrapped = XMLDocumentTest.measure(
698+
() -> new XMLDocument(xml.toFile()).inner().getFirstChild().getNodeName()
763699
);
764-
700+
MatcherAssert.assertThat(
701+
String.format(
702+
"We expect that jcabi-xml is at max 2 times slower than default approach, time spend on jcabi-xml: %d ms, time spend on default approach: %d ms",
703+
wrapped,
704+
clear
705+
),
706+
wrapped / clear,
707+
Matchers.lessThan(2L)
708+
);
709+
}
710+
711+
/**
712+
* Measure the time of execution.
713+
* @param run The callable to run.
714+
* @return Time in milliseconds.
715+
* @checkstyle IllegalCatchCheck (20 lines)
716+
*/
717+
@SuppressWarnings({"PMD.AvoidCatchingGenericException", "PMD.PrematureDeclaration"})
718+
private static long measure(final Callable<String> run) {
719+
final long start = System.nanoTime();
720+
if (!IntStream.range(0, 1000).mapToObj(
721+
each -> {
722+
try {
723+
return run.call();
724+
} catch (final Exception exception) {
725+
throw new IllegalStateException(
726+
String.format("Failed to run %s", run), exception
727+
);
728+
}
729+
}
730+
).allMatch("root"::equals)) {
731+
throw new IllegalStateException("Invalid result");
732+
}
733+
return System.nanoTime() - start / 1_000_000;
765734
}
766735

767-
private String large() {
768-
final StringBuilder builder = new StringBuilder(
769-
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>").append("<root>");
770-
final String payment = StringUtils.join(
771-
"<payment><id>333</id>",
772-
"<date>1-Jan-2013</date>",
773-
"<debit>test-1</debit>",
774-
"<credit>test-2</credit>",
775-
"</payment>"
776-
);
777-
IntStream.range(0, 1_000).mapToObj(i -> payment).forEach(builder::append);
778-
return builder.append("</root>").toString();
736+
/**
737+
* Generate large XML for tests.
738+
* @return Large XML string.
739+
*/
740+
private static String large() {
741+
return IntStream.range(0, 100)
742+
.mapToObj(
743+
i -> StringUtils.join(
744+
"<payment><id>333</id>",
745+
"<date>1-Jan-2013</date>",
746+
"<debit>test-1</debit>",
747+
"<credit>test-2</credit>",
748+
"</payment>"
749+
)
750+
).collect(
751+
Collectors.joining(
752+
"", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>", "</root>"
753+
)
754+
);
779755
}
780756

781757
}

0 commit comments

Comments
 (0)
Please sign in to comment.