All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bukkit.plugin.java.JavaPlugin Maven / Gradle / Ivy

package org.bukkit.plugin.java;

import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.EbeanServerFactory;
import com.avaje.ebean.config.DataSourceConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.ddl.DdlGenerator;
import com.google.common.base.Charsets;
import com.google.common.io.ByteStreams;
import org.apache.commons.lang.Validate;
import org.bukkit.Server;
import org.bukkit.Warning.WarningState;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.*;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Represents a Java plugin
 */
public abstract class JavaPlugin extends PluginBase {
  private boolean isEnabled = false;
  private PluginLoader loader = null;
  private Server server = null;
  private File file = null;
  private PluginDescriptionFile description = null;
  private File dataFolder = null;
  private ClassLoader classLoader = null;
  private boolean naggable = true;
  private EbeanServer ebean = null;
  private FileConfiguration newConfig = null;
  private File configFile = null;
  private PluginLogger logger = null;

  public JavaPlugin() {
    final ClassLoader classLoader = this.getClass().getClassLoader();
    if (!(classLoader instanceof PluginClassLoader)) {
      throw new IllegalStateException("JavaPlugin requires " + PluginClassLoader.class.getName());
    }
    ((PluginClassLoader) classLoader).initialize(this);
  }

  /**
   * @param loader      the plugin loader
   * @param server      the server instance
   * @param description the plugin's description
   * @param dataFolder  the plugin's data folder
   * @param file        the location of the plugin
   * @deprecated This method is intended for unit testing purposes when the
   * other {@linkplain #JavaPlugin(JavaPluginLoader,
   * PluginDescriptionFile, File, File) constructor} cannot be used.
   * 

* Its existence may be temporary. */ @Deprecated protected JavaPlugin(final PluginLoader loader, final Server server, final PluginDescriptionFile description, final File dataFolder, final File file) { final ClassLoader classLoader = this.getClass().getClassLoader(); if (classLoader instanceof PluginClassLoader) { throw new IllegalStateException("Cannot use initialization constructor at runtime"); } init(loader, server, description, dataFolder, file, classLoader); } protected JavaPlugin(final JavaPluginLoader loader, final PluginDescriptionFile description, final File dataFolder, final File file) { final ClassLoader classLoader = this.getClass().getClassLoader(); if (classLoader instanceof PluginClassLoader) { throw new IllegalStateException("Cannot use initialization constructor at runtime"); } init(loader, loader.server, description, dataFolder, file, classLoader); } /** * This method provides fast access to the plugin that has {@link * #getProvidingPlugin(Class) provided} the given plugin class, which is * usually the plugin that implemented it. *

* An exception to this would be if plugin's jar that contained the class * does not extend the class, where the intended plugin would have * resided in a different jar / classloader. * * @param a class that extends JavaPlugin * @param clazz the class desired * @return the plugin that provides and implements said class * @throws IllegalArgumentException if clazz is null * @throws IllegalArgumentException if clazz does not extend {@link * JavaPlugin} * @throws IllegalStateException if clazz was not provided by a plugin, * for example, if called with * JavaPlugin.getPlugin(JavaPlugin.class) * @throws IllegalStateException if called from the static initializer for * given JavaPlugin * @throws ClassCastException if plugin that provided the class does not * extend the class */ public static T getPlugin(Class clazz) { Validate.notNull(clazz, "Null class cannot have a plugin"); if (!JavaPlugin.class.isAssignableFrom(clazz)) { throw new IllegalArgumentException(clazz + " does not extend " + JavaPlugin.class); } final ClassLoader cl = clazz.getClassLoader(); if (!(cl instanceof PluginClassLoader)) { throw new IllegalArgumentException(clazz + " is not initialized by " + PluginClassLoader.class); } JavaPlugin plugin = ((PluginClassLoader) cl).plugin; if (plugin == null) { throw new IllegalStateException("Cannot get plugin for " + clazz + " from a static initializer"); } return clazz.cast(plugin); } /** * This method provides fast access to the plugin that has provided the * given class. * * @param clazz a class belonging to a plugin * @return the plugin that provided the class * @throws IllegalArgumentException if the class is not provided by a * JavaPlugin * @throws IllegalArgumentException if class is null * @throws IllegalStateException if called from the static initializer for * given JavaPlugin */ public static JavaPlugin getProvidingPlugin(Class clazz) { Validate.notNull(clazz, "Null class cannot have a plugin"); final ClassLoader cl = clazz.getClassLoader(); if (!(cl instanceof PluginClassLoader)) { throw new IllegalArgumentException(clazz + " is not provided by " + PluginClassLoader.class); } JavaPlugin plugin = ((PluginClassLoader) cl).plugin; if (plugin == null) { throw new IllegalStateException("Cannot get plugin for " + clazz + " from a static initializer"); } return plugin; } /** * Returns the folder that the plugin data's files are located in. The * folder may not yet exist. * * @return The folder. */ @Override public final File getDataFolder() { return dataFolder; } /** * Gets the associated PluginLoader responsible for this plugin * * @return PluginLoader that controls this plugin */ @Override public final PluginLoader getPluginLoader() { return loader; } /** * Returns the Server instance currently running this plugin * * @return Server running this plugin */ @Override public final Server getServer() { return server; } /** * Returns a value indicating whether or not this plugin is currently * enabled * * @return true if this plugin is enabled, otherwise false */ @Override public final boolean isEnabled() { return isEnabled; } /** * Sets the enabled state of this plugin * * @param enabled true if enabled, otherwise false */ protected final void setEnabled(final boolean enabled) { if (isEnabled != enabled) { isEnabled = enabled; if (isEnabled) { onEnable(); } else { onDisable(); } } } /** * Returns the file which contains this plugin * * @return File containing this plugin */ protected File getFile() { return file; } /** * Returns the plugin.yaml file containing the details for this plugin * * @return Contents of the plugin.yaml file */ @Override public final PluginDescriptionFile getDescription() { return description; } @Override public FileConfiguration getConfig() { if (newConfig == null) { reloadConfig(); } return newConfig; } /** * Provides a reader for a text file located inside the jar. The behavior * of this method adheres to {@link PluginAwareness.Flags#UTF8}, or if not * defined, uses UTF8 if {@link FileConfiguration#UTF8_OVERRIDE} is * specified, or system default otherwise. * * @param file the filename of the resource to load * @return null if {@link #getResource(String)} returns null * @throws IllegalArgumentException if file is null * @see ClassLoader#getResourceAsStream(String) */ @SuppressWarnings("deprecation") protected final Reader getTextResource(String file) { final InputStream in = getResource(file); return in == null ? null : new InputStreamReader(in, isStrictlyUTF8() || FileConfiguration.UTF8_OVERRIDE ? Charsets.UTF_8 : Charset.defaultCharset()); } @SuppressWarnings("deprecation") @Override public void reloadConfig() { newConfig = YamlConfiguration.loadConfiguration(configFile); final InputStream defConfigStream = getResource("config.yml"); if (defConfigStream == null) { return; } final YamlConfiguration defConfig; if (isStrictlyUTF8() || FileConfiguration.UTF8_OVERRIDE) { defConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(defConfigStream, Charsets.UTF_8)); } else { final byte[] contents; defConfig = new YamlConfiguration(); try { contents = ByteStreams.toByteArray(defConfigStream); } catch (final IOException e) { getLogger().log(Level.SEVERE, "Unexpected failure reading config.yml", e); return; } final String text = new String(contents, Charset.defaultCharset()); if (!text.equals(new String(contents, Charsets.UTF_8))) { getLogger().warning("Default system encoding may have misread config.yml from plugin jar"); } try { defConfig.loadFromString(text); } catch (final InvalidConfigurationException e) { getLogger().log(Level.SEVERE, "Cannot load configuration from jar", e); } } newConfig.setDefaults(defConfig); } private boolean isStrictlyUTF8() { return getDescription().getAwareness().contains(PluginAwareness.Flags.UTF8); } @Override public void saveConfig() { try { getConfig().save(configFile); } catch (IOException ex) { logger.log(Level.SEVERE, "Could not save config to " + configFile, ex); } } @Override public void saveDefaultConfig() { if (!configFile.exists()) { saveResource("config.yml", false); } } @Override public void saveResource(String resourcePath, boolean replace) { if (resourcePath == null || resourcePath.equals("")) { throw new IllegalArgumentException("ResourcePath cannot be null or empty"); } resourcePath = resourcePath.replace('\\', '/'); InputStream in = getResource(resourcePath); if (in == null) { throw new IllegalArgumentException("The embedded resource '" + resourcePath + "' cannot be found in " + file); } File outFile = new File(dataFolder, resourcePath); int lastIndex = resourcePath.lastIndexOf('/'); File outDir = new File(dataFolder, resourcePath.substring(0, lastIndex >= 0 ? lastIndex : 0)); if (!outDir.exists()) { outDir.mkdirs(); } try { if (!outFile.exists() || replace) { OutputStream out = new FileOutputStream(outFile); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } out.close(); in.close(); } else { logger.log(Level.WARNING, "Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists."); } } catch (IOException ex) { logger.log(Level.SEVERE, "Could not save " + outFile.getName() + " to " + outFile, ex); } } @Override public InputStream getResource(String filename) { if (filename == null) { throw new IllegalArgumentException("Filename cannot be null"); } try { URL url = getClassLoader().getResource(filename); if (url == null) { return null; } URLConnection connection = url.openConnection(); connection.setUseCaches(false); return connection.getInputStream(); } catch (IOException ex) { return null; } } /** * Returns the ClassLoader which holds this plugin * * @return ClassLoader holding this plugin */ @Override public final ClassLoader getClassLoader() { return classLoader; } /** * @param loader the plugin loader * @param server the server instance * @param description the plugin's description * @param dataFolder the plugin's data folder * @param file the location of the plugin * @param classLoader the class loader * @deprecated This method is legacy and will be removed - it must be * replaced by the specially provided constructor(s). */ @Deprecated protected final void initialize(PluginLoader loader, Server server, PluginDescriptionFile description, File dataFolder, File file, ClassLoader classLoader) { if (server.getWarningState() == WarningState.OFF) { return; } getLogger().log(Level.WARNING, getClass().getName() + " is already initialized", server.getWarningState() == WarningState.DEFAULT ? null : new AuthorNagException("Explicit initialization")); } final void init(PluginLoader loader, Server server, PluginDescriptionFile description, File dataFolder, File file, ClassLoader classLoader) { this.loader = loader; this.server = server; this.file = file; this.description = description; this.dataFolder = dataFolder; this.classLoader = classLoader; this.configFile = new File(dataFolder, "config.yml"); this.logger = new PluginLogger(this); if (description.isDatabaseEnabled()) { ServerConfig db = new ServerConfig(); db.setDefaultServer(false); db.setRegister(false); db.setClasses(getDatabaseClasses()); db.setName(description.getName()); server.configureDbConfig(db); DataSourceConfig ds = db.getDataSourceConfig(); ds.setUrl(replaceDatabaseString(ds.getUrl())); dataFolder.mkdirs(); ClassLoader previous = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(classLoader); ebean = EbeanServerFactory.create(db); Thread.currentThread().setContextClassLoader(previous); } } /** * Provides a list of all classes that should be persisted in the database * * @return List of Classes that are Ebeans */ public List> getDatabaseClasses() { return new ArrayList>(); } private String replaceDatabaseString(String input) { input = input.replaceAll("\\{DIR\\}", dataFolder.getPath().replaceAll("\\\\", "/") + "/"); input = input.replaceAll("\\{NAME\\}", description.getName().replaceAll("[^\\w_-]", "")); return input; } /** * Gets the initialization status of this plugin * * @return true if this plugin is initialized, otherwise false * @deprecated This method cannot return false, as {@link * JavaPlugin} is now initialized in the constructor. */ @Deprecated public final boolean isInitialized() { return true; } /** * {@inheritDoc} */ @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { return false; } /** * {@inheritDoc} */ @Override public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { return null; } /** * Gets the command with the given name, specific to this plugin. Commands * need to be registered in the {@link PluginDescriptionFile#getCommands() * PluginDescriptionFile} to exist at runtime. * * @param name name or alias of the command * @return the plugin command if found, otherwise null */ public PluginCommand getCommand(String name) { String alias = name.toLowerCase(); PluginCommand command = getServer().getPluginCommand(alias); if (command == null || command.getPlugin() != this) { command = getServer().getPluginCommand(description.getName().toLowerCase() + ":" + alias); } if (command != null && command.getPlugin() == this) { return command; } else { return null; } } @Override public void onLoad() { } @Override public void onDisable() { } @Override public void onEnable() { } @Override public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { return null; } @Override public final boolean isNaggable() { return naggable; } @Override public final void setNaggable(boolean canNag) { this.naggable = canNag; } @Override public EbeanServer getDatabase() { return ebean; } protected void installDDL() { SpiEbeanServer serv = (SpiEbeanServer) getDatabase(); DdlGenerator gen = serv.getDdlGenerator(); gen.runScript(false, gen.generateCreateDdl()); } protected void removeDDL() { SpiEbeanServer serv = (SpiEbeanServer) getDatabase(); DdlGenerator gen = serv.getDdlGenerator(); gen.runScript(true, gen.generateDropDdl()); } @Override public final Logger getLogger() { return logger; } @Override public String toString() { return description.getFullName(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy