public void unregisterExtension(String pluginName, Element extensionElement) {
   String epName = extractEPName(extensionElement);
   if (!myExtensionElement2extension.containsKey(extensionElement)) {
     XMLOutputter xmlOutputter = new XMLOutputter();
     Format format =
         Format.getCompactFormat().setIndent("  ").setTextMode(Format.TextMode.NORMALIZE);
     xmlOutputter.setFormat(format);
     StringWriter stringWriter = new StringWriter();
     try {
       xmlOutputter.output(extensionElement, stringWriter);
     } catch (IOException e) {
       throw new RuntimeException(e);
     }
     myLogger.warn(stringWriter.toString());
     throw new IllegalArgumentException(
         "Trying to unregister extension element that was never registered");
   }
   ExtensionComponentAdapter adapter = myExtensionElement2extension.remove(extensionElement);
   if (adapter == null) return;
   if (getExtensionPoint(epName).unregisterComponentAdapter(adapter)) {
     MutablePicoContainer pluginContainer = internalGetPluginContainer();
     pluginContainer.unregisterComponent(adapter.getComponentKey());
     if (pluginContainer.getComponentAdapters().isEmpty()) {
       disposePluginContainer(pluginName);
     }
   }
 }
 public void unregisterExtensionPoint(final String extensionPointName) {
   ExtensionPoint extensionPoint = myExtensionPoints.get(extensionPointName);
   if (extensionPoint != null) {
     extensionPoint.reset();
     myExtensionPoints.remove(extensionPointName);
     notifyEPRemoved(extensionPoint);
   }
 }
 public void registerExtensionPoint(final ExtensionPointImpl extensionPoint) {
   final String name = extensionPoint.getName();
   myExtensionPoints.put(name, extensionPoint);
   notifyEPRegistered(extensionPoint);
   if (DEBUG_REGISTRATION) {
     myEPTraces.put(name, new Throwable("Original registration for " + name));
   }
 }
  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;
  }
  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 void registerExtensionPoint(
      final String extensionPointName,
      String extensionPointBeanClass,
      PluginDescriptor descriptor,
      ExtensionPoint.Kind kind) {
    if (hasExtensionPoint(extensionPointName)) {
      if (DEBUG_REGISTRATION) {
        final ExtensionPointImpl oldEP = getExtensionPoint(extensionPointName);
        myLogger.error(
            "Duplicate registration for EP: "
                + extensionPointName
                + ": original plugin "
                + oldEP.getDescriptor().getPluginId()
                + ", new plugin "
                + descriptor.getPluginId(),
            myEPTraces.get(extensionPointName));
      }
      throw new RuntimeException("Duplicate registration for EP: " + extensionPointName);
    }

    registerExtensionPoint(
        new ExtensionPointImpl(
            extensionPointName,
            extensionPointBeanClass,
            kind,
            this,
            myAreaInstance,
            myLogger,
            descriptor));
  }
 @NotNull
 public <T> ExtensionPointImpl<T> getExtensionPoint(String extensionPointName) {
   ExtensionPointImpl<T> extensionPoint = myExtensionPoints.get(extensionPointName);
   if (extensionPoint == null) {
     throw new IllegalArgumentException(
         "Missing extension point: " + extensionPointName + " in area " + myAreaInstance);
   }
   return extensionPoint;
 }
  @SuppressWarnings({"unchecked"})
  private void initialize() {
    for (Map.Entry<String, String> entry : ourDefaultEPs.entrySet()) {
      String epName = entry.getKey();
      registerExtensionPoint(epName, entry.getValue());
    }

    getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME)
        .addExtensionPointListener(
            new ExtensionPointListener() {
              @SuppressWarnings({"unchecked"})
              public void extensionRemoved(
                  @NotNull Object extension, final PluginDescriptor pluginDescriptor) {
                EPAvailabilityListenerExtension epListenerExtension =
                    (EPAvailabilityListenerExtension) extension;
                Collection<ExtensionPointAvailabilityListener> listeners =
                    myAvailabilityListeners.get(epListenerExtension.getExtensionPointName());
                for (Iterator<ExtensionPointAvailabilityListener> iterator = listeners.iterator();
                    iterator.hasNext(); ) {
                  ExtensionPointAvailabilityListener listener = iterator.next();
                  if (listener
                      .getClass()
                      .getName()
                      .equals(epListenerExtension.getListenerClass())) {
                    iterator.remove();
                    return;
                  }
                }
                myLogger.warn(
                    "Failed to find EP availability listener: "
                        + epListenerExtension.getListenerClass());
              }

              public void extensionAdded(
                  @NotNull Object extension, final PluginDescriptor pluginDescriptor) {
                EPAvailabilityListenerExtension epListenerExtension =
                    (EPAvailabilityListenerExtension) extension;
                try {
                  String epName = epListenerExtension.getExtensionPointName();

                  ExtensionPointAvailabilityListener listener =
                      (ExtensionPointAvailabilityListener)
                          instantiate(epListenerExtension.loadListenerClass());
                  addAvailabilityListener(epName, listener);
                } catch (Exception e) {
                  throw new RuntimeException(e);
                }
              }
            });
  }
  static ClassLoader[] getParentLoaders(
      Map<PluginId, ? extends IdeaPluginDescriptor> idToDescriptorMap, PluginId[] pluginIds) {
    if (isUnitTestMode()) return new ClassLoader[0];
    final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
    for (final PluginId id : pluginIds) {
      IdeaPluginDescriptor pluginDescriptor = idToDescriptorMap.get(id);
      if (pluginDescriptor == null) {
        continue; // Might be an optional dependency
      }

      final ClassLoader loader = pluginDescriptor.getPluginClassLoader();
      if (loader == null) {
        getLogger().error("Plugin class loader should be initialized for plugin " + id);
      }
      classLoaders.add(loader);
    }
    return classLoaders.toArray(new ClassLoader[classLoaders.size()]);
  }
 static void mergeOptionalConfigs(Map<PluginId, IdeaPluginDescriptorImpl> descriptors) {
   final Map<PluginId, IdeaPluginDescriptorImpl> descriptorsWithModules =
       new HashMap<PluginId, IdeaPluginDescriptorImpl>(descriptors);
   addModulesAsDependents(descriptorsWithModules);
   for (IdeaPluginDescriptorImpl descriptor : descriptors.values()) {
     final Map<PluginId, IdeaPluginDescriptorImpl> optionalDescriptors =
         descriptor.getOptionalDescriptors();
     if (optionalDescriptors != null && !optionalDescriptors.isEmpty()) {
       for (Map.Entry<PluginId, IdeaPluginDescriptorImpl> entry : optionalDescriptors.entrySet()) {
         if (descriptorsWithModules.containsKey(entry.getKey())) {
           descriptor.mergeOptionalConfig(entry.getValue());
         }
       }
     }
   }
 }
 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;
 }
  private static Graph<PluginId> createPluginIdGraph(
      final Map<PluginId, IdeaPluginDescriptorImpl> idToDescriptorMap) {
    final List<PluginId> ids = new ArrayList<PluginId>(idToDescriptorMap.keySet());
    // this magic ensures that the dependent plugins always follow their dependencies in
    // lexicographic order
    // needed to make sure that extensions are always in the same order
    Collections.sort(
        ids,
        new Comparator<PluginId>() {
          @Override
          public int compare(PluginId o1, PluginId o2) {
            return o2.getIdString().compareTo(o1.getIdString());
          }
        });
    return GraphGenerator.create(
        CachingSemiGraph.create(
            new GraphGenerator.SemiGraph<PluginId>() {
              @Override
              public Collection<PluginId> getNodes() {
                return ids;
              }

              @Override
              public Iterator<PluginId> getIn(PluginId pluginId) {
                final IdeaPluginDescriptor descriptor = idToDescriptorMap.get(pluginId);
                ArrayList<PluginId> plugins = new ArrayList<PluginId>();
                for (PluginId dependentPluginId : descriptor.getDependentPluginIds()) {
                  // check for missing optional dependency
                  if (idToDescriptorMap.containsKey(dependentPluginId)) {
                    plugins.add(dependentPluginId);
                  }
                }
                return plugins.iterator();
              }
            }));
  }
 public ExtensionPoint[] getExtensionPoints() {
   return myExtensionPoints.values().toArray(new ExtensionPoint[myExtensionPoints.size()]);
 }
 static {
   ourDefaultEPs.put(
       EPAvailabilityListenerExtension.EXTENSION_POINT_NAME,
       EPAvailabilityListenerExtension.class.getName());
 }
 public void addAvailabilityListener(String epName, ExtensionPointAvailabilityListener listener) {
   myAvailabilityListeners.putValue(epName, listener);
   if (hasExtensionPoint(epName)) {
     notifyAvailableListener(listener, myExtensionPoints.get(epName));
   }
 }
 public static int getPluginLoadingOrder(PluginId id) {
   return ourId2Index.get(id);
 }
 public MutablePicoContainer[] getPluginContainers() {
   return myPluginName2picoContainer
       .values()
       .toArray(new MutablePicoContainer[myPluginName2picoContainer.values().size()]);
 }
 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());
   }
 }
  @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;
  }
  @SuppressWarnings({"HardCodedStringLiteral"})
  @Nullable
  public static IdeaPluginDescriptorImpl loadDescriptor(
      final File file, @NonNls final String fileName) {
    IdeaPluginDescriptorImpl descriptor = null;

    if (file.isDirectory()) {
      descriptor = loadDescriptorFromDir(file, fileName);

      if (descriptor == null) {
        File libDir = new File(file, "lib");
        if (!libDir.isDirectory()) {
          return null;
        }
        final File[] files = libDir.listFiles();
        if (files == null || files.length == 0) {
          return null;
        }
        Arrays.sort(
            files,
            new Comparator<File>() {
              @Override
              public int compare(File o1, File o2) {
                if (o2.getName().startsWith(file.getName())) return Integer.MAX_VALUE;
                if (o1.getName().startsWith(file.getName())) return -Integer.MAX_VALUE;
                if (o2.getName().startsWith("resources")) return -Integer.MAX_VALUE;
                if (o1.getName().startsWith("resources")) return Integer.MAX_VALUE;
                return 0;
              }
            });
        for (final File f : files) {
          if (FileUtil.isJarOrZip(f)) {
            descriptor = loadDescriptorFromJar(f, fileName);
            if (descriptor != null) {
              descriptor.setPath(file);
              break;
            }
            //           getLogger().warn("Cannot load descriptor from " + f.getName() + "");
          } else if (f.isDirectory()) {
            IdeaPluginDescriptorImpl descriptor1 = loadDescriptorFromDir(f, fileName);
            if (descriptor1 != null) {
              if (descriptor != null) {
                getLogger()
                    .info("Cannot load " + file + " because two or more plugin.xml's detected");
                return null;
              }
              descriptor = descriptor1;
              descriptor.setPath(file);
            }
          }
        }
      }
    } else if (StringUtil.endsWithIgnoreCase(file.getName(), ".jar") && file.exists()) {
      descriptor = loadDescriptorFromJar(file, fileName);
    }

    if (descriptor != null && !descriptor.getOptionalConfigs().isEmpty()) {
      final Map<PluginId, IdeaPluginDescriptorImpl> descriptors =
          new HashMap<PluginId, IdeaPluginDescriptorImpl>(descriptor.getOptionalConfigs().size());
      for (Map.Entry<PluginId, String> entry : descriptor.getOptionalConfigs().entrySet()) {
        String optionalDescriptorName = entry.getValue();
        assert !Comparing.equal(fileName, optionalDescriptorName)
            : "recursive dependency: " + fileName;

        IdeaPluginDescriptorImpl optionalDescriptor = loadDescriptor(file, optionalDescriptorName);
        if (optionalDescriptor == null && !FileUtil.isJarOrZip(file)) {
          for (URL url : getClassLoaderUrls()) {
            if ("file".equals(url.getProtocol())) {
              optionalDescriptor =
                  loadDescriptor(new File(decodeUrl(url.getFile())), optionalDescriptorName);
              if (optionalDescriptor != null) {
                break;
              }
            }
          }
        }
        if (optionalDescriptor != null) {
          descriptors.put(entry.getKey(), optionalDescriptor);
        } else {
          getLogger().info("Cannot find optional descriptor " + optionalDescriptorName);
        }
      }
      descriptor.setOptionalDescriptors(descriptors);
    }
    return descriptor;
  }
 public boolean hasExtensionPoint(String extensionPointName) {
   return myExtensionPoints.containsKey(extensionPointName);
 }
 private void disposePluginContainer(String pluginName) {
   DefaultPicoContainer pluginContainer = myPluginName2picoContainer.remove(pluginName);
   if (pluginContainer != null) {
     myPicoContainer.removeChildContainer(pluginContainer);
   }
 }
 @TestOnly
 public final void notifyAreaReplaced() {
   for (final ExtensionPointImpl point : myExtensionPoints.values()) {
     point.notifyAreaReplaced(this);
   }
 }
  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;
  }