From e5a9c82ff3e42ad7cd46d45f4f876962eece6ff2 Mon Sep 17 00:00:00 2001 From: Ruslan Penkrat Date: Sun, 5 Sep 2021 08:33:26 +0300 Subject: [PATCH] initial commands support --- .../stbf/templates/CommandResolver.java | 11 +++ .../stbf/templates/xml/CommandItem.java | 24 +++++ .../xml/FlowCommandResolverDelegate.java | 92 +++++++++++++++++++ .../stbf/templates/xml/FlowResolver.java | 3 +- .../penkrat/stbf/templates/xml/FlowRoot.java | 5 + .../stbf/templates/xml/XmlFlowResolver.java | 12 ++- .../stbf/templates/xml/FlowCommandsTest.java | 18 ++++ .../stbf/templates/xml/XmlWriterTest.java | 12 ++- .../ru/penkrat/stbf/templates/xml/flow.xml | 5 +- 9 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/CommandResolver.java create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java create mode 100644 stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/FlowCommandsTest.java diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/CommandResolver.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/CommandResolver.java new file mode 100644 index 0000000..6a3c814 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/CommandResolver.java @@ -0,0 +1,11 @@ +package ru.penkrat.stbf.templates; + +import ru.penkrat.stbf.api.Command; + +import java.util.Collection; + +public interface CommandResolver { + + Collection getCommands(); + +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java new file mode 100644 index 0000000..695a209 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java @@ -0,0 +1,24 @@ +package ru.penkrat.stbf.templates.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@JacksonXmlRootElement(localName = "command") +public class CommandItem extends NamedItem { + + @JacksonXmlProperty(isAttribute = true) + private String actionRef; + + @JacksonXmlProperty(isAttribute = true) + private String screenRef; + + @JacksonXmlProperty(isAttribute = true, localName = "class") + private String clazz; + +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java new file mode 100644 index 0000000..65584b9 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java @@ -0,0 +1,92 @@ +package ru.penkrat.stbf.templates.xml; + +import lombok.RequiredArgsConstructor; +import ru.penkrat.stbf.api.Action; +import ru.penkrat.stbf.api.BotRequest; +import ru.penkrat.stbf.api.BotResponse; +import ru.penkrat.stbf.api.Command; +import ru.penkrat.stbf.api.CommandChain; +import ru.penkrat.stbf.api.RequestMatcher; +import ru.penkrat.stbf.api.Screen; +import ru.penkrat.stbf.templates.ActionResolver; +import ru.penkrat.stbf.templates.CommandResolver; +import ru.penkrat.stbf.templates.ScreenResolver; +import ru.penkrat.stbf.templates.utils.StringUtils; +import ru.penkrat.stbf.tools.RequestMatchers; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class FlowCommandResolverDelegate implements CommandResolver { + + private final FlowRoot root; + private final ActionResolver actionResolver; + private final ScreenResolver screenResolver; + + private boolean resolved; + private Collection commands; + + @Override + public Collection getCommands() { + resolve(); + return commands; + } + + private void resolve() { + if (!resolved) { + Collection parsedCommands = Traversal.traverse(root, FlowRoot::getCommands) + .stream() + .map(this::createCommand) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + commands = Collections.unmodifiableCollection(parsedCommands); + resolved = true; + } + } + + private Command createCommand(CommandItem commandItem) { + Action action = null; + Screen screen = null; + Function screenFactory; + if (StringUtils.isNotEmpty(commandItem.getActionRef())) { + action = actionResolver.getAction(commandItem.getActionRef()); + + } + if (StringUtils.isNotEmpty(commandItem.getScreenRef())) { + screen = screenResolver.getScreen(commandItem.getScreenRef()); + screenFactory = screenResolver.getScreenFactory(commandItem.getScreenRef()); + } + if (action != null && screen != null) { + return simpleCommand(action, screen, commandItem.getId(), commandItem.getName()); + } + + return null; + } + + private Command simpleCommand(Action action, Screen screen, String id, String name) { + return new Command() { + RequestMatcher matcher = RequestMatchers.action(action); + + @Override + public void process(BotRequest botRequest, BotResponse botResponse, CommandChain chain) { + if (matcher.match(botRequest)) { + botResponse.send(screen); + } + chain.processCommand(botRequest, botResponse); + } + + @Override + public String toString() { + return "Command {" + + "id=" + id + + ", name=" + name + + '}'; + } + }; + } +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowResolver.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowResolver.java index 948e2fc..8afb6a9 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowResolver.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowResolver.java @@ -1,7 +1,8 @@ package ru.penkrat.stbf.templates.xml; import ru.penkrat.stbf.templates.ActionResolver; +import ru.penkrat.stbf.templates.CommandResolver; import ru.penkrat.stbf.templates.ScreenResolver; -public interface FlowResolver extends ScreenResolver, ActionResolver { +public interface FlowResolver extends ScreenResolver, ActionResolver, CommandResolver { } diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java index 6582d0a..16aeeb0 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java @@ -26,6 +26,11 @@ class FlowRoot { @JsonProperty("include") private List includes = new ArrayList<>(); + @Getter + @JacksonXmlElementWrapper(localName = "commands") + @JsonProperty("command") + private List commands = new ArrayList<>(); + @Getter private transient List included = new ArrayList<>(); } 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 594db45..9bf17eb 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 @@ -2,12 +2,12 @@ package ru.penkrat.stbf.templates.xml; import lombok.extern.slf4j.Slf4j; import ru.penkrat.stbf.api.Action; +import ru.penkrat.stbf.api.Command; import ru.penkrat.stbf.api.Screen; import ru.penkrat.stbf.templates.TemplateRenderer; -import java.io.File; -import java.io.IOException; import java.io.InputStream; +import java.util.Collection; @Slf4j public class XmlFlowResolver implements FlowResolver { @@ -16,17 +16,20 @@ public class XmlFlowResolver implements FlowResolver { private final FlowActionResolverDelegate actionDelegate; private final FlowScreenResolverDelegate screenDelegate; + private final FlowCommandResolverDelegate commandResolver; public XmlFlowResolver(String filename) { FlowRoot flow = reader.read(filename); actionDelegate = new FlowActionResolverDelegate(flow); screenDelegate = new FlowScreenResolverDelegate(flow, this); + commandResolver = new FlowCommandResolverDelegate(flow, actionDelegate, screenDelegate); } public XmlFlowResolver(InputStream is) { FlowRoot flow = reader.read(is); actionDelegate = new FlowActionResolverDelegate(flow); screenDelegate = new FlowScreenResolverDelegate(flow, this); + commandResolver = new FlowCommandResolverDelegate(flow, actionDelegate, screenDelegate); } @Override @@ -47,4 +50,9 @@ public class XmlFlowResolver implements FlowResolver { public void setTemplateRenderer(TemplateRenderer templateRenderer) { screenDelegate.setTemplateRenderer(templateRenderer); } + + @Override + public Collection getCommands() { + return commandResolver.getCommands(); + } } diff --git a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/FlowCommandsTest.java b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/FlowCommandsTest.java new file mode 100644 index 0000000..72b4b9c --- /dev/null +++ b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/FlowCommandsTest.java @@ -0,0 +1,18 @@ +package ru.penkrat.stbf.templates.xml; + +import org.junit.Test; +import ru.penkrat.stbf.api.Command; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FlowCommandsTest { + + @Test + public void testReadCommands() { + XmlFlowResolver resolver = new XmlFlowResolver("classpath:/ru/penkrat/stbf/templates/xml/flow.xml"); + assertThat(resolver.getCommands()).hasSize(1); + + final Command command = resolver.getCommands().iterator().next(); + assertThat(command.toString()).contains("startCommand"); + } +} diff --git a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java index 16db4cb..2c1f86b 100644 --- a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java +++ b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java @@ -1,10 +1,10 @@ package ru.penkrat.stbf.templates.xml; -import org.junit.Before; -import org.junit.Test; - import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import org.junit.Before; +import org.junit.Test; +import ru.penkrat.stbf.api.Command; public class XmlWriterTest { @@ -52,6 +52,12 @@ public class XmlWriterTest { root.getIncludes().add(new IncludeItem()); + final CommandItem commandItem = new CommandItem(); + commandItem.setActionRef("action-1"); + commandItem.setScreenRef("screen-1"); + commandItem.setClazz(Command.class.getCanonicalName()); + root.getCommands().add(commandItem); + String xml = mapper.writeValueAsString(root); System.out.println(xml); 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 index 84b4c48..27326d7 100644 --- 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 @@ -4,7 +4,7 @@ - Send phone + Start @@ -17,4 +17,7 @@ + + + \ No newline at end of file