/**
   * @param ctx Kernal context.
   * @param cfg Ignite configuration.
   * @param providers Plugin providers.
   */
  @SuppressWarnings("TypeMayBeWeakened")
  public IgnitePluginProcessor(
      GridKernalContext ctx, IgniteConfiguration cfg, List<PluginProvider> providers) {
    super(ctx);

    ExtensionRegistryImpl registry = new ExtensionRegistryImpl();

    for (PluginProvider provider : providers) {
      GridPluginContext pluginCtx = new GridPluginContext(ctx, cfg);

      if (F.isEmpty(provider.name())) throw new IgniteException("Plugin name can not be empty.");

      if (plugins.containsKey(provider.name()))
        throw new IgniteException("Duplicated plugin name: " + provider.name());

      plugins.put(provider.name(), provider);

      pluginCtxMap.put(provider, pluginCtx);

      provider.initExtensions(pluginCtx, registry);

      if (provider.plugin() == null) throw new IgniteException("Plugin is null.");
    }

    extensions = registry.createExtensionMap();
  }
  /** {@inheritDoc} */
  @Override
  public void onDiscoveryDataReceived(UUID nodeId, UUID rmtNodeId, Serializable data) {
    Map<String, Serializable> discData = (Map<String, Serializable>) data;

    if (discData != null) {
      for (Map.Entry<String, Serializable> e : discData.entrySet()) {
        PluginProvider provider = plugins.get(e.getKey());

        if (provider != null) provider.receiveDiscoveryData(nodeId, e.getValue());
        else U.warn(log, "Received discovery data for unknown plugin: " + e.getKey());
      }
    }
  }
  /** Print plugins information. */
  private void ackPluginsInfo() {
    U.quietAndInfo(log, "Configured plugins:");

    if (plugins.isEmpty()) {
      U.quietAndInfo(log, "  ^-- None");
      U.quietAndInfo(log, "");
    } else {
      for (PluginProvider plugin : plugins.values()) {
        U.quietAndInfo(log, "  ^-- " + plugin.name() + " " + plugin.version());
        U.quietAndInfo(log, "  ^-- " + plugin.copyright());
        U.quietAndInfo(log, "");
      }
    }
  }
  /**
   * @param cls Component class.
   * @param <T> Component type.
   * @return Component class instance or {@code null} if no one plugin override this component.
   */
  public <T> T createComponent(Class<T> cls) {
    for (PluginProvider plugin : plugins.values()) {
      PluginContext ctx = pluginContextForProvider(plugin);

      T comp = (T) plugin.createComponent(ctx, cls);

      if (comp != null) return comp;
    }

    return null;
  }
  /** {@inheritDoc} */
  @Nullable
  @Override
  public Serializable collectDiscoveryData(UUID nodeId) {
    HashMap<String, Serializable> discData = null;

    for (Map.Entry<String, PluginProvider> e : plugins.entrySet()) {
      Serializable data = e.getValue().provideDiscoveryData(nodeId);

      if (data != null) {
        if (discData == null) discData = new HashMap<>();

        discData.put(e.getKey(), data);
      }
    }

    return discData;
  }
 /** @return All plugin providers. */
 public Collection<PluginProvider> allProviders() {
   return plugins.values();
 }
 /**
  * @param name Plugin name.
  * @return Plugin provider.
  */
 @SuppressWarnings("unchecked")
 @Nullable
 public <T extends PluginProvider> T pluginProvider(String name) {
   return (T) plugins.get(name);
 }
 /**
  * @param provider Plugin context.
  * @return Plugin context.
  */
 @SuppressWarnings("unchecked")
 public <T extends PluginContext> T pluginContextForProvider(PluginProvider provider) {
   return (T) pluginCtxMap.get(provider);
 }