1 | package com.github.netkorp.telegram.framework.commands.basic; |
||
0 ignored issues
–
show
Code Smell
introduced
by
![]() |
|||
2 | |||
3 | import com.github.netkorp.telegram.framework.annotations.TelegramCommand; |
||
4 | import com.github.netkorp.telegram.framework.commands.abstracts.AbstractSimpleCommand; |
||
5 | import com.github.netkorp.telegram.framework.commands.interfaces.Command; |
||
6 | import com.github.netkorp.telegram.framework.commands.interfaces.HelpCommand; |
||
7 | import com.github.netkorp.telegram.framework.condition.ExcludeCondition; |
||
8 | import com.github.netkorp.telegram.framework.exceptions.CommandNotFound; |
||
9 | import com.github.netkorp.telegram.framework.managers.CommandManager; |
||
10 | import com.github.netkorp.telegram.framework.managers.SecurityManager; |
||
11 | import org.apache.logging.log4j.util.Strings; |
||
12 | import org.springframework.beans.factory.annotation.Autowired; |
||
13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; |
||
14 | import org.springframework.context.NoSuchMessageException; |
||
15 | import org.springframework.context.annotation.Conditional; |
||
16 | import org.springframework.context.i18n.LocaleContextHolder; |
||
17 | import org.telegram.telegrambots.meta.api.objects.Update; |
||
18 | |||
19 | import java.util.Collection; |
||
20 | import java.util.LinkedList; |
||
21 | import java.util.List; |
||
22 | import java.util.Objects; |
||
23 | import java.util.SortedMap; |
||
24 | import java.util.StringJoiner; |
||
25 | import java.util.TreeMap; |
||
26 | |||
27 | /** |
||
28 | * Displays the bot's help. |
||
29 | */ |
||
30 | @TelegramCommand(name = "help", group = "commands.groups.help", description = "commands.description.help") |
||
31 | @Conditional(ExcludeCondition.class) |
||
32 | @ConditionalOnSingleCandidate(HelpCommand.class) |
||
33 | public class BasicHelpCommand extends AbstractSimpleCommand implements HelpCommand { |
||
0 ignored issues
–
show
|
|||
34 | |||
35 | /** |
||
36 | * The component to know which user is authorized. |
||
37 | */ |
||
38 | private final SecurityManager securityManager; |
||
0 ignored issues
–
show
|
|||
39 | |||
40 | /** |
||
41 | * Constructs a new {@link BasicHelpCommand} instance with the {@link SecurityManager} component instance. |
||
42 | * |
||
43 | * @param securityManager the {@link SecurityManager} component instance. |
||
44 | */ |
||
45 | @Autowired |
||
46 | public BasicHelpCommand(SecurityManager securityManager) { |
||
0 ignored issues
–
show
|
|||
47 | this.securityManager = securityManager; |
||
0 ignored issues
–
show
|
|||
48 | } |
||
49 | |||
50 | /** |
||
51 | * Processes the data sent by the users. |
||
52 | * |
||
53 | * @param update the received message. |
||
54 | * @param args the parameters passed to the command execution. |
||
55 | */ |
||
56 | @Override |
||
57 | public void execute(final Update update, String[] args) { |
||
0 ignored issues
–
show
|
|||
58 | try { |
||
0 ignored issues
–
show
|
|||
59 | if (args.length == 0) { |
||
0 ignored issues
–
show
|
|||
60 | execute(update); |
||
0 ignored issues
–
show
|
|||
61 | return; |
||
62 | } |
||
63 | |||
64 | StringJoiner stringJoiner = new StringJoiner(System.lineSeparator()); |
||
65 | |||
66 | for (String arg : args) { |
||
0 ignored issues
–
show
|
|||
67 | try { |
||
0 ignored issues
–
show
|
|||
68 | stringJoiner.add(helpForCommand(commandManager.getCommand(CommandManager.getCommandFullName(arg)))); |
||
0 ignored issues
–
show
|
|||
69 | } catch (CommandNotFound commandNotFound) { |
||
0 ignored issues
–
show
|
|||
70 | bot.sendMessage(String.format("%s: %s", commandNotFound.getMessage(), arg), update.getMessage().getChatId(), true); |
||
0 ignored issues
–
show
|
|||
71 | execute(update); |
||
72 | throw commandNotFound; |
||
0 ignored issues
–
show
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. ![]() |
|||
73 | } |
||
74 | } |
||
75 | |||
76 | bot.sendMessage(stringJoiner.toString(), update.getMessage().getChatId(), true); |
||
77 | } catch (CommandNotFound commandNotFound) { |
||
0 ignored issues
–
show
Ignoring an Exception may lead to hard to find bugs. Consider logging or rethrowing the original exception. If you want to throw a different exception, you can set the original exception as its cause to preserve the stacktrace.
When instantiating a new Exception, you can set another Exception as its cause. See the Oracle documentation on Throwables. Usage example throw new Exception("Exception Message", originalException);
Complete Example: class ReThrowException {
public static void throwsException() {
try {
throw new Exception("I am the original exception");
} catch (final Exception e) {
throw new RuntimeException("I am the new exception", e);
}
}
public static void main(String[] args) {
try {
throwsException();
}
catch (final RuntimeException e) {
System.out.println(e.getMessage());
System.out.println("and my cause is: " + e.getCause().getMessage());
e.printStackTrace();
}
}
}
![]() |
|||
78 | // Do nothing |
||
79 | } |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * Executes the command's logic without taking parameters. |
||
84 | * |
||
85 | * @param update the received message. |
||
86 | */ |
||
87 | @Override |
||
88 | public void execute(Update update) { |
||
0 ignored issues
–
show
|
|||
89 | StringJoiner stringJoiner = new StringJoiner(System.lineSeparator()); |
||
0 ignored issues
–
show
|
|||
90 | |||
91 | stringJoiner.add(String.format("%s:", messageSource.getMessage("commands.basic.help.title", null, |
||
92 | LocaleContextHolder.getLocale()))); |
||
93 | |||
94 | commandsByGroup(getAvailableCommands(update.getMessage().getChatId())) |
||
95 | .forEach((group, commands) -> stringJoiner.add(helpForGroup(group, commands))); |
||
0 ignored issues
–
show
|
|||
96 | |||
97 | bot.sendMessage(stringJoiner.toString(), update.getMessage().getChatId(), true); |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Returns the help for the group of commands. |
||
102 | * |
||
103 | * @param group the name of the group. |
||
104 | * @param commands the commands into the group. |
||
105 | * @return the help for the group. |
||
106 | */ |
||
107 | private String helpForGroup(String group, List<Command> commands) { |
||
0 ignored issues
–
show
|
|||
108 | StringJoiner stringJoiner = new StringJoiner(System.lineSeparator()); |
||
0 ignored issues
–
show
|
|||
109 | if (!Strings.isEmpty(group)) { |
||
0 ignored issues
–
show
|
|||
110 | stringJoiner.add(String.format("<b>%s</b>", group)); |
||
0 ignored issues
–
show
|
|||
111 | } |
||
112 | commands.forEach(command -> stringJoiner.add(helpForCommand(command))); |
||
0 ignored issues
–
show
|
|||
113 | return System.lineSeparator() + stringJoiner.toString(); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Returns the help for a single command. |
||
118 | * |
||
119 | * @param command the command. |
||
120 | * @return the help of the command. |
||
121 | */ |
||
122 | private String helpForCommand(Command command) { |
||
0 ignored issues
–
show
|
|||
123 | StringJoiner stringJoiner = new StringJoiner(", "); |
||
0 ignored issues
–
show
|
|||
124 | CommandManager.getCommandFullNames(command).forEach(stringJoiner::add); |
||
125 | return String.format("%s - %s", stringJoiner.toString(), getDescription(command)); |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Organizes the available commands into groups. |
||
130 | * |
||
131 | * @param commands the list with all the available commands. |
||
132 | * @return the available commands in groups sorted by the group's name. |
||
133 | */ |
||
134 | private SortedMap<String, List<Command>> commandsByGroup(Collection<Command> commands) { |
||
0 ignored issues
–
show
|
|||
135 | SortedMap<String, List<Command>> commandsByGroup = new TreeMap<>(); |
||
0 ignored issues
–
show
|
|||
136 | |||
137 | commands.forEach(command -> { |
||
0 ignored issues
–
show
|
|||
138 | String group = getGroupName(command); |
||
0 ignored issues
–
show
|
|||
139 | |||
140 | List<Command> commandList = commandsByGroup.getOrDefault(group, new LinkedList<>()); |
||
141 | commandList.add(command); |
||
142 | |||
143 | commandsByGroup.put(group, commandList); |
||
144 | }); |
||
145 | |||
146 | return commandsByGroup; |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * Cleans the class name by removing the word "command" from it. |
||
151 | * |
||
152 | * @param commandClass the class to be cleaned. |
||
153 | * @return the cleaned class name. |
||
154 | */ |
||
155 | private String cleanCommandClassName(Class<?> commandClass) { |
||
0 ignored issues
–
show
|
|||
156 | String className = commandClass.getSimpleName().toLowerCase(); |
||
0 ignored issues
–
show
|
|||
157 | if (!"command".equals(className) && className.endsWith("command")) { |
||
0 ignored issues
–
show
|
|||
158 | className = className.substring(0, className.length() - 7); |
||
0 ignored issues
–
show
|
|||
159 | } |
||
160 | |||
161 | return className; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Returns the group's name of the command. |
||
166 | * |
||
167 | * @param command the command from which the group's name will be retrieved. |
||
168 | * @return the group's name. |
||
169 | */ |
||
170 | private String getGroupName(Command command) { |
||
0 ignored issues
–
show
|
|||
171 | String groupName = command.getClass().getAnnotation(TelegramCommand.class).group().trim(); |
||
0 ignored issues
–
show
|
|||
172 | |||
173 | // If there is no an explicit group, we'll try to generate a key to retrieve a message |
||
174 | String key = ""; |
||
175 | if (groupName.isEmpty()) { |
||
0 ignored issues
–
show
|
|||
176 | key = "commands.groups." + cleanCommandClassName(command.getClass()); |
||
0 ignored issues
–
show
|
|||
177 | groupName = key; |
||
178 | } |
||
179 | |||
180 | try { |
||
0 ignored issues
–
show
|
|||
181 | groupName = messageSource.getMessage(groupName, null, LocaleContextHolder.getLocale()); |
||
0 ignored issues
–
show
|
|||
182 | } catch (NoSuchMessageException exception) { |
||
0 ignored issues
–
show
Ignoring an Exception may lead to hard to find bugs. Consider logging or rethrowing the original exception. If you want to throw a different exception, you can set the original exception as its cause to preserve the stacktrace.
When instantiating a new Exception, you can set another Exception as its cause. See the Oracle documentation on Throwables. Usage example throw new Exception("Exception Message", originalException);
Complete Example: class ReThrowException {
public static void throwsException() {
try {
throw new Exception("I am the original exception");
} catch (final Exception e) {
throw new RuntimeException("I am the new exception", e);
}
}
public static void main(String[] args) {
try {
throwsException();
}
catch (final RuntimeException e) {
System.out.println(e.getMessage());
System.out.println("and my cause is: " + e.getCause().getMessage());
e.printStackTrace();
}
}
}
![]() |
|||
183 | if (Objects.equals(key, groupName)) { |
||
0 ignored issues
–
show
|
|||
184 | groupName = ""; |
||
0 ignored issues
–
show
|
|||
185 | } |
||
186 | } |
||
187 | |||
188 | return groupName; |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * Returns the description of the command. |
||
193 | * |
||
194 | * @param command the command from which the description will be retrieved. |
||
195 | * @return the command's description. |
||
196 | */ |
||
197 | private String getDescription(Command command) { |
||
0 ignored issues
–
show
|
|||
198 | String description = command.getClass().getAnnotation(TelegramCommand.class).description().trim(); |
||
0 ignored issues
–
show
|
|||
199 | |||
200 | // If there is no explicit description, we'll try to generate a description key to retrieve a message |
||
201 | String key = ""; |
||
202 | if (description.isEmpty()) { |
||
0 ignored issues
–
show
|
|||
203 | key = "commands.description." + cleanCommandClassName(command.getClass()); |
||
0 ignored issues
–
show
|
|||
204 | description = key; |
||
205 | } |
||
206 | |||
207 | try { |
||
0 ignored issues
–
show
|
|||
208 | description = messageSource.getMessage(description, null, LocaleContextHolder.getLocale()); |
||
0 ignored issues
–
show
|
|||
209 | } catch (NoSuchMessageException exception) { |
||
0 ignored issues
–
show
Ignoring an Exception may lead to hard to find bugs. Consider logging or rethrowing the original exception. If you want to throw a different exception, you can set the original exception as its cause to preserve the stacktrace.
When instantiating a new Exception, you can set another Exception as its cause. See the Oracle documentation on Throwables. Usage example throw new Exception("Exception Message", originalException);
Complete Example: class ReThrowException {
public static void throwsException() {
try {
throw new Exception("I am the original exception");
} catch (final Exception e) {
throw new RuntimeException("I am the new exception", e);
}
}
public static void main(String[] args) {
try {
throwsException();
}
catch (final RuntimeException e) {
System.out.println(e.getMessage());
System.out.println("and my cause is: " + e.getCause().getMessage());
e.printStackTrace();
}
}
}
![]() |
|||
210 | if (Objects.equals(key, description)) { |
||
0 ignored issues
–
show
|
|||
211 | description = messageSource.getMessage("commands.basic.help.default-description", null, LocaleContextHolder.getLocale()); |
||
0 ignored issues
–
show
|
|||
212 | } |
||
213 | } |
||
214 | |||
215 | return description; |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * Returns the list of available commands for the user. It takes into account whether the user is authorized or not. |
||
220 | * |
||
221 | * @param chatId the identification of the user's chat. |
||
222 | * @return the list of available commands. |
||
223 | */ |
||
224 | private Collection<Command> getAvailableCommands(Long chatId) { |
||
0 ignored issues
–
show
|
|||
225 | if (securityManager.isAuthorized(chatId)) { |
||
0 ignored issues
–
show
|
|||
226 | return commandManager.getAvailableCommands(); |
||
0 ignored issues
–
show
|
|||
227 | } |
||
228 | |||
229 | return commandManager.getAvailableNonSecureCommands(); |
||
230 | } |
||
231 | } |
||
232 |