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; }