Skip to content

4. Chaining

Max edited this page Jul 6, 2022 · 3 revisions

1. Chaining configuration

In order to start using chaining, we need to implement the SpringramUserDetailsService interface. This interface is responsible for providing data about the current user chain to the library.

Let's write a simple implementation class that will use some kind of repository and return the SpringramUserDetails implementation.

@Service
public class MyUserDetailsService implements SpringramUserDetailsService {
    private final UserRepository repository;

    public MyUserDetailsService(UserRepository repository) {
        this.repository = repository;
    }

    @Nullable
    @Override
    public SpringramUserDetails loadById(long id) {
        final User byId = repository.getById(id);
        return byId == null ? null : new MySpringramUserDetails(byId);
    }

    record MySpringramUserDetails(User user) implements SpringramUserDetails {
        @Nullable
        @Override
        public String getChain() {
            return user.getChain();
        }
    }
}

Now we need to set our service in the configuration, below is an example of how to do this.

@Configuration
public class MySpringramConfigurer implements SpringramConfigurer {
    private final SpringramUserDetailsService userDetailsService;

    public MySpringramConfigurer(SpringramUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public void configurePathMatcher(PathMatchingConfigurer configurer) {
        configurer.setUserDetailsService(userDetailsService);
    }
}

2. Using chaining

Now, using the @Chain annotation, we can specify which chain the handler method belongs to.

@BotController
public class SayController {
    private static final String MESSAGE_INPUT_CHAIN = "say/message-input";
    private final UserService userService;

    public SayController(UserService userService) {
        this.userService = userService;
    }

    @CommandMapping("say")
    public SendMessage say(ChatTextMessage message) {
        final User user = userService.getUser(message.getFromUser().getId());
        user.setChain(MESSAGE_INPUT_CHAIN);
        userService.saveUser(user);

        return SendMessage.builder()
                .chatId(String.valueOf(message.getChatId()))
                .text("Send message now")
                .build();
    }

    @CommandMapping
    @Chain(MESSAGE_INPUT_CHAIN)
    public SendMessage sayInput(ChatTextMessage message) {
        final User user = userService.getUser(message.getFromUser().getId());
        user.setChain(null);
        userService.saveUser(user);

        return SendMessage.builder()
                .chatId(String.valueOf(message.getChatId()))
                .text("Awesome! You typed: " + message.getText())
                .build();
    }
}

Since we are storing the chain data in our user, we simply set the value with a setter and then save it to the database.

As you can see, the library does not store any state. It is up to you as the developer to determine where the state will be stored and how you will update it. This approach allows you to write more productive and understandable code, and the library eliminates unnecessary complexity.

Clone this wiki locally