Compare commits
3 Commits
6aece7bb99
...
d47e43edb1
| Author | SHA1 | Date | |
|---|---|---|---|
| d47e43edb1 | |||
| c930070b9c | |||
| 81cac78737 |
@@ -1,24 +1,13 @@
|
|||||||
package ru.penkrat.stbf.impl.pengrad;
|
package ru.penkrat.stbf.impl.pengrad;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import com.google.gson.internal.reflect.ReflectionAccessor;
|
|
||||||
import com.pengrad.telegrambot.TelegramBot;
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
import com.pengrad.telegrambot.model.Update;
|
import com.pengrad.telegrambot.model.Update;
|
||||||
import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
|
import com.pengrad.telegrambot.model.request.*;
|
||||||
import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;
|
|
||||||
import com.pengrad.telegrambot.model.request.KeyboardButton;
|
|
||||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
|
||||||
import com.pengrad.telegrambot.model.request.ReplyKeyboardMarkup;
|
|
||||||
import com.pengrad.telegrambot.request.DeleteMessage;
|
import com.pengrad.telegrambot.request.DeleteMessage;
|
||||||
import com.pengrad.telegrambot.request.EditMessageText;
|
import com.pengrad.telegrambot.request.EditMessageText;
|
||||||
import com.pengrad.telegrambot.request.SendDocument;
|
import com.pengrad.telegrambot.request.SendDocument;
|
||||||
import com.pengrad.telegrambot.request.SendMessage;
|
import com.pengrad.telegrambot.request.SendMessage;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import ru.penkrat.stbf.api.BotResponse;
|
import ru.penkrat.stbf.api.BotResponse;
|
||||||
import ru.penkrat.stbf.api.Screen;
|
import ru.penkrat.stbf.api.Screen;
|
||||||
@@ -45,11 +34,13 @@ public class BotResponseImpl implements BotResponse {
|
|||||||
KeyboardButton[][] keyboard = kk.getKeyboard();
|
KeyboardButton[][] keyboard = kk.getKeyboard();
|
||||||
InlineKeyboardButton[][] inlineKeyboard = kk.getInlineKeyboard();
|
InlineKeyboardButton[][] inlineKeyboard = kk.getInlineKeyboard();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("{}", kk.toFriendlyString());
|
||||||
|
}
|
||||||
|
|
||||||
if (inlineKeyboard != null && inlineKeyboard.length > 0) {
|
if (inlineKeyboard != null && inlineKeyboard.length > 0) {
|
||||||
logKeyboard(inlineKeyboard);
|
|
||||||
sendMessage = sendMessage.replyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
sendMessage = sendMessage.replyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
||||||
} else if (keyboard != null && keyboard.length > 0) {
|
} else if (keyboard != null && keyboard.length > 0) {
|
||||||
logKeyboard(keyboard);
|
|
||||||
sendMessage = sendMessage.replyMarkup(new ReplyKeyboardMarkup(keyboard));
|
sendMessage = sendMessage.replyMarkup(new ReplyKeyboardMarkup(keyboard));
|
||||||
} else {
|
} else {
|
||||||
log.debug("No keyboard");
|
log.debug("No keyboard");
|
||||||
@@ -82,8 +73,11 @@ public class BotResponseImpl implements BotResponse {
|
|||||||
KeyboardImpl kk = (KeyboardImpl) screen.getKeyboard();
|
KeyboardImpl kk = (KeyboardImpl) screen.getKeyboard();
|
||||||
InlineKeyboardButton[][] inlineKeyboard = kk.getInlineKeyboard();
|
InlineKeyboardButton[][] inlineKeyboard = kk.getInlineKeyboard();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("{}", kk.toFriendlyString());
|
||||||
|
}
|
||||||
|
|
||||||
if (inlineKeyboard != null && inlineKeyboard.length > 0) {
|
if (inlineKeyboard != null && inlineKeyboard.length > 0) {
|
||||||
logKeyboard(inlineKeyboard);
|
|
||||||
editMessage = editMessage.replyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
editMessage = editMessage.replyMarkup(new InlineKeyboardMarkup(inlineKeyboard));
|
||||||
} else {
|
} else {
|
||||||
log.debug("No keyboard");
|
log.debug("No keyboard");
|
||||||
@@ -112,40 +106,4 @@ public class BotResponseImpl implements BotResponse {
|
|||||||
return update.message().messageId();
|
return update.message().messageId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logKeyboard(KeyboardButton[][] keyboard) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
for (int i = 0; i < keyboard.length; i++) {
|
|
||||||
if (keyboard[i].length > 0) {
|
|
||||||
String row = Stream.of(keyboard[i]).map(this::getText).collect(Collectors.joining(" | "));
|
|
||||||
log.debug("Keyboard: {}", row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logKeyboard(InlineKeyboardButton[][] keyboard) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
for (int i = 0; i < keyboard.length; i++) {
|
|
||||||
if (keyboard[i].length > 0) {
|
|
||||||
String row = Stream.of(keyboard[i]).map(this::getText).collect(Collectors.joining(" | "));
|
|
||||||
log.debug("Inline keyboard: {}", row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private String getText(KeyboardButton btn) {
|
|
||||||
Field text = KeyboardButton.class.getDeclaredField("text");
|
|
||||||
ReflectionAccessor.getInstance().makeAccessible(text);
|
|
||||||
return String.valueOf(text.get(btn));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private String getText(InlineKeyboardButton btn) {
|
|
||||||
Field text = InlineKeyboardButton.class.getDeclaredField("text");
|
|
||||||
ReflectionAccessor.getInstance().makeAccessible(text);
|
|
||||||
return String.valueOf(text.get(btn));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
package ru.penkrat.stbf.impl.pengrad;
|
package ru.penkrat.stbf.impl.pengrad;
|
||||||
|
|
||||||
|
import com.google.gson.internal.reflect.ReflectionAccessor;
|
||||||
import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
|
import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
|
||||||
import com.pengrad.telegrambot.model.request.KeyboardButton;
|
import com.pengrad.telegrambot.model.request.KeyboardButton;
|
||||||
|
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import ru.penkrat.stbf.api.Keyboard;
|
import ru.penkrat.stbf.api.Keyboard;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
class KeyboardImpl implements Keyboard {
|
class KeyboardImpl implements Keyboard {
|
||||||
|
|
||||||
@@ -13,4 +19,50 @@ class KeyboardImpl implements Keyboard {
|
|||||||
|
|
||||||
private InlineKeyboardButton[][] inlineKeyboard;
|
private InlineKeyboardButton[][] inlineKeyboard;
|
||||||
|
|
||||||
|
private Map<Object, String> text = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
int k = keyboard != null ? keyboard.length : 0;
|
||||||
|
int kn = k > 0 ? keyboard[0].length : 0;
|
||||||
|
int i = inlineKeyboard != null ? inlineKeyboard.length : 0;
|
||||||
|
int in = i > 0 ? inlineKeyboard[0].length : 0;
|
||||||
|
return "KeyboardImpl(pengrad) [keyboard=" + k + "x" + kn
|
||||||
|
+ ", inline=" + i + "x" + in + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
String toFriendlyString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (keyboard != null) {
|
||||||
|
sb.append("Keyboard:\n");
|
||||||
|
for (int i = 0; i < keyboard.length; i++) {
|
||||||
|
if (keyboard[i].length > 0) {
|
||||||
|
String row = Stream.of(keyboard[i]).map(this::getText).collect(Collectors.joining(" | "));
|
||||||
|
sb.append(row).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inlineKeyboard != null) {
|
||||||
|
sb.append("Inline keyboard:\n");
|
||||||
|
for (int i = 0; i < inlineKeyboard.length; i++) {
|
||||||
|
if (inlineKeyboard[i].length > 0) {
|
||||||
|
String row = Stream.of(inlineKeyboard[i]).map(this::getText).collect(Collectors.joining(" | "));
|
||||||
|
sb.append(row).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getText(Object btn) {
|
||||||
|
return text.computeIfAbsent(btn, o -> {
|
||||||
|
try {
|
||||||
|
Field text = btn.getClass().getDeclaredField("text");
|
||||||
|
ReflectionAccessor.getInstance().makeAccessible(text);
|
||||||
|
return String.valueOf(text.get(btn));
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
return "*error*";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ public class PengradKeyboardBuilder implements KeyboardBuilder {
|
|||||||
|
|
||||||
private InlineKeyboardButton[][] inlineKeyboard;
|
private InlineKeyboardButton[][] inlineKeyboard;
|
||||||
|
|
||||||
|
private String keyboardStr = "";
|
||||||
|
|
||||||
public static Keyboard singleKey(Action action) {
|
public static Keyboard singleKey(Action action) {
|
||||||
return KeyboardBuilder.newKeyboard().add(action).build();
|
return KeyboardBuilder.newKeyboard().add(action).build();
|
||||||
}
|
}
|
||||||
@@ -123,7 +125,6 @@ public class PengradKeyboardBuilder implements KeyboardBuilder {
|
|||||||
n[k.length] = btn;
|
n[k.length] = btn;
|
||||||
keyboard[keyboard.length - 1] = n;
|
keyboard[keyboard.length - 1] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void put(InlineKeyboardButton btn) {
|
private void put(InlineKeyboardButton btn) {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.penkrat.stbf.templates;
|
||||||
|
|
||||||
|
import ru.penkrat.stbf.api.Action;
|
||||||
|
|
||||||
|
public interface ActionResolver {
|
||||||
|
|
||||||
|
Action getAction(String name);
|
||||||
|
}
|
||||||
@@ -4,36 +4,48 @@ import lombok.experimental.UtilityClass;
|
|||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class ReflectionUtils {
|
public class ReflectionUtils {
|
||||||
|
|
||||||
public <T> T getMethodResult(Object context, String methodName, Class<T> clazz) {
|
public <T> T getMethodResult(Object context, String methodName, Class<T> clazz) {
|
||||||
|
return getMethod(context.getClass(), methodName)
|
||||||
|
.map(invoker(context, clazz))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Method> getMethod(Class<?> clazz, String methodName) {
|
||||||
try {
|
try {
|
||||||
Method method = context.getClass().getMethod(methodName);
|
Method method = clazz.getMethod(methodName);
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
Object result = method.invoke(context);
|
return Optional.of(method);
|
||||||
if (result != null && clazz.isAssignableFrom(result.getClass())) {
|
} catch (NoSuchMethodException e) {
|
||||||
|
// try find as private
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Method method = clazz.getDeclaredMethod(methodName);
|
||||||
|
method.setAccessible(true);
|
||||||
|
return Optional.of(method);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> Function<Method, T> invoker(Object target, Class<T> resultClass) {
|
||||||
|
return (method) -> {
|
||||||
|
Object result = null;
|
||||||
|
try {
|
||||||
|
result = method.invoke(target);
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
if (result != null && resultClass.isAssignableFrom(result.getClass())) {
|
||||||
return (T) result;
|
return (T) result;
|
||||||
}
|
}
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package ru.penkrat.stbf.templates.utils;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class StringUtils {
|
||||||
|
|
||||||
|
public boolean isEmpty(String string) {
|
||||||
|
return string == null || string.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotEmpty(String string) {
|
||||||
|
return !isEmpty(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
class ActionItem extends NamedItem {
|
||||||
|
|
||||||
|
@JacksonXmlText
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String command;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private boolean requestContact;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private boolean requestLocation;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String callbackData;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package ru.penkrat.stbf.templates.xml;
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -13,7 +11,10 @@ import lombok.Setter;
|
|||||||
@Setter
|
@Setter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@JacksonXmlRootElement(localName = "button")
|
@JacksonXmlRootElement(localName = "button")
|
||||||
class Button {
|
class Button extends NamedItem {
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String actionRef;
|
||||||
|
|
||||||
@JacksonXmlText
|
@JacksonXmlText
|
||||||
private String text;
|
private String text;
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import ru.penkrat.stbf.api.Action;
|
||||||
|
import ru.penkrat.stbf.templates.ActionResolver;
|
||||||
|
import ru.penkrat.stbf.templates.utils.StringUtils;
|
||||||
|
|
||||||
|
class FlowActionResolverDelegate implements ActionResolver {
|
||||||
|
|
||||||
|
private final NamedItemResolver<ActionItem> resolver;
|
||||||
|
|
||||||
|
FlowActionResolverDelegate(FlowRoot src) {
|
||||||
|
resolver = new NamedItemResolver<>(Traversal.traverse(src, FlowRoot::getActions));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action getAction(String key) {
|
||||||
|
final ActionItem actionItem = resolver.get(key);
|
||||||
|
|
||||||
|
boolean isInline = StringUtils.isNotEmpty(actionItem.getCallbackData())
|
||||||
|
&& StringUtils.isNotEmpty(actionItem.getUrl());
|
||||||
|
|
||||||
|
if (isInline) {
|
||||||
|
if (StringUtils.isNotEmpty(actionItem.getCommand())) {
|
||||||
|
throw new IllegalArgumentException("'command' is not allowed for inline button");
|
||||||
|
}
|
||||||
|
if (actionItem.isRequestContact()) {
|
||||||
|
throw new IllegalArgumentException("'requestContact' is not allowed for inline button");
|
||||||
|
}
|
||||||
|
if (actionItem.isRequestLocation()) {
|
||||||
|
throw new IllegalArgumentException("'requestLocation' is not allowed for inline button");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Action.builder()
|
||||||
|
.text(actionItem.getText())
|
||||||
|
// btn only
|
||||||
|
.cmd(actionItem.getCommand())
|
||||||
|
.requestContact(actionItem.isRequestContact())
|
||||||
|
.requestLocation(actionItem.isRequestLocation())
|
||||||
|
// inline btn only
|
||||||
|
.inline(isInline)
|
||||||
|
.callbackData(actionItem.getCallbackData())
|
||||||
|
.url(actionItem.getUrl())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<FlowRoot> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import ru.penkrat.stbf.templates.ActionResolver;
|
||||||
|
import ru.penkrat.stbf.templates.ScreenResolver;
|
||||||
|
|
||||||
|
public interface FlowResolver extends ScreenResolver, ActionResolver {
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@JacksonXmlRootElement(localName = "flow")
|
||||||
|
class FlowRoot {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@JacksonXmlElementWrapper(localName = "actions")
|
||||||
|
@JsonProperty("action")
|
||||||
|
private List<ActionItem> actions = new ArrayList<>();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@JacksonXmlElementWrapper(localName = "screens")
|
||||||
|
@JsonProperty("screen")
|
||||||
|
private List<ScreenItem> screens = new ArrayList<>();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@JacksonXmlElementWrapper(useWrapping = false)
|
||||||
|
@JsonProperty("include")
|
||||||
|
private List<IncludeItem> includes = new ArrayList<>();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private transient List<FlowRoot> included = new ArrayList<>();
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package ru.penkrat.stbf.templates.xml;
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
@@ -9,46 +8,41 @@ import ru.penkrat.stbf.api.Keyboard;
|
|||||||
import ru.penkrat.stbf.api.KeyboardBuilder;
|
import ru.penkrat.stbf.api.KeyboardBuilder;
|
||||||
import ru.penkrat.stbf.api.Screen;
|
import ru.penkrat.stbf.api.Screen;
|
||||||
import ru.penkrat.stbf.common.screen.TextScreen;
|
import ru.penkrat.stbf.common.screen.TextScreen;
|
||||||
|
import ru.penkrat.stbf.templates.ActionResolver;
|
||||||
|
import ru.penkrat.stbf.templates.KeyboardProvider;
|
||||||
import ru.penkrat.stbf.templates.ScreenResolver;
|
import ru.penkrat.stbf.templates.ScreenResolver;
|
||||||
import ru.penkrat.stbf.templates.TemplateRenderer;
|
import ru.penkrat.stbf.templates.TemplateRenderer;
|
||||||
import ru.penkrat.stbf.templates.utils.ReflectionUtils;
|
import ru.penkrat.stbf.templates.utils.ReflectionUtils;
|
||||||
|
import ru.penkrat.stbf.templates.utils.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class XmlScreenResolver implements ScreenResolver {
|
class FlowScreenResolverDelegate implements ScreenResolver {
|
||||||
|
|
||||||
private final XmlMapper mapper = new XmlMapper();
|
private final NamedItemResolver<ScreenItem> resolver;
|
||||||
|
|
||||||
private final Map<String, List<ScreenItem>> byId;
|
private final ActionResolver actionResolver;
|
||||||
private final Map<String, List<ScreenItem>> byName;
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private TemplateRenderer templateRenderer = new NoopTemplateRenderer();
|
private TemplateRenderer templateRenderer = new NoopTemplateRenderer();
|
||||||
|
|
||||||
public XmlScreenResolver(InputStream is) throws IOException {
|
FlowScreenResolverDelegate(FlowRoot src, ActionResolver actionResolver) {
|
||||||
Screens screens = mapper.readValue(is, Screens.class);
|
this.actionResolver = actionResolver;
|
||||||
|
resolver = new NamedItemResolver<>(Traversal.traverse(src, FlowRoot::getScreens));
|
||||||
byId = screens.getScreens().stream()
|
|
||||||
.collect(Collectors.groupingBy(ScreenItem::getId));
|
|
||||||
byName = screens.getScreens().stream()
|
|
||||||
.collect(Collectors.groupingBy(ScreenItem::getName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Screen getScreen(String name) {
|
public Screen getScreen(String name) {
|
||||||
ScreenItem item = get(name);
|
ScreenItem item = resolver.get(name);
|
||||||
|
|
||||||
return new TextScreen(item.getText(), buildKeyboard(item.getKeyboard(), null));
|
return new TextScreen(item.getText(), buildKeyboard(item.getKeyboard(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Screen getScreen(String name, Object context) {
|
public Screen getScreen(String name, Object context) {
|
||||||
ScreenItem item = get(name);
|
ScreenItem item = resolver.get(name);
|
||||||
|
|
||||||
return new TextScreen(templateRenderer.render(item.getText(), context),
|
return new TextScreen(templateRenderer.render(item.getText(), context),
|
||||||
resolveKeyboard(item.getKeyboard(), context));
|
resolveKeyboard(item.getKeyboard(), context));
|
||||||
@@ -58,6 +52,13 @@ public class XmlScreenResolver implements ScreenResolver {
|
|||||||
if (wrapper == null)
|
if (wrapper == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (context instanceof KeyboardProvider) {
|
||||||
|
final Keyboard keyboard = ((KeyboardProvider) context).getKeyboard();
|
||||||
|
if (keyboard == null) {
|
||||||
|
log.warn("Method 'getKeyboard' returns NULL value!", wrapper.getFactoryMethod());
|
||||||
|
}
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
if (wrapper.getFactoryMethod() != null && !wrapper.getFactoryMethod().isEmpty() && context != null) {
|
if (wrapper.getFactoryMethod() != null && !wrapper.getFactoryMethod().isEmpty() && context != null) {
|
||||||
val keyboard = ReflectionUtils.getMethodResult(context, wrapper.getFactoryMethod(), Keyboard.class);
|
val keyboard = ReflectionUtils.getMethodResult(context, wrapper.getFactoryMethod(), Keyboard.class);
|
||||||
if (keyboard == null) {
|
if (keyboard == null) {
|
||||||
@@ -77,11 +78,7 @@ public class XmlScreenResolver implements ScreenResolver {
|
|||||||
for (ButtonsRow row : wrapper.getRows()) {
|
for (ButtonsRow row : wrapper.getRows()) {
|
||||||
List<Action> buttons = row.getButtons().stream()
|
List<Action> buttons = row.getButtons().stream()
|
||||||
.filter(btn -> checkIfCondition(context, btn.getIfCondition()))
|
.filter(btn -> checkIfCondition(context, btn.getIfCondition()))
|
||||||
.map(btn -> Action.builder()
|
.map(btn -> getAction(btn))
|
||||||
.text(btn.getText())
|
|
||||||
.requestContact(btn.isRequestContact())
|
|
||||||
.requestLocation(btn.isRequestLocation())
|
|
||||||
.build())
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
builder.row(buttons.toArray(new Action[buttons.size()]));
|
builder.row(buttons.toArray(new Action[buttons.size()]));
|
||||||
@@ -92,6 +89,17 @@ public class XmlScreenResolver implements ScreenResolver {
|
|||||||
return keyboard;
|
return keyboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Action getAction(Button btn) {
|
||||||
|
if (StringUtils.isNotEmpty(btn.getActionRef())) {
|
||||||
|
return actionResolver.getAction(btn.getActionRef());
|
||||||
|
}
|
||||||
|
return Action.builder()
|
||||||
|
.text(btn.getText())
|
||||||
|
.requestContact(btn.isRequestContact())
|
||||||
|
.requestLocation(btn.isRequestLocation())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkIfCondition(Object context, String ifCondition) {
|
private boolean checkIfCondition(Object context, String ifCondition) {
|
||||||
if (ifCondition == null || ifCondition.isEmpty()) {
|
if (ifCondition == null || ifCondition.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
@@ -109,22 +117,4 @@ public class XmlScreenResolver implements ScreenResolver {
|
|||||||
|
|
||||||
return ReflectionUtils.getMethodResult(context, ifCondition, Boolean.class);
|
return ReflectionUtils.getMethodResult(context, ifCondition, Boolean.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScreenItem get(String key) {
|
|
||||||
List<ScreenItem> list = byId.get(key);
|
|
||||||
if (list != null) {
|
|
||||||
if (list.size() > 1) {
|
|
||||||
throw new IllegalStateException("Non unique 'id' " + key);
|
|
||||||
}
|
|
||||||
return list.get(0);
|
|
||||||
}
|
|
||||||
list = byName.get(key);
|
|
||||||
if (list != null) {
|
|
||||||
if (list.size() > 1) {
|
|
||||||
throw new IllegalStateException("Non unique 'name' " + key);
|
|
||||||
}
|
|
||||||
return list.get(0);
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Screen not found by 'id' or 'name' " + key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
class IncludeItem {
|
||||||
|
private String file;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
abstract class NamedItem {
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String ref;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import ru.penkrat.stbf.templates.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
class NamedItemResolver<T extends NamedItem> {
|
||||||
|
|
||||||
|
private final Map<String, List<T>> byId;
|
||||||
|
private final Map<String, List<T>> byName;
|
||||||
|
|
||||||
|
NamedItemResolver(Collection<T> src) {
|
||||||
|
byId = src.stream()
|
||||||
|
.filter(item -> StringUtils.isNotEmpty(item.getId()))
|
||||||
|
.collect(Collectors.groupingBy(NamedItem::getId));
|
||||||
|
byName = src.stream()
|
||||||
|
.filter(item -> StringUtils.isNotEmpty(item.getName()))
|
||||||
|
.collect(Collectors.groupingBy(NamedItem::getName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get(String key) {
|
||||||
|
List<T> list = byId.get(key);
|
||||||
|
if (list != null) {
|
||||||
|
if (list.size() > 1) {
|
||||||
|
throw new IllegalStateException("Non unique 'id' " + key);
|
||||||
|
}
|
||||||
|
return list.get(0);
|
||||||
|
}
|
||||||
|
list = byName.get(key);
|
||||||
|
if (list != null) {
|
||||||
|
if (list.size() > 1) {
|
||||||
|
throw new IllegalStateException("Non unique 'name' " + key);
|
||||||
|
}
|
||||||
|
return list.get(0);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Element not found by 'id' or 'name' " + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,19 +1,11 @@
|
|||||||
package ru.penkrat.stbf.templates.xml;
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
class ScreenItem {
|
class ScreenItem extends NamedItem {
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true)
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true)
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package ru.penkrat.stbf.templates.xml;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@JacksonXmlRootElement(localName = "screens")
|
|
||||||
class Screens {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@JacksonXmlElementWrapper(useWrapping = false, localName = "screen")
|
|
||||||
@JsonProperty("screen")
|
|
||||||
private List<ScreenItem> screens = new ArrayList<>();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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 <T> Collection<T> traverse(FlowRoot flow, Function<FlowRoot, Collection<T>> getter) {
|
||||||
|
final ArrayList<T> target = new ArrayList<>();
|
||||||
|
traverse(flow, getter, target);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> void traverse(FlowRoot flow, Function<FlowRoot, Collection<T>> getter, Collection<T> target) {
|
||||||
|
Collection<T> c = getter.apply(flow);
|
||||||
|
target.addAll(c);
|
||||||
|
|
||||||
|
flow.getIncluded().forEach(f -> traverse(f, getter, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
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 FlowParser reader = new FlowParser();
|
||||||
|
|
||||||
|
private final FlowActionResolverDelegate actionDelegate;
|
||||||
|
private final FlowScreenResolverDelegate screenDelegate;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Screen getScreen(String name) {
|
||||||
|
return screenDelegate.getScreen(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Screen getScreen(String name, Object context) {
|
||||||
|
return screenDelegate.getScreen(name, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action getAction(String name) {
|
||||||
|
return actionDelegate.getAction(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplateRenderer(TemplateRenderer templateRenderer) {
|
||||||
|
screenDelegate.setTemplateRenderer(templateRenderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package ru.penkrat.stbf.templates.xml;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import ru.penkrat.stbf.api.Keyboard;
|
||||||
|
import ru.penkrat.stbf.api.KeyboardBuilder;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class XmlFlowResolverTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRead() throws Exception {
|
||||||
|
InputStream xmlUnderTest = XmlFlowResolverTest.class.getResourceAsStream("screens.xml");
|
||||||
|
|
||||||
|
XmlFlowResolver resolver = new XmlFlowResolver(xmlUnderTest);
|
||||||
|
|
||||||
|
Screen screen1 = resolver.getScreen("screen-1");
|
||||||
|
|
||||||
|
assertThat(screen1).isNotNull();
|
||||||
|
assertThat(screen1.getText()).isEqualTo("Test text");
|
||||||
|
|
||||||
|
assertThat(screen1.getKeyboard()).isNotNull();
|
||||||
|
|
||||||
|
String keyboard = ReflectionUtils.getMethodResult(screen1.getKeyboard(), "toFriendlyString", String.class);
|
||||||
|
assertThat(keyboard).contains("Send phone");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadWithTemplates() throws Exception {
|
||||||
|
InputStream xmlUnderTest = XmlFlowResolverTest.class.getResourceAsStream("screens.xml");
|
||||||
|
|
||||||
|
XmlFlowResolver resolver = new XmlFlowResolver(xmlUnderTest);
|
||||||
|
resolver.setTemplateRenderer(new MustacheRenderer());
|
||||||
|
|
||||||
|
Keyboard keyboard = KeyboardBuilder.newKeyboard().build();
|
||||||
|
Screen screen2 = resolver.getScreen("screen-2", new Object() {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public String name = "Tester";
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public Keyboard getKeyboard() {
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(screen2).isNotNull();
|
||||||
|
assertThat(screen2.getText()).isEqualTo("Hello, Tester");
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package ru.penkrat.stbf.templates.xml;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import ru.penkrat.stbf.api.Keyboard;
|
|
||||||
import ru.penkrat.stbf.api.KeyboardBuilder;
|
|
||||||
import ru.penkrat.stbf.api.Screen;
|
|
||||||
import ru.penkrat.stbf.templates.impl.MustacheRenderer;
|
|
||||||
|
|
||||||
public class XmlScreenResolverTest {
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRead() throws Exception {
|
|
||||||
InputStream xmlUnderTest = XmlScreenResolverTest.class.getResourceAsStream("screens.xml");
|
|
||||||
|
|
||||||
XmlScreenResolver resolver = new XmlScreenResolver(xmlUnderTest);
|
|
||||||
|
|
||||||
Screen screen1 = resolver.getScreen("screen-1");
|
|
||||||
|
|
||||||
assertThat(screen1).isNotNull();
|
|
||||||
assertThat(screen1.getText()).isEqualTo("Test text");
|
|
||||||
|
|
||||||
assertThat(screen1.getKeyboard()).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadWithTemplates() throws Exception {
|
|
||||||
InputStream xmlUnderTest = XmlScreenResolverTest.class.getResourceAsStream("screens.xml");
|
|
||||||
|
|
||||||
XmlScreenResolver resolver = new XmlScreenResolver(xmlUnderTest);
|
|
||||||
resolver.setTemplateRenderer(new MustacheRenderer());
|
|
||||||
|
|
||||||
Keyboard keyboard = KeyboardBuilder.newKeyboard().build();
|
|
||||||
Screen screen2 = resolver.getScreen("screen-2", new Object() {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public String name = "Tester";
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public Keyboard getKeyboard() {
|
|
||||||
return keyboard;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assertThat(screen2).isNotNull();
|
|
||||||
assertThat(screen2.getText()).isEqualTo("Hello, Tester");
|
|
||||||
|
|
||||||
assertThat(screen2.getKeyboard()).isEqualTo(keyboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,11 +6,6 @@ import org.junit.Test;
|
|||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||||
|
|
||||||
import ru.penkrat.stbf.templates.xml.Button;
|
|
||||||
import ru.penkrat.stbf.templates.xml.ButtonsRow;
|
|
||||||
import ru.penkrat.stbf.templates.xml.ScreenItem;
|
|
||||||
import ru.penkrat.stbf.templates.xml.Screens;
|
|
||||||
|
|
||||||
public class XmlWriterTest {
|
public class XmlWriterTest {
|
||||||
|
|
||||||
private final XmlMapper mapper = new XmlMapper();
|
private final XmlMapper mapper = new XmlMapper();
|
||||||
@@ -18,11 +13,12 @@ public class XmlWriterTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
|
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWrite() throws Exception {
|
public void testWrite() throws Exception {
|
||||||
Screens root = new Screens();
|
FlowRoot root = new FlowRoot();
|
||||||
|
|
||||||
ScreenItem item1 = new ScreenItem();
|
ScreenItem item1 = new ScreenItem();
|
||||||
item1.setId("1");
|
item1.setId("1");
|
||||||
@@ -52,6 +48,10 @@ public class XmlWriterTest {
|
|||||||
root.getScreens().add(item1);
|
root.getScreens().add(item1);
|
||||||
root.getScreens().add(item2);
|
root.getScreens().add(item2);
|
||||||
|
|
||||||
|
root.getActions().add(new ActionItem());
|
||||||
|
|
||||||
|
root.getIncludes().add(new IncludeItem());
|
||||||
|
|
||||||
String xml = mapper.writeValueAsString(root);
|
String xml = mapper.writeValueAsString(root);
|
||||||
|
|
||||||
System.out.println(xml);
|
System.out.println(xml);
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<flow>
|
||||||
|
|
||||||
|
<include file="screens.xml"/>
|
||||||
|
<include file="/test/a.xml"/>
|
||||||
|
|
||||||
|
<actions>
|
||||||
|
<action id="2001" requestContact="true">Send phone</action>
|
||||||
|
</actions>
|
||||||
|
<screens>
|
||||||
|
<screen id="5001" name="screen-5001">
|
||||||
|
<text>Test text</text>
|
||||||
|
<keyboard>
|
||||||
|
<row>
|
||||||
|
<button>Btn1</button>
|
||||||
|
<button>Btn2</button>
|
||||||
|
</row>
|
||||||
|
</keyboard>
|
||||||
|
</screen>
|
||||||
|
</screens>
|
||||||
|
</flow>
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
<flow>
|
||||||
|
<actions>
|
||||||
|
<action id="1001" requestContact="true">Send phone</action>
|
||||||
|
</actions>
|
||||||
<screens>
|
<screens>
|
||||||
<screen id="1" name="screen-1">
|
<screen id="1" name="screen-1">
|
||||||
<text>Test text</text>
|
<text>Test text</text>
|
||||||
@@ -5,6 +9,7 @@
|
|||||||
<row>
|
<row>
|
||||||
<button if="false">Btn1</button>
|
<button if="false">Btn1</button>
|
||||||
<button>Btn2</button>
|
<button>Btn2</button>
|
||||||
|
<button actionRef="1001">Action.name</button>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<button>Btn1</button>
|
<button>Btn1</button>
|
||||||
@@ -17,3 +22,4 @@
|
|||||||
<keyboard factoryMethod="getKeyboard"/>
|
<keyboard factoryMethod="getKeyboard"/>
|
||||||
</screen>
|
</screen>
|
||||||
</screens>
|
</screens>
|
||||||
|
</flow>
|
||||||
6
stbf-templates/src/test/resources/test/a.xml
Normal file
6
stbf-templates/src/test/resources/test/a.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<flow>
|
||||||
|
<include file="/test/b/b.xml"/>
|
||||||
|
<actions>
|
||||||
|
<action id="3001">A action</action>
|
||||||
|
</actions>
|
||||||
|
</flow>
|
||||||
5
stbf-templates/src/test/resources/test/b/b.xml
Normal file
5
stbf-templates/src/test/resources/test/b/b.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<flow>
|
||||||
|
<actions>
|
||||||
|
<action id="4001">B action</action>
|
||||||
|
</actions>
|
||||||
|
</flow>
|
||||||
Reference in New Issue
Block a user