Class CommandHandler<M>

  • Type Parameters:
    M - the class of the messages this command handler processes

    public abstract class CommandHandler<M>
    extends Object
    A base class for command handlers that does the common logic.

    Each method of this class starting with do, should usually be called by a subclass. Typically per each such method a subclass will have an according method that gets the needed arguments injected by the CDI framework. CDI cannot inject beans into methods that use wildcards (like Restriction<? super M>) but only into methods that define concrete type arguments (like Restriction<? super Message>). Due to this fact, this class cannot get the beans injected themselves, but has to rely on the subclass to get the beans injected and forward them to the superclass.

    If a subclass needs to do additional actions like registering message listeners on injected beans, this could for example be done in a method annotated with @PostConstruct.

    • Constructor Detail

      • CommandHandler

        public CommandHandler()
        Constructs a new command handler.
    • Method Detail

      • doSetAvailableRestrictions

        protected void doSetAvailableRestrictions​(Instance<Restriction<? super M>> availableRestrictions)
        Sets the available restrictions for this command handler.

        A subclass will typically have a method where it gets these injected, specific to the handled message type, and forwards its parameter as argument to this method like

        
         @Inject
         private void setAvailableRestrictions(Instance<Restriction<? super Message>> availableRestrictions) {
             doSetAvailableRestrictions(availableRestrictions);
         }
         
        Parameters:
        availableRestrictions - the available restrictions for this command handler
      • doSetCommands

        protected void doSetCommands​(Instance<Command<? super M>> commands)
        Sets the commands for this command handler.

        A subclass will typically have a method where it gets these injected, specific to the handled message type, and forwards its parameter as argument to this method like

        
         @Inject
         private void setCommands(Instance<Command<? super Message>> commands) {
             doSetCommands(commands);
         }
         
        Parameters:
        commands - the available commands for this command handler
      • doSetCustomPrefixProvider

        protected void doSetCustomPrefixProvider​(Instance<PrefixProvider<? super M>> customPrefixProvider)
        Sets the custom prefix provider for this command handler.

        A subclass will typically have a method where it gets this injected, specific to the handled message type, and forwards its parameter as argument to this method like

        
         @Inject
         private void setCustomPrefixProvider(Instance<PrefixProvider<? super Message>> customPrefixProvider) {
             doSetCustomPrefixProvider(customPrefixProvider);
         }
         

        Important: This method should be called directly in the injectable method as shown above, not in some @PostConstruct annotated method, as the @PostConstruct stage is used to decide whether the custom or the default prefix provider should be used, so it has to already be set at that point.

        Parameters:
        customPrefixProvider - the custom prefix provider for this command handler
      • doHandleMessage

        protected void doHandleMessage​(M message,
                                       String messageContent)
        Handles the given message with the given textual content. The textual content needs to be given separately as this generic method does not know now to get the content from the message.

        This method checks the message content for a command invocation, checks the configured restrictions for the command and if all passed, invokes the command synchronously or asynchronously as configured. If the command was denied by any restriction, a command not allowed CDI event is fired asynchronously. (See for example CommandNotAllowedEventJavacord) If the message started with the command prefix, but no matching command was found, a command not found CDI event is fired asynchronously. (See for example CommandNotFoundEventJavacord)

        Parameters:
        message - the message that potentially contains a command invocation
        messageContent - the textual content of the given message
      • fireCommandNotAllowedEvent

        protected abstract void fireCommandNotAllowedEvent​(M message,
                                                           String prefix,
                                                           String usedAlias)
        Fires a command not allowed CDI event asynchronously using Event.fireAsync(Object) that can be handled using @ObservesAsync.
        Parameters:
        message - the message that contains the command but was not allowed
        prefix - the command prefix that was used to trigger the command
        usedAlias - the alias that was used to trigger the command
        See Also:
        @ObservesAsync
      • fireCommandNotFoundEvent

        protected abstract void fireCommandNotFoundEvent​(M message,
                                                         String prefix,
                                                         String usedAlias)
        Fires a command not found CDI event asynchronously using Event.fireAsync(Object) that can be handled using @ObservesAsync.
        Parameters:
        message - the message that contains the command that was not found
        prefix - the command prefix that was used to trigger the command
        usedAlias - the alias that was used to trigger the command
        See Also:
        @ObservesAsync
      • executeAsync

        protected void executeAsync​(M message,
                                    Runnable commandExecutor)
        Executes the given command executor that is caused by the given message asynchronously.

        The default implementation executes the command in a thread pool and logs any throwables on error level. A subclass that has some means to execute tasks asynchronously anyways like the thread pool provided by Javacord, can overwrite this message and replace the asynchronous execution implementation.

        Parameters:
        message - the message that caused the given command executor
        commandExecutor - the executor that runs the actual command implementation