From 0e1cbdddf6bf2a0b25c211148e1f5f7bbdc2f131 Mon Sep 17 00:00:00 2001 From: Jarno Elovirta Date: Sun, 24 Mar 2019 14:03:09 +0200 Subject: [PATCH 1/2] Add project factory that loads and resolves includes Signed-off-by: Jarno Elovirta --- .../java/org/dita/dost/project/Project.java | 17 ++++++- .../org/dita/dost/project/ProjectFactory.java | 46 +++++++++++++++++++ .../org/dita/dost/project/ProjectTest.java | 36 +++++++++++++-- .../org/dita/dost/project/common.json | 43 +++++++++++++++++ .../resources/org/dita/dost/project/root.json | 10 ++++ 5 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/dita/dost/project/ProjectFactory.java create mode 100644 src/test/resources/org/dita/dost/project/common.json create mode 100644 src/test/resources/org/dita/dost/project/root.json diff --git a/src/main/java/org/dita/dost/project/Project.java b/src/main/java/org/dita/dost/project/Project.java index ac580e982f..e33a6bceac 100644 --- a/src/main/java/org/dita/dost/project/Project.java +++ b/src/main/java/org/dita/dost/project/Project.java @@ -22,10 +22,15 @@ public class Project { @JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "deliverable") public final List deliverables; + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "include") + public final List includes; @JsonCreator - public Project(@JsonProperty("deliverables") List deliverables) { + public Project(@JsonProperty("deliverables") List deliverables, + @JsonProperty("includes") List includes) { this.deliverables = deliverables; + this.includes = includes; } public static class Deliverable { @@ -173,4 +178,14 @@ public Param( } } } + + public static class ProjectRef { + @JacksonXmlProperty(isAttribute = true) + public final URI href; + + @JsonCreator + public ProjectRef(@JsonProperty("href") URI href) { + this.href = href; + } + } } diff --git a/src/test/java/org/dita/dost/project/ProjectFactory.java b/src/test/java/org/dita/dost/project/ProjectFactory.java new file mode 100644 index 0000000000..60c22227c7 --- /dev/null +++ b/src/test/java/org/dita/dost/project/ProjectFactory.java @@ -0,0 +1,46 @@ +/* + * This file is part of the DITA Open Toolkit project. + * + * Copyright 2019 Jarno Elovirta + * + * See the accompanying LICENSE file for applicable license. + */ + +package org.dita.dost.project; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +public class ProjectFactory { + + public static Project load(final URI file) throws IOException { + final ObjectMapper mapper = new ObjectMapper(); + try { + return resolve(mapper.readValue(file.toURL(), Project.class), file); + } catch (IOException e) { + throw new IOException("Failed to read project file: " + e.getMessage(), e); + } + } + + private static Project resolve(final Project project, final URI base) throws IOException { + if (project.includes == null || project.includes.isEmpty()) { + return project; + } + final List res = project.deliverables != null + ? new ArrayList(project.deliverables) + : new ArrayList(); + if (project.includes != null) { + for (final Project.ProjectRef projectRef : project.includes) { + final URI href = projectRef.href.isAbsolute() ? projectRef.href : base.resolve(projectRef.href); + final Project ref = load(href); + res.addAll(ref.deliverables); + } + } + return new Project(res, project.includes); + } + +} diff --git a/src/test/java/org/dita/dost/project/ProjectTest.java b/src/test/java/org/dita/dost/project/ProjectTest.java index 230362815c..4644bfe5de 100644 --- a/src/test/java/org/dita/dost/project/ProjectTest.java +++ b/src/test/java/org/dita/dost/project/ProjectTest.java @@ -22,22 +22,45 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.net.URISyntaxException; import java.util.Arrays; +import static org.junit.Assert.*; + public class ProjectTest { + @Test + public void read() throws IOException, URISyntaxException { + final URI file = getClass().getClassLoader().getResource("org/dita/dost/project/simple.json").toURI(); + final Project project = ProjectFactory.load(file); + assertEquals(1, project.deliverables.size()); + assertNull(project.includes); + } + @Test public void deserializeXmlSimple() throws IOException { final ObjectMapper xmlMapper = new XmlMapper(); final InputStream in = getClass().getClassLoader().getResourceAsStream("org/dita/dost/project/simple.xml"); - xmlMapper.readValue(in, Project.class); + final Project project = xmlMapper.readValue(in, Project.class); + assertNotNull(project.deliverables); + assertNull( project.includes); } @Test public void deserializeJsonSimple() throws IOException { final ObjectMapper xmlMapper = new ObjectMapper(); final InputStream in = getClass().getClassLoader().getResourceAsStream("org/dita/dost/project/simple.json"); - xmlMapper.readValue(in, Project.class); + final Project project = xmlMapper.readValue(in, Project.class); + assertNotNull(project.deliverables); + assertNull(project.includes); + } + + @Test + public void deserializeJsonRoot() throws IOException, URISyntaxException { + final URI input = getClass().getClassLoader().getResource("org/dita/dost/project/root.json").toURI(); + final Project project = ProjectFactory.load(input); + assertEquals(2, project.deliverables.size()); + assertEquals(2, project.includes.size()); } @Test @@ -54,6 +77,13 @@ public void serializeJsonSimple() throws IOException { xmlMapper.writeValueAsString(project); } + @Test + public void serializeJsonRoot() throws IOException { + final ObjectMapper xmlMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); + final Project project = new Project(null, Arrays.asList(new Project.ProjectRef(URI.create("simple.json")))); + xmlMapper.writeValueAsString(project); + } + private Project getProject() { return new Project(Arrays.asList(new Project.Deliverable( "name", @@ -70,6 +100,6 @@ private Project getProject() { new Publication.Param("args.gen.task.lbl", "YES", null), new Publication.Param("args.rellinks", "noparent", null) )) - ))); + )), null); } } diff --git a/src/test/resources/org/dita/dost/project/common.json b/src/test/resources/org/dita/dost/project/common.json new file mode 100644 index 0000000000..68fd7cbea4 --- /dev/null +++ b/src/test/resources/org/dita/dost/project/common.json @@ -0,0 +1,43 @@ +{ + "deliverables": [ + { + "name": "common-name", + "context": { + "name": "common-Site", + "id": "common-site", + "inputs": { + "inputs": [ + { + "href": "site.ditamap" + } + ] + }, + "profiles": { + "ditavals": [ + { + "href": "site.ditaval" + } + ] + } + }, + "output": "./site", + "publications": { + "transtype": "html5", + "id": "common-sitePub", + "name": "common-Site", + "params": [ + { + "name": "args.gen.task.lbl", + "value": "YES", + "href": null + }, + { + "name": "args.rellinks", + "value": "noparent", + "href": null + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/test/resources/org/dita/dost/project/root.json b/src/test/resources/org/dita/dost/project/root.json new file mode 100644 index 0000000000..17c6f8abd3 --- /dev/null +++ b/src/test/resources/org/dita/dost/project/root.json @@ -0,0 +1,10 @@ +{ + "includes": [ + { + "href": "common.json" + }, + { + "href": "simple.json" + } + ] +} \ No newline at end of file From 83ea4efeabb8d13e0bacacec98b8e9003a84676d Mon Sep 17 00:00:00 2001 From: Jarno Elovirta Date: Mon, 25 Mar 2019 09:46:23 +0200 Subject: [PATCH 2/2] Detect recursive read Signed-off-by: Jarno Elovirta --- .../org/dita/dost/project/ProjectFactory.java | 21 +++++++++++++++---- .../org/dita/dost/project/ProjectTest.java | 8 ++++++- .../org/dita/dost/project/recursive.json | 7 +++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/org/dita/dost/project/recursive.json diff --git a/src/test/java/org/dita/dost/project/ProjectFactory.java b/src/test/java/org/dita/dost/project/ProjectFactory.java index 60c22227c7..2b53061946 100644 --- a/src/test/java/org/dita/dost/project/ProjectFactory.java +++ b/src/test/java/org/dita/dost/project/ProjectFactory.java @@ -9,24 +9,37 @@ package org.dita.dost.project; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Set; public class ProjectFactory { + private static final ObjectReader reader = new ObjectMapper().reader().forType(Project.class); + public static Project load(final URI file) throws IOException { - final ObjectMapper mapper = new ObjectMapper(); try { - return resolve(mapper.readValue(file.toURL(), Project.class), file); + return load(file, Collections.emptySet()); } catch (IOException e) { throw new IOException("Failed to read project file: " + e.getMessage(), e); } } - private static Project resolve(final Project project, final URI base) throws IOException { + private static Project load(final URI file, final Set processed) throws IOException { + if (processed.contains(file)) { + throw new RuntimeException("Recursive project file import: " + file); + } + final Project project = reader.readValue(file.toURL()); + return resolve(project, file, ImmutableSet.builder().addAll(processed).add(file).build()); + } + + private static Project resolve(final Project project, final URI base, final Set processed) throws IOException { if (project.includes == null || project.includes.isEmpty()) { return project; } @@ -36,7 +49,7 @@ private static Project resolve(final Project project, final URI base) throws IOE if (project.includes != null) { for (final Project.ProjectRef projectRef : project.includes) { final URI href = projectRef.href.isAbsolute() ? projectRef.href : base.resolve(projectRef.href); - final Project ref = load(href); + final Project ref = load(href, processed); res.addAll(ref.deliverables); } } diff --git a/src/test/java/org/dita/dost/project/ProjectTest.java b/src/test/java/org/dita/dost/project/ProjectTest.java index 4644bfe5de..a3b80135ab 100644 --- a/src/test/java/org/dita/dost/project/ProjectTest.java +++ b/src/test/java/org/dita/dost/project/ProjectTest.java @@ -43,7 +43,7 @@ public void deserializeXmlSimple() throws IOException { final InputStream in = getClass().getClassLoader().getResourceAsStream("org/dita/dost/project/simple.xml"); final Project project = xmlMapper.readValue(in, Project.class); assertNotNull(project.deliverables); - assertNull( project.includes); + assertNull(project.includes); } @Test @@ -63,6 +63,12 @@ public void deserializeJsonRoot() throws IOException, URISyntaxException { assertEquals(2, project.includes.size()); } + @Test(expected = RuntimeException.class) + public void deserializeJsonRecursive() throws IOException, URISyntaxException { + final URI input = getClass().getClassLoader().getResource("org/dita/dost/project/recursive.json").toURI(); + ProjectFactory.load(input); + } + @Test public void serializeXmlSimple() throws IOException { final ObjectMapper xmlMapper = new XmlMapper().enable(SerializationFeature.INDENT_OUTPUT); diff --git a/src/test/resources/org/dita/dost/project/recursive.json b/src/test/resources/org/dita/dost/project/recursive.json new file mode 100644 index 0000000000..9e3e7eb27f --- /dev/null +++ b/src/test/resources/org/dita/dost/project/recursive.json @@ -0,0 +1,7 @@ +{ + "includes": [ + { + "href": "recursive.json" + } + ] +} \ No newline at end of file