Example #1
0
  /**
   * This will create a {@link PluginEnvironment} for the plugin at the given URL. The plugin's
   * descriptor is parsed. Once this method returns, the plugin's components are ready to be created
   * and used.
   *
   * @param pluginUrl the new plugin's jar location
   * @param classLoader the new plugin's classloader
   * @param pluginDescriptor the already parsed plugin descriptor for this plugin
   * @throws PluginContainerException if the plugin fails to load
   */
  private void loadPlugin(URL pluginUrl, ClassLoader classLoader, PluginDescriptor pluginDescriptor)
      throws PluginContainerException {

    if (log.isDebugEnabled()) {
      log.debug("Loading plugin from [" + pluginUrl + "] in classloader [" + classLoader + "]...");
    }

    PluginDescriptorLoader pluginDescriptorLoader =
        new PluginDescriptorLoader(pluginUrl, classLoader);
    PluginEnvironment pluginEnvironment =
        new PluginEnvironment(pluginDescriptor.getName(), pluginDescriptorLoader);
    String pluginName = pluginEnvironment.getPluginName();

    // tell the plugin we have loaded it
    PluginLifecycleListener overseer =
        getPluginLifecycleListener(pluginName, pluginEnvironment, pluginDescriptor);
    if (overseer != null) {
      PluginContext context = createPluginContext(pluginName);
      ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader();
      try {
        Thread.currentThread().setContextClassLoader(classLoader);
        overseer.initialize(context);
      } catch (Throwable t) {
        throw new PluginContainerException(
            "Plugin Lifecycle Listener failed to initialize plugin", t);
      } finally {
        Thread.currentThread().setContextClassLoader(originalContextClassLoader);
      }
    }

    // everything is loaded and initialized
    this.loadedPluginEnvironments.put(pluginName, pluginEnvironment);
    this.metadataManager.loadPlugin(pluginDescriptor);
    pluginLifecycleListenerMgr.setListener(pluginDescriptor.getName(), overseer);
    updateLoadedPlugins.execute(pluginDescriptor, pluginUrl);
  }
Example #2
0
  /**
   * Finds all plugins using the plugin finder defined in the <code>pluginContainerConfiguration
   * </code> and {@link #loadPlugin(java.net.URL, ClassLoader,
   * org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor) loads} each plugin found.
   */
  public PluginManager(
      PluginContainerConfiguration pluginContainerConfiguration,
      PluginLifecycleListenerManager pluginLifecycleListenerManager) {

    if (pluginContainerConfiguration == null) {
      throw new NullPointerException("pluginContainerConfiguration is null");
    }
    if (pluginLifecycleListenerManager == null) {
      throw new NullPointerException("pluginLifecycleListenerManager is null");
    }

    this.pluginContainerConfiguration = pluginContainerConfiguration;
    this.pluginLifecycleListenerMgr = pluginLifecycleListenerManager;
    loadedPluginEnvironments = new HashMap<String, PluginEnvironment>();
    loadedPlugins = new ArrayList<Plugin>();
    metadataManager = new PluginMetadataManager();

    metadataManager.setDisabledResourceTypes(
        pluginContainerConfiguration.getDisabledResourceTypes());
    updateLoadedPlugins =
        new UpdateLoadedPlugins() {
          PluginTransformer transformer = new PluginTransformer();

          public void execute(PluginDescriptor pluginDescriptor, URL pluginURL) {
            Plugin plugin = transformer.toPlugin(pluginDescriptor, pluginURL);
            loadedPlugins.add(plugin);
          }
        };

    PluginFinder finder = pluginContainerConfiguration.getPluginFinder();
    File tmpDir = pluginContainerConfiguration.getTemporaryDirectory();
    List<String> disabledPlugins = pluginContainerConfiguration.getDisabledPlugins();

    // The root classloader for all plugins will have all classes hidden except for those configured
    // in the regex.
    // Notice this root classloader has no jar URLs - it will provide no classes except for what it
    // will allow
    // the parent to expose as dictated by the regex.
    ClassLoader thisClassLoader = this.getClass().getClassLoader();
    String rootPluginClassLoaderRegex =
        pluginContainerConfiguration.getRootPluginClassLoaderRegex();
    ClassLoader rootCL =
        new RootPluginClassLoader(new URL[] {}, thisClassLoader, rootPluginClassLoaderRegex);

    // build our empty class loader manager - we use it to create and manage our plugin's
    // classloaders
    Map<String, URL> pluginNamesUrls = new HashMap<String, URL>();
    // Save descriptors for later use, so we don't need to parse them twice.
    Map<URL, PluginDescriptor> descriptors = new HashMap<URL, PluginDescriptor>();
    PluginDependencyGraph graph = new PluginDependencyGraph();
    boolean createResourceCL = pluginContainerConfiguration.isCreateResourceClassloaders();
    this.classLoaderManager =
        new ClassLoaderManager(pluginNamesUrls, graph, rootCL, tmpDir, createResourceCL);

    if (finder == null) {
      log.warn(
          "No plugin finder was specified in the plugin container configuration - this should only occur within test environments.");
      return;
    }

    try {
      Collection<URL> pluginUrls = finder.findPlugins();

      // first, we need to parse all descriptors so we can build the dependency graph
      for (URL url : pluginUrls) {
        log.debug("Plugin found at: " + url);
        try {
          PluginDescriptor descriptor = AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(url);
          if (!disabledPlugins.contains(descriptor.getName())) {
            AgentPluginDescriptorUtil.addPluginToDependencyGraph(graph, descriptor);
            pluginNamesUrls.put(descriptor.getName(), url);
            descriptors.put(url, descriptor);
          } else {
            log.info("Not loading disabled plugin: " + url);
          }
        } catch (Throwable t) {
          // probably due to invalid XML syntax in the deployment descriptor - the plugin will be
          // ignored
          log.error(
              "Plugin at [" + url + "] could not be loaded and will therefore not be deployed.", t);
          continue;
        }
      }

      // our graph is complete, get the order that we have to deploy the plugins
      List<String> deploymentOrder = graph.getDeploymentOrder();

      // now deploy the plugins in the proper order, making sure we build the proper classloaders
      for (String nextPlugin : deploymentOrder) {
        URL pluginUrl = pluginNamesUrls.get(nextPlugin);

        try {
          ClassLoader pluginClassLoader =
              this.classLoaderManager.obtainPluginClassLoader(nextPlugin);
          PluginDescriptor descriptor = descriptors.get(pluginUrl);
          loadPlugin(pluginUrl, pluginClassLoader, descriptor);
        } catch (Throwable t) {
          // for some reason, the plugin failed to load - it will be ignored, and its depending
          // plugins will also fail later
          log.error(
              "Plugin ["
                  + nextPlugin
                  + "] at ["
                  + pluginUrl
                  + "] could not be loaded and will therefore not be deployed.",
              t);
          continue;
        }
      }
      log.info("Deployed plugins: " + this.loadedPlugins);
      metadataManager.cleanupDescriptors();
    } catch (Exception e) {
      shutdown(); // have to clean up the environments (e.g. unpacked jars) we might have already
      // created
      log.error("Error initializing plugin container", e);
      throw new RuntimeException("Cannot initialize the plugin container", e);
    }
  }