/*
* Contributions to FindBugs
* Copyright (C) 2010, Andrei Loskutov
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package de.tobject.findbugs.properties;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.swt.widgets.FileDialog;
import de.tobject.findbugs.DetectorsExtensionHelper;
import de.tobject.findbugs.FindbugsPlugin;
import de.tobject.findbugs.builder.FindBugsWorker;
import de.tobject.findbugs.properties.DetectorValidator.ValidationStatus;
import edu.umd.cs.findbugs.Plugin;
import edu.umd.cs.findbugs.config.UserPreferences;
public class DetectorProvider extends PathsProvider {
protected DetectorProvider(CheckboxTableViewer viewer, FindbugsPropertyPage propertyPage) {
super(viewer, propertyPage);
setDetectorPlugins(propertyPage.getCurrentUserPreferences());
}
/**
* The complexity of the code below is partly caused by the fact that we
* might have multiple ways to install and/or enable custom plugins. There
* are plugins discovered by FB itself, plugins contributed to Eclipse and
* plugins added by user manually via properties. Plugins can be disabled
* via code or properties. The code below is still work in progress, see
* also {@link FindbugsPlugin#applyCustomDetectors(boolean)}.
*
* @return a list with all known plugin paths known by FindBugs (they must
* neither be valid nor exists).
*/
public static List<IPathElement> getPluginElements(UserPreferences userPreferences) {
DetectorValidator validator = new DetectorValidator();
final List<IPathElement> newPaths = new ArrayList<IPathElement>();
Map<String, Boolean> pluginPaths = userPreferences.getCustomPlugins();
Set<String> disabledSystemPlugins = new HashSet<String>();
Set<URI> customPlugins = new HashSet<URI>();
Set<Entry<String,Boolean>> entrySet = pluginPaths.entrySet();
for (Entry<String, Boolean> entry : entrySet) {
String idOrPath = entry.getKey();
if(new Path(idOrPath).segmentCount() == 1) {
PathElement element = new PathElement(new Path(idOrPath), Status.OK_STATUS);
element.setSystem(true);
if (!entry.getValue().booleanValue()) {
element.setEnabled(false);
// this is not a path => this is a disabled plugin id
disabledSystemPlugins.add(idOrPath);
newPaths.add(element);
} else {
element.setEnabled(true);
}
continue;
}
// project is not supported (propertyPage.getProject() == null for workspace prefs).
IPath pluginPath = FindBugsWorker.getFilterPath(idOrPath, null);
URI uri = pluginPath.toFile().toURI();
customPlugins.add(uri);
ValidationStatus status = validator.validate(pluginPath.toOSString());
PathElement element = new PathElement(pluginPath, status);
Plugin plugin = Plugin.getByPluginId(status.getSummary().id);
if(plugin != null && !uri.equals(plugin.getPluginLoader().getURI())) {
// disable contribution if the plugin is already there
// but loaded from different location
element.setEnabled(false);
} else {
element.setEnabled(entry.getValue().booleanValue());
}
newPaths.add(element);
}
Map<URI, Plugin> allPlugins = Plugin.getAllPluginsMap();
// List of plugins contributed by Eclipse
SortedMap<String, String> contributedDetectors = DetectorsExtensionHelper.getContributedDetectors();
for (Entry<String, String> entry : contributedDetectors.entrySet()) {
String pluginId = entry.getKey();
URI uri = new Path(entry.getValue()).toFile().toURI();
Plugin plugin = allPlugins.get(uri);
if(plugin != null && !isEclipsePluginDisabled(pluginId, allPlugins)) {
PluginElement element = new PluginElement(plugin, true);
newPaths.add(0, element);
customPlugins.add(uri);
}
}
// Remaining plugins contributed by FB itself
for (Plugin plugin : allPlugins.values()) {
PluginElement element = new PluginElement(plugin, false);
if(!customPlugins.contains(plugin.getPluginLoader().getURI())) {
newPaths.add(0, element);
if(disabledSystemPlugins.contains(plugin.getPluginId())) {
element.setEnabled(false);
}
}
}
return newPaths;
}
/**
* Eclipse plugin can be disabled ONLY by user, so it must NOT be in the
* list of loaded plugins
*/
static boolean isEclipsePluginDisabled(String pluginId, Map<URI, Plugin> allPlugins) {
for (Plugin plugin : allPlugins.values()) {
if(pluginId.equals(plugin.getPluginId())) {
return false;
}
}
return true;
}
@Override
protected void applyToPreferences() {
super.applyToPreferences();
propertyPage.getCurrentUserPreferences().setCustomPlugins(pathsToStrings());
}
void setDetectorPlugins(UserPreferences userPreferences) {
setFilters(getPluginElements(userPreferences));
}
@Override
protected IStatus validate() {
DetectorValidator validator = new DetectorValidator();
IStatus bad = null;
for (IPathElement path : paths) {
if(path.isSystem()) {
continue;
}
String pathStr = path.getPath();
ValidationStatus status = validator.validate(pathStr);
path.setStatus(status);
if (!status.isOK() && path.isEnabled()) {
bad = status;
path.setEnabled(false);
break;
}
}
return bad;
}
@Override
protected void configureDialog(FileDialog dialog) {
dialog.setFilterExtensions(new String[] { "*.jar" });
dialog.setText("Select FindBugs plugins (file must have '.jar' extension)");
}
}