diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowActionResolverDelegate.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowActionResolverDelegate.java index 1448794..71741ed 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowActionResolverDelegate.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowActionResolverDelegate.java @@ -9,7 +9,7 @@ class FlowActionResolverDelegate implements ActionResolver { private final NamedItemResolver resolver; FlowActionResolverDelegate(FlowRoot src) { - resolver = new NamedItemResolver<>(src.getActions()); + resolver = new NamedItemResolver<>(Traversal.traverse(src, FlowRoot::getActions)); } @Override diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowParser.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowParser.java new file mode 100644 index 0000000..34980be --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowParser.java @@ -0,0 +1,68 @@ +package ru.penkrat.stbf.templates.xml; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import lombok.NonNull; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +class FlowParser { + + private final XmlMapper mapper = new XmlMapper(); + private String basePath = ""; + + public FlowRoot read(File file) throws IOException { + return read(new FileInputStream(file)); + } + + public FlowRoot read(@NonNull String fileName) { + if (fileName.startsWith("classpath:")) { + String fn = fileName.replaceFirst("^classpath:", ""); + basePath = "classpath:" + Paths.get(fileName).getParent().toString(); + return read(FlowParser.class.getResourceAsStream(fn)); + } else { + basePath = Paths.get(fileName).getParent().toString(); + try { + return read(new FileInputStream(fileName)); + } catch (FileNotFoundException e) { + throw new RuntimeException("Can't load file " + fileName, e); + } + } + } + + public FlowRoot read(InputStream is) { + FlowRoot flow = readFlow(is); + includes(flow); + return flow; + } + + private void includes(FlowRoot src) { + final List flowRoots = src.getIncludes().stream() + .map(IncludeItem::getFile) + .map(fileName -> readFlow(basePath, fileName)) + .filter(Objects::nonNull) + .peek(this::includes) + .collect(Collectors.toList()); + + src.getIncluded().addAll(flowRoots); + } + + private FlowRoot readFlow(InputStream is) { + try { + return mapper.readValue(is, FlowRoot.class); + } catch (IOException e) { + throw new RuntimeException("Can't load resource", e); + } + } + + private FlowRoot readFlow(String basePath, String file) { + return readFlow(FlowParser.class.getResourceAsStream(file)); + } +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java index 984c26b..73446e6 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java @@ -30,7 +30,7 @@ class FlowScreenResolverDelegate implements ScreenResolver { FlowScreenResolverDelegate(FlowRoot src, ActionResolver actionResolver) { this.actionResolver = actionResolver; - resolver = new NamedItemResolver<>(src.getScreens()); + resolver = new NamedItemResolver<>(Traversal.traverse(src, FlowRoot::getScreens)); } @Override diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/Traversal.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/Traversal.java new file mode 100644 index 0000000..913a293 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/Traversal.java @@ -0,0 +1,24 @@ +package ru.penkrat.stbf.templates.xml; + +import lombok.experimental.UtilityClass; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Function; + +@UtilityClass +class Traversal { + + public Collection traverse(FlowRoot flow, Function> getter) { + final ArrayList target = new ArrayList<>(); + traverse(flow, getter, target); + return target; + } + + private void traverse(FlowRoot flow, Function> getter, Collection target) { + Collection c = getter.apply(flow); + target.addAll(c); + + flow.getIncluded().forEach(f -> traverse(f, getter, target)); + } +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java index 37b45c8..594db45 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java @@ -1,25 +1,30 @@ package ru.penkrat.stbf.templates.xml; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; import lombok.extern.slf4j.Slf4j; import ru.penkrat.stbf.api.Action; import ru.penkrat.stbf.api.Screen; import ru.penkrat.stbf.templates.TemplateRenderer; +import java.io.File; import java.io.IOException; import java.io.InputStream; @Slf4j public class XmlFlowResolver implements FlowResolver { - private final XmlMapper mapper = new XmlMapper(); + private final FlowParser reader = new FlowParser(); private final FlowActionResolverDelegate actionDelegate; private final FlowScreenResolverDelegate screenDelegate; - public XmlFlowResolver(InputStream is) throws IOException { - FlowRoot flow = mapper.readValue(is, FlowRoot.class); + public XmlFlowResolver(String filename) { + FlowRoot flow = reader.read(filename); + actionDelegate = new FlowActionResolverDelegate(flow); + screenDelegate = new FlowScreenResolverDelegate(flow, this); + } + public XmlFlowResolver(InputStream is) { + FlowRoot flow = reader.read(is); actionDelegate = new FlowActionResolverDelegate(flow); screenDelegate = new FlowScreenResolverDelegate(flow, this); } diff --git a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlFlowResolverTest.java b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlFlowResolverTest.java index a995f76..b74c338 100644 --- a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlFlowResolverTest.java +++ b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlFlowResolverTest.java @@ -8,7 +8,11 @@ import ru.penkrat.stbf.api.Screen; import ru.penkrat.stbf.templates.impl.MustacheRenderer; import ru.penkrat.stbf.templates.utils.ReflectionUtils; +import java.io.FileOutputStream; import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import static org.assertj.core.api.Assertions.assertThat; @@ -59,4 +63,50 @@ public class XmlFlowResolverTest { assertThat(screen2.getKeyboard()).isEqualTo(keyboard); } + @Test + public void testReadWithInclude() throws Exception { + InputStream xmlUnderTest = XmlFlowResolverTest.class.getResourceAsStream("flow.xml"); + + XmlFlowResolver resolver = new XmlFlowResolver(xmlUnderTest); + + assertThat(resolver.getScreen("screen-1")).isNotNull(); + } + + @Test + public void testReadWithIncludeWithInclude() throws Exception { + InputStream xmlUnderTest = XmlFlowResolverTest.class.getResourceAsStream("flow.xml"); + + XmlFlowResolver resolver = new XmlFlowResolver(xmlUnderTest); + + assertThat(resolver.getAction("4001")).isNotNull(); + } + + @Test + public void testReadFile() throws Exception { + Path tmp = Files.createTempFile("test-flow", ".xml"); + OutputStream fos = new FileOutputStream(tmp.toFile()); + + InputStream xmlUnderTest = XmlFlowResolverTest.class.getResourceAsStream("flow.xml"); + int b = xmlUnderTest.read(); + while (b >= 0) { + fos.write(b); + b = xmlUnderTest.read(); + } + fos.close(); + + XmlFlowResolver resolver = new XmlFlowResolver(tmp.toFile().getAbsolutePath()); + + assertThat(resolver.getScreen("screen-1")).isNotNull(); + assertThat(resolver.getAction("3001")).isNotNull(); + + Files.deleteIfExists(tmp); + } + + @Test + public void testReadClasspath() throws Exception { + XmlFlowResolver resolver = new XmlFlowResolver("classpath:/ru/penkrat/stbf/templates/xml/flow.xml"); + assertThat(resolver.getScreen("screen-1")).isNotNull(); + assertThat(resolver.getAction("3001")).isNotNull(); + } + } diff --git a/stbf-templates/src/test/resources/ru/penkrat/stbf/templates/xml/flow.xml b/stbf-templates/src/test/resources/ru/penkrat/stbf/templates/xml/flow.xml new file mode 100644 index 0000000..84b4c48 --- /dev/null +++ b/stbf-templates/src/test/resources/ru/penkrat/stbf/templates/xml/flow.xml @@ -0,0 +1,20 @@ + + + + + + + Send phone + + + + Test text + + + + + + + + + \ No newline at end of file diff --git a/stbf-templates/src/test/resources/test/a.xml b/stbf-templates/src/test/resources/test/a.xml new file mode 100644 index 0000000..08d4256 --- /dev/null +++ b/stbf-templates/src/test/resources/test/a.xml @@ -0,0 +1,6 @@ + + + + A action + + \ No newline at end of file diff --git a/stbf-templates/src/test/resources/test/b/b.xml b/stbf-templates/src/test/resources/test/b/b.xml new file mode 100644 index 0000000..56a8045 --- /dev/null +++ b/stbf-templates/src/test/resources/test/b/b.xml @@ -0,0 +1,5 @@ + + + B action + + \ No newline at end of file