diff --git a/eo-parser/src/main/java/org/eolang/parser/StrictXmir.java b/eo-parser/src/main/java/org/eolang/parser/StrictXmir.java index a91d450dc6..f1319f8be9 100644 --- a/eo-parser/src/main/java/org/eolang/parser/StrictXmir.java +++ b/eo-parser/src/main/java/org/eolang/parser/StrictXmir.java @@ -205,30 +205,46 @@ private static XML reset(final XML xml, final Path tmp) { private static File fetch(final String uri, final Path path, final Path tmp) { final File ret; if (StrictXmir.MINE.equals(uri)) { - if (path.toFile().getParentFile().mkdirs()) { - Logger.debug(StrictXmir.class, "Directory for %[file]s created", path); - } - try { - Files.write( - path, - new IoCheckedBytes( - new BytesOf(new ResourceOf("XMIR.xsd")) - ).asBytes() - ); - Logger.debug(StrictXmir.class, "XSD copied to %[file]s", path); - } catch (final IOException ex) { - throw new IllegalArgumentException( - String.format("Failed to save %s to %s", uri, path), - ex - ); - } - ret = path.toFile(); + ret = StrictXmir.copied(uri, path, tmp); } else { - ret = StrictXmir.download(uri, path, tmp); + ret = StrictXmir.downloaded(uri, path, tmp); } return ret; } + /** + * Copy URI from local resource and save to file. + * @param uri The URI + * @param path The file + * @param tmp Directory to synchronize by + * @return Where it was saved + */ + private static File copied(final String uri, final Path path, final Path tmp) { + final File file = path.toFile(); + synchronized (tmp) { + if (!file.exists()) { + if (file.getParentFile().mkdirs()) { + Logger.debug(StrictXmir.class, "Directory for %[file]s created", path); + } + try { + Files.write( + path, + new IoCheckedBytes( + new BytesOf(new ResourceOf("XMIR.xsd")) + ).asBytes() + ); + Logger.debug(StrictXmir.class, "XSD copied to %[file]s", path); + } catch (final IOException ex) { + throw new IllegalArgumentException( + String.format("Failed to save %s to %s", uri, path), + ex + ); + } + } + } + return file; + } + /** * Download URI from Internet and save to file. * @param uri The URI @@ -237,7 +253,7 @@ private static File fetch(final String uri, final Path path, final Path tmp) { * @return Where it was saved */ @SuppressWarnings("PMD.CognitiveComplexity") - private static File download(final String uri, final Path path, final Path tmp) { + private static File downloaded(final String uri, final Path path, final Path tmp) { final File abs = path.toFile().getAbsoluteFile(); synchronized (tmp) { if (!abs.exists()) { diff --git a/eo-parser/src/test/java/org/eolang/parser/StrictXmirTest.java b/eo-parser/src/test/java/org/eolang/parser/StrictXmirTest.java index 6a5dc80745..1f822bb92f 100644 --- a/eo-parser/src/test/java/org/eolang/parser/StrictXmirTest.java +++ b/eo-parser/src/test/java/org/eolang/parser/StrictXmirTest.java @@ -138,6 +138,49 @@ void validatesXmirWithLocalSchema(@Mktmp final Path tmp) { ); } + @RepeatedTest(20) + @ExtendWith(MktmpResolver.class) + void validatesXmirWithLocalSchemaInMultipleThreads(@Mktmp final Path tmp) { + Assertions.assertDoesNotThrow( + new Together<>( + thread -> new StrictXmir( + new Xmir( + StrictXmirTest.xmir( + String.format( + "https://www.eolang.org/xsd/XMIR-%s.xsd", + Manifests.read("EO-Version") + ) + ) + ), + tmp + ).inner() + )::asList, + "validation should pass as normal" + ); + } + + @RepeatedTest(20) + @ExtendWith(MktmpResolver.class) + void validatesXmirWithLocalSchemaInMultipleThreadsWithTheSameXml(@Mktmp final Path tmp) { + final XML xml = new StrictXmir( + new Xmir( + StrictXmirTest.xmir( + String.format( + "https://www.eolang.org/xsd/XMIR-%s.xsd", + Manifests.read("EO-Version") + ) + ) + ), + tmp + ); + Assertions.assertDoesNotThrow( + new Together<>( + thread -> xml.inner() + )::asList, + "validation should pass as normal" + ); + } + @Test @ExtendWith(MktmpResolver.class) void validatesXmirWithBrokenUri(@Mktmp final Path tmp) {