Package com.comphenix.protocol.injector

Source Code of com.comphenix.protocol.injector.PluginVerifier

package com.comphenix.protocol.injector;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginLoadOrder;

import com.google.common.collect.Sets;

/**
* Determine if a plugin using ProtocolLib is correct.
*
* @author Kristian
*/
class PluginVerifier {
  /**
   * A named plugin cannot be found.
   * @author Kristian
   */
  public static class PluginNotFoundException extends RuntimeException {
    /**
     * Generated by Eclipse.
     */
    private static final long serialVersionUID = 8956699101336877611L;

    public PluginNotFoundException() {
      super();
    }

    public PluginNotFoundException(String message) {
      super(message);
    }
  }
 
  public enum VerificationResult {
    VALID,
   
    /**
     * The plugin doesn't depend on ProtocolLib directly or indirectly.
     */
    NO_DEPEND;
   
    /**
     * Determine if the verification was valid.
     */
    public boolean isValid() {
      return this == VALID;
    }
  }
 
  /**
   * Contains a list of plugins that will detect and use ProtocolLib dynamically, instead of relying on the dependency system.
   */
  private static final Set<String> DYNAMIC_DEPENDENCY = Sets.newHashSet("mcore", "MassiveCore");
 
  /**
   * Set of plugins that have been loaded after ProtocolLib.
   */
  private final Set<String> loadedAfter = new HashSet<String>();
 
  /**
   * Reference to ProtocolLib.
   */
  private final Plugin dependency;
 
  /**
   * Construct a new plugin verifier.
   * @param dependency - reference to ProtocolLib, a dependency we require of plugins.
   */
  public PluginVerifier(Plugin dependency) {
    if (dependency == null)
      throw new IllegalArgumentException("dependency cannot be NULL.");
    // This would screw with the assumption in hasDependency(Plugin, Plugin)
    if (safeConversion(dependency.getDescription().getLoadBefore()).size() > 0)
      throw new IllegalArgumentException("dependency cannot have a load directives.");
   
    this.dependency = dependency;
  }

  /**
   * Retrieve a plugin by name.
   * @param pluginName - the non-null name of the plugin to retrieve.
   * @return The retrieved plugin.
   * @throws PluginNotFoundException If a plugin with the given name cannot be found.
   */
  private Plugin getPlugin(String pluginName) {
    Plugin plugin = getPluginOrDefault(pluginName);
   
    // Ensure that the plugin exists
    if (plugin != null)
      return plugin;
    else
      throw new PluginNotFoundException("Cannot find plugin " + pluginName);
  }
 
  /**
   * Retrieve a plugin by name.
   * @param pluginName - the non-null name of the plugin to retrieve.
   * @return The retrieved plugin, or NULL if not found.
   */
  private Plugin getPluginOrDefault(String pluginName) {
    return dependency.getServer().getPluginManager().getPlugin(pluginName);
  }
 
  /**
   * Performs simple verifications on the given plugin.
   * <p>
   * Results may be cached.
   * @param pluginName - the plugin to verify.
   * @return A verification result.
   * @throws IllegalArgumentException If plugin name is NULL.
   * @throws PluginNotFoundException If a plugin with the given name cannot be found.
   */
  public VerificationResult verify(String pluginName) {
    if (pluginName == null)
      throw new IllegalArgumentException("pluginName cannot be NULL.");
    return verify(getPlugin(pluginName));
  }
 
  /**
   * Performs simple verifications on the given plugin.
   * <p>
   * Results may be cached.
   * @param plugin - the plugin to verify.
   * @return A verification result.
   * @throws IllegalArgumentException If plugin name is NULL.
   * @throws PluginNotFoundException If a plugin with the given name cannot be found.
   */
  public VerificationResult verify(Plugin plugin) {
    if (plugin == null)
      throw new IllegalArgumentException("plugin cannot be NULL.");
    String name = plugin.getName();
   
    // Skip the load order check for ProtocolLib itself
    if (!dependency.equals(plugin)) {
      if (!loadedAfter.contains(name) && !DYNAMIC_DEPENDENCY.contains(name)) {
        if (verifyLoadOrder(dependency, plugin)) {
          // Memorize
          loadedAfter.add(plugin.getName());
        } else {
          return VerificationResult.NO_DEPEND;
        }
      }
    }
   
    // Everything seems to be in order
    return VerificationResult.VALID;
  }
 
  /**
   * Determine if a given plugin is guarenteed to be loaded before the other.
   * <p>
   * Note that the before plugin is assumed to have no "load" directives - that is, plugins to be
   * loaded after itself. The after plugin may have "load" directives, but it is irrelevant for our purposes.
   * @param beforePlugin - the plugin that is loaded first.
   * @param afterPlugin - the plugin that is loaded last.
   * @return TRUE if it will, FALSE if it may or must load in the opposite other.
   */
  private boolean verifyLoadOrder(Plugin beforePlugin, Plugin afterPlugin) {
    // If a plugin has a dependency, it will be loaded after its dependency
    if (hasDependency(afterPlugin, beforePlugin)) {
      return true;
    }
   
    // No dependency - check the load order
    if (beforePlugin.getDescription().getLoad() == PluginLoadOrder.STARTUP &&
      afterPlugin.getDescription().getLoad() == PluginLoadOrder.POSTWORLD) {
      return true;
    }
    return false;
  }
 
  /**
   * Determine if a plugin has a given dependency, either directly or indirectly.
   * @param plugin - the plugin to check.
   * @param dependency - the dependency to find.
   * @return TRUE if the plugin has the given dependency, FALSE otherwise.
   */
  private boolean hasDependency(Plugin plugin, Plugin dependency) {
    return hasDependency(plugin, dependency, Sets.<String>newHashSet());
  }
 
  /**
   * Convert a list to a set.
   * <p>
   * A null list will be converted to an empty set.
   * @param list - the list to convert.
   * @return The converted list.
   */
  private Set<String> safeConversion(List<String> list) {
    if (list == null)
      return Collections.emptySet();
    else
      return Sets.newHashSet(list);
  }
 
  // Avoid cycles. DFS.
  private boolean hasDependency(Plugin plugin, Plugin dependency, Set<String> checking) {
    Set<String> childNames = Sets.union(
         safeConversion(plugin.getDescription().getDepend()),
         safeConversion(plugin.getDescription().getSoftDepend())
    );
   
    // Ensure that the same plugin isn't processed twice
    if (!checking.add(plugin.getName())) {
      throw new IllegalStateException("Cycle detected in dependency graph: " + plugin);
    }
    // Look for the dependency in the immediate children
    if (childNames.contains(dependency.getName())) {
      return true;
    }
   
    // Recurse through their dependencies
    for (String childName : childNames) {
      Plugin childPlugin = getPluginOrDefault(childName);
     
      if (childPlugin != null && hasDependency(childPlugin, dependency, checking)) {
        return true;
      }
    }
   
    // Cross edges are permitted
    checking.remove(plugin.getName());
   
    // No dependency found!
    return false;
  }
}
TOP

Related Classes of com.comphenix.protocol.injector.PluginVerifier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.