Skip to content

Commit

Permalink
[FEATURE]: add parsing scenario from config file
Browse files Browse the repository at this point in the history
  • Loading branch information
Drednote committed Jan 8, 2025
1 parent ffe6bc2 commit 54dd526
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public TelegramControllerBeanPostProcessor(ControllerRegistrar registrar) {
* identifies annotated methods and registers them using the {@link ControllerRegistrar}.
*/
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName)
public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName)
throws BeansException {
Class<?> targetClass = AopUtils.getTargetClass(bean);
TelegramController telegramController = AnnotationUtils.findAnnotation(targetClass,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public ScenarioFactoryBeanPostProcessor(ScenarioFactoryContainer registrar) {
* methods and registers them using the {@link ScenarioFactoryContainer}.
*/
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName)
public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName)
throws BeansException {
Class<?> targetClass = AopUtils.getTargetClass(bean);
TelegramScenario scenarioFactory = AnnotationUtils.findAnnotation(targetClass, TelegramScenario.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;

Expand All @@ -22,8 +23,8 @@ public void registerAction(Object bean, Method method, TelegramScenarioAction ac
HandlerMethod existingHandler = mappingLookup.get(name);
if (existingHandler != null) {
throw new IllegalStateException(

Check warning on line 25 in src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioFactoryContainer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioFactoryContainer.java#L25

Added line #L25 was not covered by tests
"\nAmbiguous mapping. Cannot map '" + handlerMethod.getBean() + "' method \n" +
handlerMethod + "\nto " + name + ": There is already '" +
"\nAmbiguous mapping. Cannot map '" + bean + "' method \n" +
method + "\nto " + name + ": There is already '" +
existingHandler.getBean() + "' bean method\n" + existingHandler + " mapped.");

Check warning on line 28 in src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioFactoryContainer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioFactoryContainer.java#L28

Added line #L28 was not covered by tests
} else {
mappingLookup.put(name, handlerMethod);
Expand All @@ -38,7 +39,7 @@ private static String resolveHandlerName(
if (action.fullName()) {
name = handlerMethod.toString();
} else {
name = bean.getClass().getSimpleName() + "#" + method.getName();
name = AopProxyUtils.ultimateTargetClass(bean).getSimpleName() + "#" + method.getName();
}
} else {
name = action.value();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package io.github.drednote.telegram.handler.scenario.property;

import io.github.drednote.telegram.core.annotation.BetaApi;
import io.github.drednote.telegram.core.annotation.TelegramRequest;
import io.github.drednote.telegram.core.request.MessageType;
import io.github.drednote.telegram.core.request.RequestType;
import io.github.drednote.telegram.handler.scenario.ActionContext;
import io.github.drednote.telegram.handler.scenario.configurer.transition.ScenarioExternalTransitionConfigurer;
import io.github.drednote.telegram.handler.scenario.configurer.transition.ScenarioResponseMessageTransitionConfigurer;
import io.github.drednote.telegram.handler.scenario.configurer.transition.ScenarioRollbackTransitionConfigurer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -13,64 +19,162 @@
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.lang.Nullable;

/**
* This class holds configuration properties for scenarios.
* <p>
* It includes various properties related to scenarios, requests, and rollbacks.
*
* @author Ivan Galushko
*/
@ConfigurationProperties("drednote.telegram.scenario")
@Getter
@Setter
@BetaApi
public class ScenarioProperties {

/**
* A map of scenario names to their corresponding {@link Scenario} objects.
*/
@Nullable
private Map<String, Scenario> values;

/**
* The default rollback configuration, which applies if no another set in scenario object.
*/
@Nullable
private Rollback defaultRollback;

/**
* Represents a scenario with its associated properties and actions.
*/
@Getter
@Setter
public static class Scenario {

/**
* The request associated with this scenario.
*/
private Request request;
/**
* A set of action references names related to this scenario. The name must be exactly the same as in
* {@link TelegramScenarioAction}.
*/
private Set<String> actionReferences;
private TransitionType type = TransitionType.External;
/**
* The type of transition for this scenario. Defaults to {@link TransitionType#EXTERNAL}.
*/
private TransitionType type = TransitionType.EXTERNAL;
/**
* The source state identifier for this scenario.
*/
private String source;
/**
* The target state identifier for this scenario.
*/
private String target;
/**
* A list of nodes representing the graph of this scenario. The graph is explaining the connections between
* different scenarios. The path from one scenario to others. ID is the same as a key in {@link #steps}
* <p>
* Example:
* <pre>{@code graph:
* - id: get
* - id: change
* children:
* - id: lang-change}
* </pre>
*/
private List<Node> graph = new ArrayList<>();
/**
* Only if type == Rollback.
* The rollback configuration, applicable only if the type is {@link TransitionType#ROLLBACK}.
*/
@Nullable
private Rollback rollback;

/**
* A map of additional properties related to this scenario. This props pass to the {@link ActionContext}.
*/
private Map<String, Object> props = new HashMap<>();
/**
* A map of steps associated with this scenario, where each step is another scenario. The keys are the same as
* {@link Node#id} in {@link #graph}.
*/
private Map<String, Scenario> steps = new HashMap<>();

/**
* Enum representing the types of transitions for a scenario.
*/
public enum TransitionType {
Rollback, ResponseMessageProcessing, External
/**
* The type associated with a {@link ScenarioRollbackTransitionConfigurer}
*/
ROLLBACK,
/**
* The type associated with a {@link ScenarioResponseMessageTransitionConfigurer}
*/
RESPONSE_MESSAGE_PROCESSING,
/**
* The type associated with a {@link ScenarioExternalTransitionConfigurer}
*/
EXTERNAL
}
}

/**
* Represents a node in the scenario graph.
*/
@Getter
@Setter
public static class Node {

/**
* The unique identifier for this node.
*/
private String id;
/**
* A list of child nodes for this node.
*/
private List<Node> children = new ArrayList<>();

}

/**
* Represents a request configuration for a scenario.
*/
@Getter
@Setter
public static class Request {

/**
* @see TelegramRequest#pattern()
*/
private Set<String> patterns;
/**
* @see TelegramRequest#requestType()
*/
private Set<RequestType> requestTypes;
/**
* @see TelegramRequest#messageType()
*/
private Set<MessageType> messageTypes = new HashSet<>();
/**
* @see TelegramRequest#exclusiveMessageType()
*/
private boolean exclusiveMessageType = false;
}

/**
* Represents a rollback configuration for a scenario.
*/
@Getter
@Setter
public static class Rollback {

/**
* The request associated with the rollback.
*/
private Request request;
/**
* @see Scenario#actionReferences
*/
private Set<String> actionReferences;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public <S> void configure(ScenarioBuilder<S> scenarioBuilder) {
if (values != null) {
values.forEach((key, scenario) -> {
Assert.required(scenario, "Scenario");
if (scenario.getType() == TransitionType.Rollback) {
if (scenario.getType() == TransitionType.ROLLBACK) {
throw new IllegalArgumentException("First transition cannot be of 'Rollback' type");

Check warning on line 47 in src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioPropertiesConfigurer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioPropertiesConfigurer.java#L47

Added line #L47 was not covered by tests
}
TransitionData<S> transitionData = configureTransition(scenarioBuilder, scenario, null);
Expand Down Expand Up @@ -88,9 +88,9 @@ private <S> TransitionData<S> configureTransition(
source, target, action, telegramRequest, scenario.getProps()
);

if (scenario.getType() == TransitionType.ResponseMessageProcessing) {
if (scenario.getType() == TransitionType.RESPONSE_MESSAGE_PROCESSING) {
transitionData.setResponseMessageProcessing(true);
} else if (scenario.getType() == TransitionType.Rollback) {
} else if (scenario.getType() == TransitionType.ROLLBACK) {
Rollback rollback = firstNonNull(scenario.getRollback(), scenarioProperties.getDefaultRollback());
if (parent == null || rollback == null) {
throw new IllegalArgumentException(

Check warning on line 96 in src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioPropertiesConfigurer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioPropertiesConfigurer.java#L96

Added line #L96 was not covered by tests
Expand All @@ -114,7 +114,7 @@ private List<Action<Object>> createAction(@Nullable Set<String> actionReference)
for (String name : actionReference) {
HandlerMethod handlerMethod = scenarioFactoryResolver.resolveAction(name);
if (handlerMethod == null) {
throw new IllegalArgumentException("Action class name" + name + " not found");
throw new IllegalArgumentException("Action class name '" + name + "' not found");

Check warning on line 117 in src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioPropertiesConfigurer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/io/github/drednote/telegram/handler/scenario/property/ScenarioPropertiesConfigurer.java#L117

Added line #L117 was not covered by tests
}
InvocableHandlerMethod invocableHandlerMethod = new InvocableHandlerMethod(handlerMethod,
"ScenarioFactory");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ private static HttpComponentsClientHttpRequestFactory configureProxy(ProxyUrl pr
}

@Bean
@ConditionalOnMissingBean
public org.telegram.telegrambots.meta.generics.TelegramClient absSender(
SessionProperties properties, TelegramProperties telegramProperties) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ public void setProxyUrl(@Nullable String proxyUrl) {
@RequiredArgsConstructor
public static class ProxyUrl {

@NonNull
private final String host;
private final int port;
@Nullable
private String userName;
@Nullable
private char[] password;
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/application-scenarioproperties.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ drednote:
scenario:
values:
telegram-settings:
type: ResponseMessageProcessing
type: Response_message_processing
request:
patterns: [/telegramsettings]
requestTypes: [MESSAGE]
Expand Down

0 comments on commit 54dd526

Please sign in to comment.