/******************************************************************************* * Copyright (c) 2016 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.windup.ui.internal.explorer; import static org.jboss.tools.windup.model.domain.WindupMarker.SEVERITY; import java.io.File; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.commons.collections.BidiMap; import org.apache.commons.collections.bidimap.DualHashBidiMap; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.jdt.internal.ui.navigator.IExtensionStateConstants; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.Viewer; import org.eclipse.ui.IMemento; import org.eclipse.ui.internal.navigator.NavigatorContentServiceContentProvider; import org.eclipse.ui.navigator.ICommonContentExtensionSite; import org.eclipse.ui.navigator.ICommonContentProvider; import org.eclipse.ui.navigator.IExtensionStateModel; import org.eclipse.ui.navigator.INavigatorContentService; import org.jboss.tools.windup.model.domain.ModelService; import org.jboss.tools.windup.model.domain.WindupConstants; import org.jboss.tools.windup.model.domain.WindupMarker; import org.jboss.tools.windup.ui.internal.Messages; import org.jboss.tools.windup.ui.internal.explorer.IssueConstants.Severity; import org.jboss.tools.windup.ui.internal.services.IssueGroupService; import org.jboss.tools.windup.ui.internal.services.MarkerService; import org.jboss.tools.windup.windup.ConfigurationElement; import org.jboss.tools.windup.windup.Hint; import org.jboss.tools.windup.windup.Input; import org.jboss.tools.windup.windup.Issue; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * Content provider for the Windup explorer. */ @SuppressWarnings("restriction") public class IssueExplorerContentProvider implements ICommonContentProvider { @Inject private IssueExplorerContentService contentService; @Override public Object[] getElements(Object inputElement) { return getChildren(inputElement); } @Override public Object[] getChildren(Object parent) { return contentService.getChildren(parent); } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object getParent(Object element) { return contentService.getParent(element); } @Override public boolean hasChildren(Object element) { return contentService.hasChildren(element); } @Override public void restoreState(IMemento aMemento) {} @Override public void saveState(IMemento aMemento) {} @Override public void init(ICommonContentExtensionSite aConfig) {} public static class TreeNodeBuilder { private List<IMarker> markers; private NavigatorContentServiceContentProvider contentProvider; private IssueGroupService groupService; private IEclipseContext context; private ConfigurationElement configuration; private MarkerService markerService; private ModelService modelService; private BidiMap nodeMap = new DualHashBidiMap(); // Used for explorer linking private Map<IResource, TreeNode> resourceMap = Maps.newHashMap(); public TreeNodeBuilder(List<IMarker> markers, IssueExplorer explorer, IssueGroupService groupService, IEclipseContext context, MarkerService markerService, ConfigurationElement configuration, ModelService modelService) { this.markers = markers; this.groupService = groupService; this.contentProvider = (NavigatorContentServiceContentProvider)explorer.getCommonViewer().getContentProvider(); contentProvider.getParents(ResourcesPlugin.getWorkspace().getRoot()); this.configuration = configuration; this.markerService = markerService; this.modelService = modelService; // TODO: Correct this temporary hack to get flat package layout. INavigatorContentService contentService = explorer.getCommonViewer().getNavigatorContentService(); IExtensionStateModel m = contentService.findStateModel(IssueConstants.JDT_CONTENT); m.setBooleanProperty(IExtensionStateConstants.Values.IS_LAYOUT_FLAT, true); this.context = context; } public Map<IResource, TreeNode> getResourceMap() { return resourceMap; } public TreeNode[] build() { if (configuration == null) { return new TreeNode[0]; } RootTreeNode root = new RootTreeNode(); for (IMarker marker : markers) { List<TreePath> paths = Lists.newArrayList(contentProvider.getParents(marker.getResource())); if (!paths.isEmpty()) { TreePath path = paths.get(0); build(root, root, path, marker, 1); } } List<TreeNode> children = root.getChildren(); if (children.isEmpty()) { return new TreeNode[0]; } return children.stream().toArray(TreeNode[]::new); } public BidiMap getNodeMap() { return nodeMap; } public void build(TreeNode root, TreeNode node, TreePath path, IMarker marker, int index) { if (groupService.isGroupByHierarchy()) { // build the hierarchy. if (index < path.getSegmentCount()) { Object segment = path.getSegment(index); TreeNode child = node.getChildPath(segment); if (child == null) { child = new TreeNode(segment); node.addChild(child); if (segment instanceof IProject) { resourceMap.put((IProject)segment, child); if (configuration.isGenerateReport() && !configuration.getInputs().isEmpty()) { Input input = configuration.getInputs().get(0); IPath reportPath = modelService.getGeneratedReport(configuration, input); File report = new File(reportPath.toString()); if (report.exists()) { TreeNode reportNode = child.getChildPath(Messages.generatedReport); if (reportNode == null) { reportNode = new RootReportNode(Messages.generatedReport, reportPath.toString()); child.addChild(reportNode); } } } } } build(root, child, path, marker, ++index); return; } } TreeNode parent = groupService.isGroupByHierarchy() ? node : root; if (groupService.isGroupByFile()) { TreeNode resourceNode = parent.getChildPath(marker.getResource()); if (resourceNode == null) { resourceNode = new TreeNode(marker.getResource()); parent.addChild(resourceNode); resourceMap.put(marker.getResource(), resourceNode); } parent = resourceNode; if (configuration.isGenerateReport()) { Issue issue = markerService.find(marker); if (issue != null) { if (issue.getGeneratedReportLocation() != null) { File report = new File(issue.getGeneratedReportLocation()); if (report.exists()) { TreeNode reportNode = parent.getChildPath(Messages.generatedReport); if (reportNode == null) { reportNode = new ReportNode(Messages.generatedReport, marker); parent.addChild(reportNode); } } } } } } if (groupService.isGroupBySeverity()) { Object segment = marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); String severity = marker.getAttribute(SEVERITY, Severity.POTENTIAL.toString()); TreeNode severityNode = parent.getChildPath(segment); if (severityNode == null) { severityNode = new SeverityNode(segment, severity); parent.addChild(severityNode); } parent = severityNode; } if (groupService.isGroupByRule()) { String ruleId = marker.getAttribute(WindupMarker.RULE_ID, WindupConstants.DEFAULT_RULE_ID); String title = ""; Issue issue = markerService.find(marker); if (issue instanceof Hint) { title = ((Hint)issue).getTitle(); } String segment = ruleId+title; TreeNode ruleNode = parent.getChildPath(segment); if (ruleNode == null) { ruleNode = new RuleGroupNode(segment, ruleId, title); parent.addChild(ruleNode); } parent = ruleNode; } Issue issue = markerService.find(marker); if (issue != null) { IEclipseContext child = context.createChild(); child.set(IMarker.class, marker); child.set(Issue.class, issue); MarkerNode markerNode = ContextInjectionFactory.make(MarkerNode.class, child); parent.addChild(markerNode); nodeMap.put(marker, markerNode); } } } public static class TreeNode { private Object segment; private TreeNode parent; private Map<Object, TreeNode> children = Maps.newHashMap(); public TreeNode(Object segment) { this.segment = segment; } public List<TreeNode> getChildren() { return Lists.newArrayList(children.values()); } public void removeChild(Object key) { children.remove(key); } public TreeNode getParent() { return parent; } public Object getSegment() { return segment; } public TreeNode getChildPath(Object path) { return children.get(path); } public void addChild(TreeNode node) { node.parent = this; children.put(node.segment, node); } public boolean isLeafParent() { if (children.isEmpty()) { return false; } for (Iterator<Map.Entry<Object, TreeNode>> iter = children.entrySet().iterator(); iter.hasNext();) { TreeNode child = iter.next().getValue(); if (!(child instanceof RootReportNode) && !(child instanceof ReportNode)) { if (child.getChildren().isEmpty()) { return true; } } } return false; } } public static class SeverityNode extends TreeNode { private String severity; public SeverityNode(Object segment, String severity) { super(segment); this.severity = severity; } public String getSeverity() { return severity; } } public static class RootTreeNode extends TreeNode { public RootTreeNode() { super(null); } } public static class RuleGroupNode extends TreeNode { private String ruleId; private String title; public RuleGroupNode(Object segment, String ruleId, String title) { super(segment); this.ruleId = ruleId; this.title = title; } public String getRuleId() { return ruleId; } public String getTitle() { return title; } } public static class TreeGroupNode extends TreeNode { public TreeGroupNode(Object segment) { super(segment); } } public static class ReportNode extends TreeNode { private IMarker marker; public ReportNode (Object segment, IMarker marker) { super(segment); this.marker = marker; } public IMarker getMarker() { return marker; } } public static class RootReportNode extends TreeNode { private String reportLocation; public RootReportNode(Object segment, String reportLocation) { super(segment); this.reportLocation = reportLocation; } public String getReportLocation() { return reportLocation; } } }