protected String getPluginCaller(String method) {
    String packageName;
    String pluginName;
    StackTraceElement[] traces = new Exception().getStackTrace();
    StackTraceElement trace;

    int tracesLength = traces.length;
    for (int i = 0; i < tracesLength; i++) {
      trace = traces[i];

      if (trace.getMethodName().equals(method) && tracesLength >= i) {
        trace = traces[++i];

        packageName = trace.getClassName();
        packageName = packageName.substring(0, packageName.lastIndexOf('.'));
        pluginName = plugins.get(packageName);

        if (pluginName != null) {
          return pluginName;
        }

        MessageSender.getInstance()
            .debug(
                "<red>Couldn't figure out plugin of package: "
                    + packageName
                    + " | class="
                    + trace.getClassName());
        return null;
      }
    }

    MessageSender.getInstance().debug("<red>Couldn't find caller of " + method + "!");
    return null;
  }
  private void setupVault(PluginManager pm) {
    if (pm.getPlugin("Vault") == null) {
      MessageSender.getInstance().log("Vault was not found, economy features are not available.");
    } else {
      RegisteredServiceProvider<Economy> econProvider =
          getServer().getServicesManager().getRegistration(Economy.class);
      if (econProvider != null) {
        Econ.getInstance().init(econProvider.getProvider());
      }

      RegisteredServiceProvider<Permission> permProvider =
          getServer().getServicesManager().getRegistration(Permission.class);
      if (permProvider != null) {
        Perms.getInstance().init(permProvider.getProvider());
      }
    }
  }
  @Override
  public void onDisable() {
    try {
      Bukkit.getScheduler().cancelTasks(this);

      if (plugin == null) {
        return;
      }

      Vanilla.removeCustomRecipes();

      Furnaces.save();
      Furnaces.clean();

      BrewingStands.save();
      BrewingStands.clean();

      Workbenches.clean();
      Players.clean();
      Vanilla.clean();

      recipes.clean();
      recipes = null;

      recipeBooks.clean();
      recipeBooks = null;

      events.clean();
      events = null;

      Settings.clean();

      Econ.getInstance().clean();
      Perms.getInstance().clean();

      if (metrics != null) {
        metrics.stop();
        metrics = null;
      }

      plugin = null;
    } catch (Throwable e) {
      MessageSender.getInstance().error(null, e, null);
    }
  }
  @Override
  public void onEnable() {
    if (loaded) {
      MessageSender.getInstance().info(ChatColor.RED + "Plugin is already enabled");
      return;
    }

    plugin = this;
    Locale.setDefault(Locale.ENGLISH); // avoid needless complications

    PluginManager pm = getServer().getPluginManager();

    FurnaceData.init(); // dummy caller
    BrewingStandData.init();
    Furnaces.load(); // load saved furnaces...
    BrewingStands.load();

    events = new Events();
    recipes = new Recipes();

    setupVault(pm);

    Vanilla.init(); // get initial recipes...

    Args.init(); // dummy method to avoid errors on 'reload' with updating
    ArgBuilder.init();

    flagLoader = new FlagLoader();

    // wait for all plugins to load then enable this
    new BukkitRunnable() {
      public void run() {
        onEnablePost();
      }
    }.runTask(this);
  }