Passed
Push — master ( ec853f...5c2486 )
by Roannel Fernández
02:47
created

com.github.netkorp.telegram.framework.managers.CommandManager   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 236
Duplicated Lines 0 %

Importance

Changes 9
Bugs 0 Features 0
Metric Value
dl 0
loc 236
rs 10
c 9
b 0
f 0
eloc 63
wmc 25

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getActiveCommand(Long) 0 6 2
A hasActiveCommand(Long) 0 2 1
A setActiveCommand(Long,MultistageCommand) 0 2 1
A removeActiveCommand(Long) 0 2 1
B addCommand(Command) 0 16 7
A getCommand(String) 0 6 2
A getHelpCommand() 0 2 1
A getAvailableCommands() 0 2 1
A getCloseCommand() 0 2 1
A getCommandFullName(String) 0 2 2
A getAvailableNonSecureCommands() 0 2 1
A getCommandFullName(Command) 0 2 1
A getDoneCommand() 0 2 1
A getCommandName(Command) 0 3 1
A isNonSecureCommand(Command) 0 2 1
A CommandManager(List,CommandProperties) 0 11 1
1
package com.github.netkorp.telegram.framework.managers;
2
3
import com.github.netkorp.telegram.framework.annotations.TelegramCommand;
4
import com.github.netkorp.telegram.framework.commands.interfaces.Command;
5
import com.github.netkorp.telegram.framework.commands.interfaces.HelpCommand;
6
import com.github.netkorp.telegram.framework.commands.interfaces.MultistageCommand;
7
import com.github.netkorp.telegram.framework.commands.multistage.MultistageCloseCommand;
8
import com.github.netkorp.telegram.framework.commands.multistage.MultistageDoneCommand;
9
import com.github.netkorp.telegram.framework.properties.CommandProperties;
10
import com.github.netkorp.telegram.framework.exceptions.CommandNotActive;
11
import com.github.netkorp.telegram.framework.exceptions.CommandNotFound;
12
import org.springframework.beans.factory.annotation.Autowired;
13
import org.springframework.stereotype.Component;
14
15
import java.util.Collection;
16
import java.util.HashMap;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Optional;
20
21
/**
22
 * Provides the component for managing all of the commands available in the bot.
23
 * It includes the management of non-secure commands, active command, basic commands and
24
 * those commands that are involved in the multistage command flow.
25
 */
26
@SuppressWarnings("WeakerAccess")
27
@Component
28
public class CommandManager {
29
30
    /**
31
     * The list of the available commands into a map to get a quick access from its name.
32
     */
33
    private final Map<String, Command> commands;
34
35
    /**
36
     * The list of the non-secure commands into a map to get a quick access from its name.
37
     */
38
    private final Map<String, Command> nonSecureCommands;
39
40
    /**
41
     * The command that is active for each user.
42
     */
43
    private final Map<Long, MultistageCommand> activeCommand;
44
45
    /**
46
     * The properties of the commands.
47
     */
48
    private final CommandProperties commandProperties;
49
50
    /**
51
     * The command that closes an active conversation with the bot, indicating to the active command that the conversation is closed.
52
     * It is kept here for a quick access to the close command.
53
     */
54
    private MultistageCloseCommand closeCommand;
55
56
    /**
57
     * The command that closes an active conversation with the bot, indicating to the active command that the conversation is done.
58
     * It is kept here for a quick access to the done command.
59
     */
60
    private MultistageDoneCommand doneCommand;
61
62
    /**
63
     * The command that shows the help of the bot.
64
     * It is kept here for a quick access to the help command.
65
     */
66
    private HelpCommand helpCommand;
67
68
    /**
69
     * Constructs a new {@link CommandManager} instance with the list of available {@link Command}
70
     * and the properties of the commands.
71
     *
72
     * @param commands          the list of available {@link Command}.
73
     * @param commandProperties the properties of the commands.
74
     */
75
    @Autowired
76
    public CommandManager(List<Command> commands, CommandProperties commandProperties) {
77
        this.commands = new HashMap<>();
78
        this.nonSecureCommands = new HashMap<>();
79
80
        this.activeCommand = new HashMap<>();
81
        this.commandProperties = commandProperties;
82
83
        commands.stream()
84
                .filter(item -> item.getClass().isAnnotationPresent(TelegramCommand.class))
85
                .forEach(this::addCommand);
86
    }
87
88
    /**
89
     * Adds the command to the list of available/non-secure commands and sets the commands for
90
     * {@link #closeCommand}, {@link #doneCommand} and {@link #helpCommand}.
91
     *
92
     * @param command the command to be added.
93
     * @see #commands
94
     * @see #nonSecureCommands
95
     * @see #closeCommand
96
     * @see #doneCommand
97
     * @see #helpCommand
98
     */
99
    private void addCommand(Command command) {
100
        this.commands.put(getCommandFullName(command), command);
101
102
        // Just for keeping a reference of the non-secure commands
103
        if (commandProperties.getNonSecure().contains(getCommandName(command))
104
                || commandProperties.getNonSecure().contains(getCommandFullName(command))
105
                || !command.getClass().getAnnotation(TelegramCommand.class).secure()) {
106
            this.nonSecureCommands.put(getCommandFullName(command), command);
107
        }
108
109
        if (command instanceof MultistageCloseCommand) {
110
            closeCommand = ((MultistageCloseCommand) command);
111
        } else if (command instanceof MultistageDoneCommand) {
112
            doneCommand = ((MultistageDoneCommand) command);
113
        } else if (command instanceof HelpCommand) {
114
            helpCommand = ((HelpCommand) command);
115
        }
116
    }
117
118
    /**
119
     * Returns {@code true} if the command is non-secure.
120
     *
121
     * @param command the command to be processed.
122
     * @return {@code true} if the command is non-secure; {@code false} otherwise.
123
     */
124
    public boolean isNonSecureCommand(Command command) {
125
        return this.nonSecureCommands.containsKey(getCommandFullName(command));
126
    }
127
128
    /**
129
     * Returns the name of the command (the same name declared on {@link TelegramCommand#name()}).
130
     * The name may include the slash (/).
131
     *
132
     * @param command the command from which the name will be identified.
133
     * @return the name of the command.
134
     */
135
    @SuppressWarnings("WeakerAccess")
136
    public static String getCommandName(Command command) {
137
        return command.getClass().getAnnotation(TelegramCommand.class).name();
138
    }
139
140
    /**
141
     * Returns the name of the command. It includes the slash (/).
142
     *
143
     * @param commandName the command's name (the same name declared on {@link TelegramCommand#name()})
144
     * @return the name of the command.
145
     */
146
    public static String getCommandFullName(String commandName) {
147
        return commandName.startsWith("/") ? commandName : String.format("/%s", commandName);
148
    }
149
150
    /**
151
     * Returns the name of the command. It includes the slash (/).
152
     *
153
     * @param command the command from which the name will be identified.
154
     * @return the name of the command.
155
     */
156
    public static String getCommandFullName(Command command) {
157
        return getCommandFullName(getCommandName(command));
158
    }
159
160
    /**
161
     * Returns the {@link Command} instance from the command name.
162
     *
163
     * @param command the command name.
164
     * @return the {@link Command} instance.
165
     * @throws CommandNotFound if the name is not related to any commands.
166
     */
167
    public Command getCommand(String command) throws CommandNotFound {
168
        if (!this.commands.containsKey(command)) {
169
            throw new CommandNotFound();
170
        }
171
172
        return this.commands.get(command);
173
    }
174
175
    /**
176
     * Sets the multistage command as the active one.
177
     *
178
     * @param idChat  the chat identification of the user for whom the multistage command will be active.
179
     * @param command the command to activate.
180
     */
181
    public void setActiveCommand(final Long idChat, final MultistageCommand command) {
182
        this.activeCommand.put(idChat, command);
183
    }
184
185
    /**
186
     * Gets the active command for the user.
187
     *
188
     * @param idChat the chat identification of the user.
189
     * @return the active command.
190
     * @throws CommandNotActive if there is no an active command.
191
     */
192
    public MultistageCommand getActiveCommand(Long idChat) throws CommandNotActive {
193
        if (!hasActiveCommand(idChat)) {
194
            throw new CommandNotActive();
195
        }
196
197
        return activeCommand.get(idChat);
198
    }
199
200
    /**
201
     * Removes the active command.
202
     *
203
     * @param idChat the chat identification of the user.
204
     */
205
    public void removeActiveCommand(Long idChat) {
206
        activeCommand.remove(idChat);
207
    }
208
209
    /**
210
     * Returns {@code true} if there is an active command.
211
     *
212
     * @param idChat the chat identification of the user.
213
     * @return {@code true} if there is an active command; {@code false} otherwise.
214
     */
215
    public boolean hasActiveCommand(Long idChat) {
216
        return activeCommand.containsKey(idChat);
217
    }
218
219
    /**
220
     * Returns the {@link MultistageCloseCommand} if it exists.
221
     *
222
     * @return the {@link MultistageCloseCommand} instance.
223
     */
224
    public Optional<MultistageCloseCommand> getCloseCommand() {
225
        return Optional.ofNullable(this.closeCommand);
226
    }
227
228
    /**
229
     * Returns the {@link MultistageDoneCommand} if it exists.
230
     *
231
     * @return the {@link MultistageDoneCommand} instance.
232
     */
233
    public Optional<MultistageDoneCommand> getDoneCommand() {
234
        return Optional.ofNullable(this.doneCommand);
235
    }
236
237
    /**
238
     * Returns the {@link HelpCommand} if it exists.
239
     *
240
     * @return the {@link HelpCommand} instance.
241
     */
242
    public Optional<HelpCommand> getHelpCommand() {
243
        return Optional.ofNullable(this.helpCommand);
244
    }
245
246
    /**
247
     * Returns a list with the available commands.
248
     *
249
     * @return the available commands.
250
     */
251
    public Collection<Command> getAvailableCommands() {
252
        return commands.values();
253
    }
254
255
    /**
256
     * Returns a list with the available non-secure commands.
257
     *
258
     * @return the available non-secure commands.
259
     */
260
    public Collection<Command> getAvailableNonSecureCommands() {
261
        return nonSecureCommands.values();
262
    }
263
}
264