Completed
Push — master ( dbd5a1...2daf05 )
by Roannel Fernández
03:23
created

getHelpCommand()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 2
eloc 2
rs 10
cc 1
1
package com.github.netkorp.telegram.framework.managers;
0 ignored issues
show
Code Smell introduced by
It is a best practice to supply a copyright/licence header in your code. Your organisation probably has a template for that.
Loading history...
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.HashMap;
16
import java.util.LinkedList;
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")
0 ignored issues
show
Best Practice introduced by
Suppressing code checker warnings is not a best practice. Consider working on your code until it meets guidelines.
Loading history...
27
@Component
28
public class CommandManager {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
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> commandsByFullName;
0 ignored issues
show
Coding Style introduced by
Make this line start at column 3.
Loading history...
34
35
    /**
36
     * The list of the available commands.
37
     */
38
    private final List<Command> commands;
39
40
    /**
41
     * The list of the non-secure commands.
42
     */
43
    private final List<Command> nonSecureCommands;
44
45
    /**
46
     * The command that is active for each user.
47
     */
48
    private final Map<Long, MultistageCommand> activeCommand;
49
50
    /**
51
     * The properties of the commands.
52
     */
53
    private final CommandProperties commandProperties;
54
55
    /**
56
     * The command that closes an active conversation with the bot, indicating to the active command that the conversation is closed.
0 ignored issues
show
Coding Style introduced by
This line is 133 characters long, which is over the set limit of 120 characters.
Loading history...
57
     * It is kept here for a quick access to the close command.
58
     */
59
    private MultistageCloseCommand closeCommand;
60
61
    /**
62
     * The command that closes an active conversation with the bot, indicating to the active command that the conversation is done.
0 ignored issues
show
Coding Style introduced by
This line is 131 characters long, which is over the set limit of 120 characters.
Loading history...
63
     * It is kept here for a quick access to the done command.
64
     */
65
    private MultistageDoneCommand doneCommand;
66
67
    /**
68
     * The command that shows the help of the bot.
69
     * It is kept here for a quick access to the help command.
70
     */
71
    private HelpCommand helpCommand;
72
73
    /**
74
     * Constructs a new {@link CommandManager} instance with the list of available {@link Command}
75
     * and the properties of the commands.
76
     *
77
     * @param commands          the list of available {@link Command}.
78
     * @param commandProperties the properties of the commands.
79
     */
80
    @Autowired
81
    public CommandManager(List<Command> commands, CommandProperties commandProperties) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
82
        this.commandsByFullName = new HashMap<>();
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
83
        this.commands = new LinkedList<>();
84
        this.nonSecureCommands = new LinkedList<>();
85
86
        this.activeCommand = new HashMap<>();
87
        this.commandProperties = commandProperties;
88
89
        commands.stream()
90
                .filter(item -> item.getClass().isAnnotationPresent(TelegramCommand.class))
0 ignored issues
show
introduced by
Specify a type for: 'item'
Loading history...
91
                .forEach(this::addCommand);
92
    }
93
94
    /**
95
     * Adds the command to the list of available/non-secure commands and sets the commands for
96
     * {@link #closeCommand}, {@link #doneCommand} and {@link #helpCommand}.
97
     *
98
     * @param command the command to be added.
99
     * @see #commandsByFullName
100
     * @see #commands
101
     * @see #nonSecureCommands
102
     * @see #closeCommand
103
     * @see #doneCommand
104
     * @see #helpCommand
105
     */
106
    private void addCommand(Command command) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
107
        // Registering the command for each name
108
        for (String name : getCommandNames(command)) {
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
109
            this.commandsByFullName.put(getCommandFullName(name), command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 7.
Loading history...
110
111
            if (!this.commands.contains(command)) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
112
                this.commands.add(command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 9.
Loading history...
113
            }
114
115
            // Just for keeping a reference of the non-secure commands
116
            if ((commandProperties.getNonSecure().contains(name)
117
                    || !command.getClass().getAnnotation(TelegramCommand.class).secure())
118
                    && !this.nonSecureCommands.contains(command)) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
119
                this.nonSecureCommands.add(command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 9.
Loading history...
120
            }
121
122
            if (command instanceof MultistageCloseCommand) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
123
                closeCommand = ((MultistageCloseCommand) command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 9.
Loading history...
124
            } else if (command instanceof MultistageDoneCommand) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
Coding Style introduced by
Move this "else" keyword to a new dedicated line.
Loading history...
125
                doneCommand = ((MultistageDoneCommand) command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 9.
Loading history...
126
            } else if (command instanceof HelpCommand) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
Coding Style introduced by
Move this "else" keyword to a new dedicated line.
Loading history...
127
                helpCommand = ((HelpCommand) command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 9.
Loading history...
128
            }
129
        }
130
    }
131
132
    /**
133
     * Returns {@code true} if the command is non-secure.
134
     *
135
     * @param command the command to be processed.
136
     * @return {@code true} if the command is non-secure; {@code false} otherwise.
137
     */
138
    public boolean isNonSecureCommand(Command command) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
139
        return this.nonSecureCommands.contains(command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
140
    }
141
142
    /**
143
     * Returns the names of the command (the same names declared on {@link TelegramCommand#name()}).
144
     * The names may include the slash (/).
145
     *
146
     * @param command the command from which the names will be identified.
147
     * @return the names of the command.
148
     */
149
    public static String[] getCommandNames(Command command) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
150
        return command.getClass().getAnnotation(TelegramCommand.class).name();
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
151
    }
152
153
    /**
154
     * Returns the name of the command. It includes the slash (/).
155
     *
156
     * @param commandName the command's name (the same name declared on {@link TelegramCommand#name()})
157
     * @return the name of the command.
158
     */
159
    public static String getCommandFullName(String commandName) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
160
        return commandName.startsWith("/") ? commandName : String.format("/%s", commandName);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
161
    }
162
163
    /**
164
     * Returns the names of the command. They include the slash (/).
165
     *
166
     * @param command the command from which the names will be identified.
167
     * @return the names of the command.
168
     */
169
    public static List<String> getCommandFullNames(Command command) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
170
        List<String> commandFullNames = new LinkedList<>();
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
171
172
        for (String name : getCommandNames(command)) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
173
            commandFullNames.add(getCommandFullName(name));
0 ignored issues
show
Coding Style introduced by
Make this line start at column 7.
Loading history...
174
        }
175
176
        return commandFullNames;
177
    }
178
179
    /**
180
     * Returns the {@link Command} instance from the command name.
181
     *
182
     * @param command the command name.
183
     * @return the {@link Command} instance.
184
     * @throws CommandNotFound if the name is not related to any commands.
185
     */
186
    public Command getCommand(String command) throws CommandNotFound {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
187
        if (!this.commandsByFullName.containsKey(command)) {
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
188
            throw new CommandNotFound();
0 ignored issues
show
Coding Style introduced by
Make this line start at column 7.
Loading history...
Best Practice introduced by
As defined in your coding style, remove the checked exception: CommandNotFound. Consider throwing an unchecked exception instead.

Opionions on checked exceptions are divided.

On the positive side they do make code safer and provide self-documentation on possible error conditions that the caller has to be aware of.

On the negative side, they do force the caller to deal with these errors, either by catching or specifying them in the method definition. This may make the code more verbose than necessary.

The Java documentation recommends using them wisely.

Loading history...
189
        }
190
191
        return this.commandsByFullName.get(command);
192
    }
193
194
    /**
195
     * Sets the multistage command as the active one.
196
     *
197
     * @param idChat  the chat identification of the user for whom the multistage command will be active.
198
     * @param command the command to activate.
199
     */
200
    public void setActiveCommand(final Long idChat, final MultistageCommand command) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
201
        this.activeCommand.put(idChat, command);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
202
    }
203
204
    /**
205
     * Gets the active command for the user.
206
     *
207
     * @param idChat the chat identification of the user.
208
     * @return the active command.
209
     * @throws CommandNotActive if there is no an active command.
210
     */
211
    public MultistageCommand getActiveCommand(Long idChat) throws CommandNotActive {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
212
        if (!hasActiveCommand(idChat)) {
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
213
            throw new CommandNotActive();
0 ignored issues
show
Coding Style introduced by
Make this line start at column 7.
Loading history...
Best Practice introduced by
As defined in your coding style, remove the checked exception: CommandNotActive. Consider throwing an unchecked exception instead.

Opionions on checked exceptions are divided.

On the positive side they do make code safer and provide self-documentation on possible error conditions that the caller has to be aware of.

On the negative side, they do force the caller to deal with these errors, either by catching or specifying them in the method definition. This may make the code more verbose than necessary.

The Java documentation recommends using them wisely.

Loading history...
214
        }
215
216
        return activeCommand.get(idChat);
217
    }
218
219
    /**
220
     * Removes the active command.
221
     *
222
     * @param idChat the chat identification of the user.
223
     */
224
    public void removeActiveCommand(Long idChat) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
225
        activeCommand.remove(idChat);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
226
    }
227
228
    /**
229
     * Returns {@code true} if there is an active command.
230
     *
231
     * @param idChat the chat identification of the user.
232
     * @return {@code true} if there is an active command; {@code false} otherwise.
233
     */
234
    public boolean hasActiveCommand(Long idChat) {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
235
        return activeCommand.containsKey(idChat);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
236
    }
237
238
    /**
239
     * Returns the {@link MultistageCloseCommand} if it exists.
240
     *
241
     * @return the {@link MultistageCloseCommand} instance.
242
     */
243
    public Optional<MultistageCloseCommand> getCloseCommand() {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
244
        return Optional.ofNullable(this.closeCommand);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
245
    }
246
247
    /**
248
     * Returns the {@link MultistageDoneCommand} if it exists.
249
     *
250
     * @return the {@link MultistageDoneCommand} instance.
251
     */
252
    public Optional<MultistageDoneCommand> getDoneCommand() {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
253
        return Optional.ofNullable(this.doneCommand);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
254
    }
255
256
    /**
257
     * Returns the {@link HelpCommand} if it exists.
258
     *
259
     * @return the {@link HelpCommand} instance.
260
     */
261
    public Optional<HelpCommand> getHelpCommand() {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
262
        return Optional.ofNullable(this.helpCommand);
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
263
    }
264
265
    /**
266
     * Returns a list with the available commands.
267
     *
268
     * @return the available commands.
269
     */
270
    public List<Command> getAvailableCommands() {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
271
        return commands;
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
Security Comprehensibility introduced by
Mutable class members should never be returned to a caller or accepted and stored directly. You might want to Return a copy of commands instead.
Loading history...
272
    }
273
274
    /**
275
     * Returns a list with the available non-secure commands.
276
     *
277
     * @return the available non-secure commands.
278
     */
279
    public List<Command> getAvailableNonSecureCommands() {
0 ignored issues
show
Coding Style introduced by
Move this left curly brace to the beginning of next line of code.
Loading history...
280
        return nonSecureCommands;
0 ignored issues
show
Coding Style introduced by
Make this line start at column 5.
Loading history...
Security Comprehensibility introduced by
Mutable class members should never be returned to a caller or accepted and stored directly. You might want to Return a copy of nonSecureCommands instead.
Loading history...
281
    }
282
}
283