Skip to content

Separation of Concerns

In JDA we follow the pattern of Separation of Concerns (SoC) for our entities. This means that updates and moderation all happens in dedicated classes rather than on the entities themselves (with a few exceptions like deletion)

Each entity that can be updated directly has a Manager instance which can be used to update one or more of the entity properties such as its name.

Managers

The managers in JDA are useful to update entities. Without many complications, you can update many of properties in a single RestAction execution (HTTP request).

Updating an Entity

We will make a small example here on how to update the name and the topic of a TextChannel.

public void updateChannel(TextChannel channel) {
    ChannelManager manager = channel.getManager(); // get the manager
    manager.setName("testing-2").setTopic("This is a testing channel, no memes allowed"); // set the new values
    manager.queue(); // execute update, this updates both name and topic
}

Note

queue() is async so the update is not done when this method returns!

Re-usability of Managers

Every manager in JDA is cached for re-use and can be updated for an interval and then executed upon command, very useful for bots!

Example State Machine
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.requests.restaction.MessageAction;

// derived with permission from https://gist.github.com/MinnDevelopment/190b79109b17c3bb446eea13be57c43c
public class UpdateStateMachine extends ListenerAdapter {
private final TextChannel channel;
private String name = null;
private String topic = null;
private int state = 0;

    public UpdateStateMachine(TextChannel channel) {
        this.channel = channel;
    }

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        if (!event.isFromGuild()) return;
        if (!event.getChannel().equals(channel)) return;
        String content = event.getMessage().getContentRaw();
        if (!content.startsWith("!update ")) return;
        String parts[] = content.split(" ", 2);
        String arguments = parts.length > 1 ? parts[1] : "";
        switch (state) {
            case 0: // setting mode
                if (arguments.equals("done")) {              // finish update
                    state = 2; // enter update mode
                    sendStatus().append("\nType `!update yes` to finish!").queue();
                } else if (arguments.equals("reset")) {      // reset state
                    state = 1; // enter reset mode
                    sendStatus().append("\nType `!update yes` to reset!").queue();
                } else if (arguments.startsWith("topic ")) { // update topic
                    this.topic = arguments.split(" ", 2)[1];
                    channel.getManager().setTopic(this.topic);
                } else if (arguments.startsWith("name ")) {  // update name
                    this.name = arguments.split(" ", 3)[1];
                    channel.getManager().setName(this.name);
                } else {
                    channel.sendMessage("I'm sorry I did not understand.").queue();
                }
                break;
            case 1: // reset mode
                state = 0;
                if (arguments.equals("yes"))  // we should reset
                    resetState();
                else                          // nevermind, we are not done
                    channel.sendMessage("Ok, what do you want to change?").queue();
                break;
            case 2: // update mode
                state = 0;
                if (arguments.equals("yes")) // we should update
                    channel.getManager().queue((v) -> resetState());
                else                         // nevermind, we are not done
                    channel.sendMessage("Ok, what do you want to change?").queue();
                break;
        }
    }

    protected void resetState() {
        channel.getManager().reset();
        this.name = null;
        this.topic = null;
    }

    private MessageAction sendStatus() {
        MessageBuilder builder = new MessageBuilder();
        builder.append("**Current Status**");
        if (name != null || topic != null) {
            StringBuilder changes = new StringBuilder();
            if (name != null)
                changes.append("name -> ").append(name).append("\n");
            if (topic != null)
                changes.append("topic -> ").append(topic);
            builder.appendCodeBlock(changes, "");
        }
        return builder.sendTo(channel);
    }
}

Exceptions to SoC Pattern

The only exceptions we have are deletion and creation. All entities are deleted directly using its delete() method, for instance Channel.delete().

You can create copies of entities in the same fashion with one twist. Some createCopy() methods allow you to modify the new copy before execution of the RestAction

Note

This will copy the provided Channel and set its name to the provided newName!

public void copyChannel(Channel channel, String newName) {
    channel.createCopy().setName(newName).queue();
}

These things can be overlooked, so we do recommend inspecting the return type of these operations: getManager(), create...(), delete(), ban(...), kick(...) and similar when you use them so that you are not caught out.