/* * SonarLint for Eclipse * Copyright (C) 2015-2017 SonarSource SA * sonarlint@sonarsource.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonarlint.eclipse.core.internal.extension; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker; import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler; import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; import org.eclipse.core.runtime.dynamichelpers.IFilter; import org.sonarlint.eclipse.core.SonarLintLogger; import org.sonarlint.eclipse.core.analysis.IAnalysisConfigurator; import org.sonarlint.eclipse.core.analysis.IFileLanguageProvider; import org.sonarlint.eclipse.core.configurator.ProjectConfigurator; import org.sonarlint.eclipse.core.resource.ISonarLintFileAdapterParticipant; import org.sonarlint.eclipse.core.resource.ISonarLintProjectAdapterParticipant; import org.sonarlint.eclipse.core.resource.ISonarLintProjectsProvider; public class SonarLintExtensionTracker implements IExtensionChangeHandler { private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ private final SonarLintEP<ProjectConfigurator> configuratorEp = new SonarLintEP<>("org.sonarlint.eclipse.core.projectConfigurators"); //$NON-NLS-1$ private final SonarLintEP<IAnalysisConfigurator> analysisEp = new SonarLintEP<>("org.sonarlint.eclipse.core.analysisConfigurator"); //$NON-NLS-1$ private final SonarLintEP<ISonarLintProjectsProvider> projectsProviderEp = new SonarLintEP<>("org.sonarlint.eclipse.core.projectsProvider"); //$NON-NLS-1$ private final SonarLintEP<ISonarLintFileAdapterParticipant> fileAdapterParticipantEp = new SonarLintEP<>("org.sonarlint.eclipse.core.fileAdapterParticipant"); //$NON-NLS-1$ private final SonarLintEP<ISonarLintProjectAdapterParticipant> projectAdapterParticipantEp = new SonarLintEP<>( "org.sonarlint.eclipse.core.projectAdapterParticipant"); //$NON-NLS-1$ private final SonarLintEP<IFileLanguageProvider> languageEp = new SonarLintEP<>("org.sonarlint.eclipse.core.languageProvider"); //$NON-NLS-1$ private static class SonarLintEP<G> { private final String id; private final Collection<G> instances = new ArrayList<>(); public SonarLintEP(String id) { this.id = id; } } private final Collection<SonarLintEP<?>> allEps = Arrays.asList(configuratorEp, analysisEp, projectsProviderEp, fileAdapterParticipantEp, projectAdapterParticipantEp, languageEp); private ExtensionTracker tracker; public void start() { IExtensionRegistry reg = Platform.getExtensionRegistry(); tracker = new ExtensionTracker(reg); IExtensionPoint[] epArray = allEps.stream().map(ep -> reg.getExtensionPoint(ep.id)).toArray(IExtensionPoint[]::new); IFilter filter = ExtensionTracker.createExtensionPointFilter(epArray); tracker.registerHandler(this, filter); for (IExtensionPoint ep : epArray) { for (IExtension ext : ep.getExtensions()) { addExtension(tracker, ext); } } } public void close() { if (tracker != null) { tracker.close(); tracker = null; } } @Override public void addExtension(IExtensionTracker tracker, IExtension extension) { IConfigurationElement[] configs = extension.getConfigurationElements(); for (final IConfigurationElement element : configs) { try { instanciateAndRegister(tracker, extension, element); } catch (CoreException e) { SonarLintLogger.get().error("Unable to load one SonarLint extension", e); } } } private void instanciateAndRegister(IExtensionTracker tracker, IExtension extension, final IConfigurationElement element) throws CoreException { for (SonarLintEP ep : allEps) { if (ep.id.equals(extension.getExtensionPointUniqueIdentifier())) { Object instance = element.createExecutableExtension(ATTR_CLASS); ep.instances.add(instance); // register association between object and extension with the tracker tracker.registerObject(extension, instance, IExtensionTracker.REF_WEAK); break; } } } @Override public void removeExtension(IExtension extension, Object[] objects) { // stop using objects associated with the removed extension for (SonarLintEP ep : allEps) { if (ep.id.equals(extension.getExtensionPointUniqueIdentifier())) { ep.instances.removeAll(Arrays.asList(objects)); break; } } } public Collection<ProjectConfigurator> getConfigurators() { return configuratorEp.instances; } public Collection<IAnalysisConfigurator> getAnalysisConfigurators() { return analysisEp.instances; } public Collection<ISonarLintProjectsProvider> getProjectsProviders() { return projectsProviderEp.instances; } public Collection<ISonarLintProjectAdapterParticipant> getProjectAdapterParticipants() { return projectAdapterParticipantEp.instances; } public Collection<ISonarLintFileAdapterParticipant> getFileAdapterParticipants() { return fileAdapterParticipantEp.instances; } public Collection<IFileLanguageProvider> getLanguageProviders() { return languageEp.instances; } }