net.dv8tion.jda.core.JDABuilder.java Source code

Java tutorial

Introduction

Here is the source code for net.dv8tion.jda.core.JDABuilder.java

Source

/*
 *     Copyright 2015-2016 Austin Keener & Michael Ritter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package net.dv8tion.jda.core;

import net.dv8tion.jda.core.JDA.Status;
import net.dv8tion.jda.core.entities.Game;
import net.dv8tion.jda.core.entities.impl.JDAImpl;
import net.dv8tion.jda.core.exceptions.RateLimitedException;
import net.dv8tion.jda.core.hooks.IEventManager;
import net.dv8tion.jda.core.managers.impl.PresenceImpl;
import org.apache.http.HttpHost;

import javax.security.auth.login.LoginException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * Used to create a new {@link net.dv8tion.jda.core.JDA} instance. This is useful for making sure all of
 * your {@link net.dv8tion.jda.core.hooks.EventListener EventListeners} as registered
 * before {@link net.dv8tion.jda.core.JDA} attempts to log in.
 * <p>
 * A single JDABuilder can be reused multiple times. Each call to
 * {@link net.dv8tion.jda.core.JDABuilder#buildAsync() buildAsync()} or
 * {@link net.dv8tion.jda.core.JDABuilder#buildBlocking() buildBlocking()}
 * creates a new {@link net.dv8tion.jda.core.JDA} instance using the same information.
 * This means that you can have listeners easily registered to multiple {@link net.dv8tion.jda.core.JDA} instances.
 */
public class JDABuilder {
    protected static boolean jdaCreated = false;
    protected static HttpHost proxy = null;
    protected final List<Object> listeners;
    protected AccountType accountType;
    protected String token = null;
    protected boolean enableVoice = true;
    protected boolean enableShutdownHook = true;
    protected boolean enableBulkDeleteSplitting = true;
    protected boolean autoReconnect = true;
    protected boolean idle = false;
    protected IEventManager eventManager = null;
    protected JDA.ShardInfo shardInfo = null;
    protected Game game = null;
    protected OnlineStatus status = OnlineStatus.ONLINE;

    /**
     * Creates a completely empty JDABuilder.<br>
     * If you use this, you need to set the  token using
     * {@link net.dv8tion.jda.core.JDABuilder#setToken(String) setBotToken(String)}
     * before calling {@link net.dv8tion.jda.core.JDABuilder#buildAsync() buildAsync()}
     * or {@link net.dv8tion.jda.core.JDABuilder#buildBlocking() buildBlocking()}
     *
     * @param accountType
     *          The {@link net.dv8tion.jda.core.AccountType AccountType}.
     */
    public JDABuilder(AccountType accountType) {
        if (accountType == null)
            throw new NullPointerException("Provided AccountType was null!");
        this.accountType = accountType;
        listeners = new LinkedList<>();
    }

    /**
     * Sets the botToken that will be used by the {@link net.dv8tion.jda.core.JDA} instance to log in when
     * {@link net.dv8tion.jda.core.JDABuilder#buildAsync() buildAsync()}
     * or {@link net.dv8tion.jda.core.JDABuilder#buildBlocking() buildBlocking()}
     * is called.
     *
     * @param token
     *          The token of the bot-account that you would like to login with.
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder setToken(String token) {
        this.token = token;
        return this;
    }

    /**
     * Sets the proxy that will be used by <b>ALL</b> JDA instances.<br>
     * Once this is set <b>IT CANNOT BE CHANGED.</b><br>
     * After a JDA instance as been created, this method can never be called again, even if you are creating a new JDA object.<br>
     * <b>Note:</b> currently this only supports HTTP proxies.
     *
     * @param proxy
     *          The proxy to use.
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     * @throws UnsupportedOperationException
     *          If this method is called after proxy settings have already been set or after at least 1 JDA object has been created.
     */
    public JDABuilder setProxy(HttpHost proxy) {
        if (jdaCreated)
            throw new UnsupportedOperationException(
                    "You cannot change the proxy after a JDA object has been created. Proxy settings are global among all instances!");
        this.proxy = proxy;
        return this;
    }

    /**
     * Enables/Disables Voice functionality.<br>
     * This is useful, if your current system doesn't support Voice and you do not need it.
     * <p>
     * Default: <b>true (enabled)</b>
     *
     * @param enabled
     *          True - enables voice support.
     * @return
     *          Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder setAudioEnabled(boolean enabled) {
        this.enableVoice = enabled;
        return this;
    }

    /**
     * If enabled, JDA will separate the bulk delete event into individual delete events, but this isn't as efficient as
     * handling a single event would be. It is recommended that BulkDelete Splitting be disabled and that the developer
     * should instead handle the {@link net.dv8tion.jda.core.events.message.MessageBulkDeleteEvent MessageBulkDeleteEvent}
     * <p>
     * Default: <b>true (enabled)</b>
     *
     * @param enabled
     *          True - The MESSAGE_DELTE_BULK will be split into multiple individual MessageDeleteEvents.
     * @return
     *       Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder setBulkDeleteSplittingEnabled(boolean enabled) {
        this.enableBulkDeleteSplitting = enabled;
        return this;
    }

    /**
     * Enables/Disables the use of a Shutdown hook to clean up JDA.<br>
     * When the Java program closes shutdown hooks are run. This is used as a last-second cleanup
     * attempt by JDA to properly severe connections.
     * <p>
     * Default: <b>true (enabled)</b>
     *
     * @param enable
     *          True (default) - use shutdown hook to clean up JDA if the Java program is closed.
     * @return
     *      Return the {@link net.dv8tion.jda.core.JDABuilder JDABuilder } instance. Useful for chaining.
     */
    public JDABuilder setEnableShutdownHook(boolean enable) {
        this.enableShutdownHook = enable;
        return this;
    }

    /**
     * Sets whether or not JDA should try to reconnect, if a connection-error occured.
     * This will use and incremental reconnect (timeouts are increased each time an attempt fails).
     *
     * Default is true.
     *
     * @param autoReconnect
     *      If true - enables autoReconnect
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder setAutoReconnect(boolean autoReconnect) {
        this.autoReconnect = autoReconnect;
        return this;
    }

    /**
     * Changes the internally used EventManager.
     * There are 2 provided Implementations:
     * <ul>
     *     <li>{@link net.dv8tion.jda.core.hooks.InterfacedEventManager} which uses the Interface {@link net.dv8tion.jda.core.hooks.EventListener}
     *     (tip: use the {@link net.dv8tion.jda.core.hooks.ListenerAdapter}). This is the default EventManager.</li>
     *     <li>{@link net.dv8tion.jda.core.hooks.AnnotatedEventManager} which uses the Annotation {@link net.dv8tion.jda.core.hooks.SubscribeEvent} to mark the methods that listen for events.</li>
     * </ul>
     * You can also create your own EventManager (See {@link net.dv8tion.jda.core.hooks.IEventManager}).
     *
     * @param manager
     *      The new {@link net.dv8tion.jda.core.hooks.IEventManager} to use
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder setEventManager(IEventManager manager) {
        this.eventManager = manager;
        return this;
    }

    /**
     * Sets whether or not we should mark our session as afk<p>
     * This value can be changed at any time in the {@link net.dv8tion.jda.core.managers.Presence Presence} from a JDA instance.
     *
     * @param idle
     *      boolean value that will be provided with our IDENTIFY package to mark our session as afk or not. (default false)
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     * @see net.dv8tion.jda.core.managers.Presence#setIdle(boolean)
     */
    public JDABuilder setIdle(boolean idle) {
        this.idle = idle;
        return this;
    }

    /**
     * Sets the {@link net.dv8tion.jda.core.entities.Game Game} for our session.<p>
     * This value can be changed at any time in the {@link net.dv8tion.jda.core.managers.Presence Presence} from a JDA instance.
     *
     * @param game
     *      An instance of {@link net.dv8tion.jda.core.entities.Game Game} (null allowed)
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     * @see net.dv8tion.jda.core.managers.Presence#setGame(Game)
     */
    public JDABuilder setGame(Game game) {
        this.game = game;
        return this;
    }

    /**
     * Sets the {@link net.dv8tion.jda.core.OnlineStatus OnlineStatus} our connection will display.<p>
     * This value can be changed at any time in the {@link net.dv8tion.jda.core.managers.Presence Presence} from a JDA instance.<p>
     * <b>This will not take affect for {@link net.dv8tion.jda.core.AccountType#CLIENT AccountType#CLIENT} if the status specified in the user_settings
     * is not "online" as it is overriding our identify status.</b>
     *
     * @param status
     *      Not-null OnlineStatus (default online)
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     * @throws IllegalArgumentException
     *      if the provided OnlineStatus is null or {@link net.dv8tion.jda.core.OnlineStatus#UNKNOWN UNKNOWN}
     * @see net.dv8tion.jda.core.managers.Presence#setStatus(OnlineStatus)
     */
    public JDABuilder setStatus(OnlineStatus status) {
        if (status == null || status == OnlineStatus.UNKNOWN)
            throw new IllegalArgumentException("OnlineStatus cannot be null or unknown!");
        this.status = status;
        return this;
    }

    /**
     * Adds all provided listeners to the list of listeners that will be used to populate the {@link net.dv8tion.jda.core.JDA} object.
     * This uses the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} by default.
     * To switch to the {@link net.dv8tion.jda.core.hooks.AnnotatedEventManager AnnotatedEventManager},
     * use {@link #setEventManager(net.dv8tion.jda.core.hooks.IEventManager) setEventManager(new AnnotatedEventManager())}.
     *
     * Note: when using the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} (default),
     * given listener <b>must</b> be instance of {@link net.dv8tion.jda.core.hooks.EventListener EventListener}!
     *
     * @param listeners
     *          The listeners to add to the list.
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder addListener(Object... listeners) {
        Collections.addAll(this.listeners, listeners);
        return this;
    }

    /**
     * Removes all provided listeners from the list of listeners.
     *
     * @param listeners
     *          The listeners to remove from the list.
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder removeListener(Object... listeners) {
        this.listeners.removeAll(Arrays.asList(listeners));
        return this;
    }

    /**
     * This will enable sharding mode for JDA.
     * In sharding mode, guilds are split up and assigned one of multiple shards (clients).
     * The shardId that receives all stuff related to given bot is calculated as follows: shardId = (guildId &gt;&gt; 22)%numShards .
     * PMs are only sent to shard 0.
     *
     * Please note, that a shard will not even know about guilds not assigned to.
     *
     * @param shardId
     *      The id of this shard (starting at 0).
     * @param numShards
     *      The number of overall shards.
     * @return
     *      Returns the {@link net.dv8tion.jda.core.JDABuilder JDABuilder} instance. Useful for chaining.
     */
    public JDABuilder useSharding(int shardId, int numShards) {
        if (shardId < 0 || numShards < 2 || shardId >= numShards) {
            throw new RuntimeException(
                    "This configuration of shardId and numShards is not allowed! 0 <= shardId < numShards with numShards > 1");
        }
        shardInfo = new JDA.ShardInfo(shardId, numShards);
        return this;
    }

    /**
     * Builds a new {@link net.dv8tion.jda.core.JDA} instance and uses the provided token to start the login process.<br>
     * The login process runs in a different thread, so while this will return immediately, {@link net.dv8tion.jda.core.JDA} has not
     * finished loading, thus many {@link net.dv8tion.jda.core.JDA} methods have the chance to return incorrect information.
     * <p>
     * If you wish to be sure that the {@link net.dv8tion.jda.core.JDA} information is correct, please use
     * {@link net.dv8tion.jda.core.JDABuilder#buildBlocking() buildBlocking()} or register a
     * {@link net.dv8tion.jda.core.events.ReadyEvent ReadyEvent} {@link net.dv8tion.jda.core.hooks.EventListener EventListener}.
     *
     * @return
     *      A {@link net.dv8tion.jda.core.JDA} instance that has started the login process. It is unknown as to whether or not loading has finished when this returns.
     * @throws LoginException
     *          If the provided token is invalid.
     * @throws IllegalArgumentException
     *          If the provided token is empty or null.
     * @throws RateLimitedException
     *          If we are being Rate limited.
     */
    public JDA buildAsync() throws LoginException, IllegalArgumentException, RateLimitedException {
        jdaCreated = true;

        JDAImpl jda = new JDAImpl(accountType, proxy, autoReconnect, enableVoice, enableShutdownHook,
                enableBulkDeleteSplitting);

        if (eventManager != null) {
            jda.setEventManager(eventManager);
        }
        listeners.forEach(jda::addEventListener);
        jda.setStatus(JDA.Status.INITIALIZED); //This is already set by JDA internally, but this is to make sure the listeners catch it.
        //        jda.login(token, sharding);
        // Set the presence information before connecting to have the correct information ready when sending IDENTIFY
        ((PresenceImpl) jda.getPresence()).setCacheGame(game).setCacheIdle(idle).setCacheStatus(status);
        jda.login(token, shardInfo);
        return jda;
    }

    /**
     * Builds a new {@link net.dv8tion.jda.core.JDA} instance and uses the provided token to start the login process.<br>
     * This method will block until JDA has logged in and finished loading all resources. This is an alternative
     * to using {@link net.dv8tion.jda.core.events.ReadyEvent ReadyEvent}.
     *
     * @return
     *      A {@link net.dv8tion.jda.core.JDA} Object that is <b>guaranteed</b> to be logged in and finished loading.
     * @throws LoginException
     *          If the provided token is invalid.
     * @throws IllegalArgumentException
     *          If the provided token is empty or null.
     * @throws InterruptedException
     *          If an interrupt request is received while waiting for {@link net.dv8tion.jda.core.JDA} to finish logging in.
     *          This would most likely be caused by a JVM shutdown request.
     * @throws RateLimitedException
     *          If we are being Rate limited.
     */
    public JDA buildBlocking()
            throws LoginException, IllegalArgumentException, InterruptedException, RateLimitedException {
        JDA jda = buildAsync();
        while (jda.getStatus() != Status.CONNECTED) {
            Thread.sleep(50);
        }
        return jda;
    }
}