public void registerExtension(
      final PluginDescriptor pluginDescriptor, final Element extensionElement) {
    final PluginId pluginId = pluginDescriptor.getPluginId();

    String epName = extractEPName(extensionElement);

    ExtensionComponentAdapter adapter;
    final PicoContainer container = getPluginContainer(pluginId.getIdString());
    final ExtensionPoint extensionPoint = getExtensionPoint(epName);
    if (extensionPoint.getKind() == ExtensionPoint.Kind.INTERFACE) {
      String implClass = extensionElement.getAttributeValue("implementation");
      if (implClass == null) {
        throw new RuntimeException(
            "'implementation' attribute not specified for '"
                + epName
                + "' extension in '"
                + pluginId.getIdString()
                + "' plugin");
      }
      adapter =
          new ExtensionComponentAdapter(
              implClass,
              extensionElement,
              container,
              pluginDescriptor,
              shouldDeserializeInstance(extensionElement));
    } else {
      adapter =
          new ExtensionComponentAdapter(
              extensionPoint.getClassName(), extensionElement, container, pluginDescriptor, true);
    }
    myExtensionElement2extension.put(extensionElement, adapter);
    internalGetPluginContainer().registerComponent(adapter);
    getExtensionPoint(epName).registerExtensionAdapter(adapter);
  }
  private static boolean checkDependants(
      final IdeaPluginDescriptor pluginDescriptor,
      final Function<PluginId, IdeaPluginDescriptor> pluginId2Descriptor,
      final Condition<PluginId> check,
      final Set<PluginId> processed) {
    processed.add(pluginDescriptor.getPluginId());
    final PluginId[] dependentPluginIds = pluginDescriptor.getDependentPluginIds();
    final Set<PluginId> optionalDependencies =
        new HashSet<PluginId>(Arrays.asList(pluginDescriptor.getOptionalDependentPluginIds()));
    for (final PluginId dependentPluginId : dependentPluginIds) {
      if (processed.contains(dependentPluginId)) continue;

      // TODO[yole] should this condition be a parameter?
      if (isModuleDependency(dependentPluginId)
          && (ourAvailableModules.isEmpty()
              || ourAvailableModules.contains(dependentPluginId.getIdString()))) {
        continue;
      }
      if (!optionalDependencies.contains(dependentPluginId)) {
        if (!check.value(dependentPluginId)) {
          return false;
        }
        final IdeaPluginDescriptor dependantPluginDescriptor =
            pluginId2Descriptor.fun(dependentPluginId);
        if (dependantPluginDescriptor != null
            && !checkDependants(dependantPluginDescriptor, pluginId2Descriptor, check, processed)) {
          return false;
        }
      }
    }
    return true;
  }
  static boolean shouldSkipPlugin(
      final IdeaPluginDescriptor descriptor, IdeaPluginDescriptor[] loaded) {
    final String idString = descriptor.getPluginId().getIdString();
    if (idString.equals(CORE_PLUGIN_ID)) {
      return false;
    }

    //noinspection HardCodedStringLiteral
    final String pluginId = System.getProperty("idea.load.plugins.id");
    if (pluginId == null) {
      if (descriptor instanceof IdeaPluginDescriptorImpl && !descriptor.isEnabled()) return true;

      if (!shouldLoadPlugins()) return true;
    }
    final List<String> pluginIds = pluginId == null ? null : StringUtil.split(pluginId, ",");

    final boolean checkModuleDependencies =
        !ourAvailableModules.isEmpty() && !ourAvailableModules.contains("com.intellij.modules.all");
    if (checkModuleDependencies && !hasModuleDependencies(descriptor)) {
      return true;
    }

    boolean shouldLoad;
    //noinspection HardCodedStringLiteral
    final String loadPluginCategory = System.getProperty("idea.load.plugins.category");
    if (loadPluginCategory != null) {
      shouldLoad = loadPluginCategory.equals(descriptor.getCategory());
    } else {
      if (pluginIds != null) {
        shouldLoad = pluginIds.contains(idString);
        if (!shouldLoad) {
          Map<PluginId, IdeaPluginDescriptor> map = new HashMap<PluginId, IdeaPluginDescriptor>();
          for (final IdeaPluginDescriptor pluginDescriptor : loaded) {
            map.put(pluginDescriptor.getPluginId(), pluginDescriptor);
          }
          addModulesAsDependents(map);
          final IdeaPluginDescriptor descriptorFromProperty = map.get(PluginId.getId(pluginId));
          shouldLoad =
              descriptorFromProperty != null
                  && isDependent(
                      descriptorFromProperty,
                      descriptor.getPluginId(),
                      map,
                      checkModuleDependencies);
        }
      } else {
        shouldLoad = !getDisabledPlugins().contains(idString);
      }
      if (shouldLoad && descriptor instanceof IdeaPluginDescriptorImpl) {
        if (isIncompatible(descriptor)) return true;
      }
    }

    return !shouldLoad;
  }
 static boolean isDependent(
     final IdeaPluginDescriptor descriptor,
     final PluginId on,
     Map<PluginId, IdeaPluginDescriptor> map,
     final boolean checkModuleDependencies) {
   for (PluginId id : descriptor.getDependentPluginIds()) {
     if (ArrayUtil.contains(id, (Object[]) descriptor.getOptionalDependentPluginIds())) {
       continue;
     }
     if (!checkModuleDependencies && isModuleDependency(id)) {
       continue;
     }
     if (id.equals(on)) {
       return true;
     }
     final IdeaPluginDescriptor depDescriptor = map.get(id);
     if (depDescriptor != null && isDependent(depDescriptor, on, map, checkModuleDependencies)) {
       return true;
     }
   }
   return false;
 }
 public void registerExtension(final String pluginName, final Element extensionElement) {
   registerExtension(new DefaultPluginDescriptor(PluginId.getId(pluginName)), extensionElement);
 }
 public void registerExtensionPoint(String pluginName, Element extensionPointElement) {
   registerExtensionPoint(
       new DefaultPluginDescriptor(PluginId.getId(pluginName)), extensionPointElement);
 }
  @Nullable
  static String filterBadPlugins(
      List<? extends IdeaPluginDescriptor> result, final Map<String, String> disabledPluginNames) {
    final Map<PluginId, IdeaPluginDescriptor> idToDescriptorMap =
        new HashMap<PluginId, IdeaPluginDescriptor>();
    final StringBuffer message = new StringBuffer();
    boolean pluginsWithoutIdFound = false;
    for (Iterator<? extends IdeaPluginDescriptor> it = result.iterator(); it.hasNext(); ) {
      final IdeaPluginDescriptor descriptor = it.next();
      final PluginId id = descriptor.getPluginId();
      if (id == null) {
        pluginsWithoutIdFound = true;
      }
      if (idToDescriptorMap.containsKey(id)) {
        message.append("<br>");
        message.append(IdeBundle.message("message.duplicate.plugin.id"));
        message.append(id);
        it.remove();
      } else if (descriptor.isEnabled()) {
        idToDescriptorMap.put(id, descriptor);
      }
    }
    addModulesAsDependents(idToDescriptorMap);
    final List<String> disabledPluginIds = new ArrayList<String>();
    final LinkedHashSet<String> faultyDescriptors = new LinkedHashSet<String>();
    for (final Iterator<? extends IdeaPluginDescriptor> it = result.iterator(); it.hasNext(); ) {
      final IdeaPluginDescriptor pluginDescriptor = it.next();
      checkDependants(
          pluginDescriptor,
          new Function<PluginId, IdeaPluginDescriptor>() {
            @Override
            public IdeaPluginDescriptor fun(final PluginId pluginId) {
              return idToDescriptorMap.get(pluginId);
            }
          },
          new Condition<PluginId>() {
            @Override
            public boolean value(final PluginId pluginId) {
              if (!idToDescriptorMap.containsKey(pluginId)) {
                pluginDescriptor.setEnabled(false);
                if (!pluginId.getIdString().startsWith(MODULE_DEPENDENCY_PREFIX)) {
                  faultyDescriptors.add(pluginId.getIdString());
                  disabledPluginIds.add(pluginDescriptor.getPluginId().getIdString());
                  message.append("<br>");
                  final String name = pluginDescriptor.getName();
                  final IdeaPluginDescriptor descriptor = idToDescriptorMap.get(pluginId);
                  String pluginName;
                  if (descriptor == null) {
                    pluginName = pluginId.getIdString();
                    if (disabledPluginNames.containsKey(pluginName)) {
                      pluginName = disabledPluginNames.get(pluginName);
                    }
                  } else {
                    pluginName = descriptor.getName();
                  }

                  message.append(
                      getDisabledPlugins().contains(pluginId.getIdString())
                          ? IdeBundle.message("error.required.plugin.disabled", name, pluginName)
                          : IdeBundle.message(
                              "error.required.plugin.not.installed", name, pluginName));
                }
                it.remove();
                return false;
              }
              return true;
            }
          });
    }
    if (!disabledPluginIds.isEmpty()) {
      myPlugins2Disable = disabledPluginIds;
      myPlugins2Enable = faultyDescriptors;
      message.append("<br>");
      message.append("<br>").append("<a href=\"" + DISABLE + "\">Disable ");
      if (disabledPluginIds.size() == 1) {
        final PluginId pluginId2Disable = PluginId.getId(disabledPluginIds.iterator().next());
        message.append(
            idToDescriptorMap.containsKey(pluginId2Disable)
                ? idToDescriptorMap.get(pluginId2Disable).getName()
                : pluginId2Disable.getIdString());
      } else {
        message.append("not loaded plugins");
      }
      message.append("</a>");
      boolean possibleToEnable = true;
      for (String descriptor : faultyDescriptors) {
        if (disabledPluginNames.get(descriptor) == null) {
          possibleToEnable = false;
          break;
        }
      }
      if (possibleToEnable) {
        message
            .append("<br>")
            .append("<a href=\"" + ENABLE + "\">Enable ")
            .append(
                faultyDescriptors.size() == 1
                    ? disabledPluginNames.get(faultyDescriptors.iterator().next())
                    : " all necessary plugins")
            .append("</a>");
      }
      message.append("<br>").append("<a href=\"" + EDIT + "\">Open plugin manager</a>");
    }
    if (pluginsWithoutIdFound) {
      message.append("<br>");
      message.append(IdeBundle.message("error.plugins.without.id.found"));
    }
    if (message.length() > 0) {
      message.insert(0, IdeBundle.message("error.problems.found.loading.plugins"));
      return message.toString();
    }
    return null;
  }
 private static void addModulesAsDependents(Map<PluginId, ? super IdeaPluginDescriptorImpl> map) {
   for (String module : ourAvailableModules) {
     // fake plugin descriptors to satisfy dependencies
     map.put(PluginId.getId(module), new IdeaPluginDescriptorImpl());
   }
 }
 public static boolean isModuleDependency(final PluginId dependentPluginId) {
   return dependentPluginId.getIdString().startsWith(MODULE_DEPENDENCY_PREFIX);
 }
  static void initializePlugins(@Nullable StartupProgress progress) {
    configureExtensions();

    final IdeaPluginDescriptorImpl[] pluginDescriptors = loadDescriptors(progress);

    final Class callerClass = ReflectionUtil.findCallerClass(1);
    assert callerClass != null;
    final ClassLoader parentLoader = callerClass.getClassLoader();

    final List<IdeaPluginDescriptorImpl> result = new ArrayList<IdeaPluginDescriptorImpl>();
    final HashMap<String, String> disabledPluginNames = new HashMap<String, String>();
    for (IdeaPluginDescriptorImpl descriptor : pluginDescriptors) {
      if (descriptor.getPluginId().getIdString().equals(CORE_PLUGIN_ID)) {
        final List<String> modules = descriptor.getModules();
        if (modules != null) {
          ourAvailableModules.addAll(modules);
        }
      }

      if (!shouldSkipPlugin(descriptor, pluginDescriptors)) {
        result.add(descriptor);
      } else {
        descriptor.setEnabled(false);
        disabledPluginNames.put(descriptor.getPluginId().getIdString(), descriptor.getName());
        initClassLoader(parentLoader, descriptor);
      }
    }

    prepareLoadingPluginsErrorMessage(filterBadPlugins(result, disabledPluginNames));

    final Map<PluginId, IdeaPluginDescriptorImpl> idToDescriptorMap =
        new HashMap<PluginId, IdeaPluginDescriptorImpl>();
    for (final IdeaPluginDescriptorImpl descriptor : result) {
      idToDescriptorMap.put(descriptor.getPluginId(), descriptor);
    }

    final IdeaPluginDescriptor corePluginDescriptor =
        idToDescriptorMap.get(PluginId.getId(CORE_PLUGIN_ID));
    assert corePluginDescriptor != null
        : CORE_PLUGIN_ID
            + " not found; platform prefix is "
            + System.getProperty(PlatformUtilsCore.PLATFORM_PREFIX_KEY);
    for (IdeaPluginDescriptorImpl descriptor : result) {
      if (descriptor != corePluginDescriptor) {
        descriptor.insertDependency(corePluginDescriptor);
      }
    }

    mergeOptionalConfigs(idToDescriptorMap);

    // sort descriptors according to plugin dependencies
    Collections.sort(result, getPluginDescriptorComparator(idToDescriptorMap));

    for (int i = 0; i < result.size(); i++) {
      ourId2Index.put(result.get(i).getPluginId(), i);
    }

    int i = 0;
    for (final IdeaPluginDescriptorImpl pluginDescriptor : result) {
      if (pluginDescriptor.getPluginId().getIdString().equals(CORE_PLUGIN_ID)
          || pluginDescriptor.isUseCoreClassLoader()) {
        pluginDescriptor.setLoader(parentLoader);
      } else {
        final List<File> classPath = pluginDescriptor.getClassPath();
        final PluginId[] dependentPluginIds = pluginDescriptor.getDependentPluginIds();
        final ClassLoader[] parentLoaders = getParentLoaders(idToDescriptorMap, dependentPluginIds);

        final ClassLoader pluginClassLoader =
            createPluginClassLoader(
                classPath.toArray(new File[classPath.size()]),
                parentLoaders.length > 0 ? parentLoaders : new ClassLoader[] {parentLoader},
                pluginDescriptor);
        pluginDescriptor.setLoader(pluginClassLoader);
      }

      if (progress != null) {
        progress.showProgress(
            "", PLUGINS_PROGRESS_MAX_VALUE + (i++ / (float) result.size()) * 0.35f);
      }
    }

    registerExtensionPointsAndExtensions(Extensions.getRootArea(), result);
    Extensions.getRootArea()
        .getExtensionPoint(Extensions.AREA_LISTENER_EXTENSION_POINT)
        .registerExtension(
            new AreaListener() {
              @Override
              public void areaCreated(
                  @NotNull String areaClass, @NotNull AreaInstance areaInstance) {
                registerExtensionPointsAndExtensions(Extensions.getArea(areaInstance), result);
              }

              @Override
              public void areaDisposing(
                  @NotNull String areaClass, @NotNull AreaInstance areaInstance) {}
            });

    ourPlugins = pluginDescriptors;
  }