blob: d501a7dfdf1f7a7bc8b9b14b55f01c98314cd516 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.api.tools.internal.builder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.IApiComponent;
import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
import org.eclipse.pde.api.tools.internal.provisional.builder.IApiProblemReporter;
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
/**
* Class for collecting {@link IApiProblem}s and creating {@link IMarker}s (if running in the framework)
*
* @since 1.0.0
*/
public class ApiProblemReporter implements IApiProblemReporter {
/**
* The current listing of {@link IApiProblem}s
*/
private HashMap fProblems = null;
/**
* The singleton instance
*/
private static ApiProblemReporter fInstance = null;
private static IProject fProject = null;
/**
* Constructor
*/
private ApiProblemReporter() {}
/**
* Returns an {@link ApiProblemReporter}
* @return an {@link ApiProblemReporter}
*/
public static ApiProblemReporter reporter(IProject project) {
Assert.isNotNull(project);
Assert.isTrue(project.isAccessible());
if(fInstance == null) {
fInstance = new ApiProblemReporter();
}
fProject = project;
return fInstance;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.builder.IApiProblemReporter#addProblem(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem)
*/
public boolean addProblem(IApiProblem problem) {
if(problem == null) {
return false;
}
if(isProblemFiltered(problem)) {
return false;
}
if(fProblems == null) {
fProblems = new HashMap();
}
String problemtype = getProblemTypeFromCategory(problem.getCategory());
HashSet problems = (HashSet) fProblems.get(problemtype);
if(problems == null) {
problems = new HashSet();
fProblems.put(problemtype, problems);
}
return problems.add(problem);
}
/**
* Returns the {@link IApiMarkerConstants} problem type given the
* problem category
* @param category
* @return the problem type or <code>null</code>
*/
private String getProblemTypeFromCategory(int category) {
switch(category) {
case IApiProblem.CATEGORY_API_PROFILE: {
return IApiMarkerConstants.DEFAULT_API_PROFILE_PROBLEM_MARKER;
}
case IApiProblem.CATEGORY_BINARY: {
return IApiMarkerConstants.BINARY_COMPATIBILITY_PROBLEM_MARKER;
}
case IApiProblem.CATEGORY_SINCETAGS: {
return IApiMarkerConstants.SINCE_TAGS_PROBLEM_MARKER;
}
case IApiProblem.CATEGORY_USAGE: {
return IApiMarkerConstants.API_USAGE_PROBLEM_MARKER;
}
case IApiProblem.CATEGORY_VERSION: {
return IApiMarkerConstants.VERSION_NUMBERING_PROBLEM_MARKER;
}
}
return null;
}
/**
* Creates new markers are for the listing of problems added to this reporter.
* If no problems have been added to this reporter, or we are not running in the framework,
* no work is done.
*/
public void createMarkers() {
if(fProblems == null || !ApiPlugin.isRunningInFramework()) {
return;
}
HashSet problems = null;
String type = null;
IApiProblem problem = null;
for(Iterator iter = fProblems.keySet().iterator(); iter.hasNext();) {
type = (String) iter.next();
problems = (HashSet) fProblems.get(type);
if(problems != null && problems.size() > 0) {
for(Iterator iter2 = problems.iterator(); iter2.hasNext();) {
problem = (IApiProblem) iter2.next();
createMarkerForProblem(type, problem);
}
}
}
}
/**
* Creates an {@link IMarker} on the resource specified
* in the problem (via its path) with the given problem
* attributes
* @param problem the problem to create a marker from
*/
private void createMarkerForProblem(String type, IApiProblem problem) {
IResource resource = resolveResource(problem);
if(resource == null) {
return;
}
try {
IMarker marker = resource.createMarker(type);
marker.setAttributes(
new String[] {IMarker.MESSAGE,
IMarker.SEVERITY,
IMarker.LINE_NUMBER,
IMarker.CHAR_START,
IMarker.CHAR_END,
IMarker.SOURCE_ID,
IApiMarkerConstants.MARKER_ATTR_PROBLEM_ID},
new Object[] {problem.getMessage(),
new Integer(problem.getSeverity()),
new Integer(problem.getLineNumber()),
new Integer(problem.getCharStart()),
new Integer(problem.getCharEnd()),
ApiAnalysisBuilder.SOURCE,
new Integer(problem.getId()),
}
);
//add message arguments, if any
String[] args = problem.getMessageArguments();
if(args.length > 0) {
marker.setAttribute(IApiMarkerConstants.MARKER_ATTR_MESSAGE_ARGUMENTS, createArgAttribute(args));
}
//add all other extra arguments, if any
if(problem.getExtraMarkerAttributeIds().length > 0) {
marker.setAttributes(problem.getExtraMarkerAttributeIds(), problem.getExtraMarkerAttributeValues());
}
} catch (CoreException e) {
//ignore and continue
return;
}
}
/**
* Creates a single string attribute from an array of strings. Uses the '#' char as
* a delimiter
* @param args
* @return a single string attribute from an array or arguments
*/
private String createArgAttribute(String[] args) {
StringBuffer buff = new StringBuffer();
for(int i = 0; i < args.length; i++) {
buff.append(args[i]);
if(i < args.length-1) {
buff.append("#"); //$NON-NLS-1$
}
}
return buff.toString();
}
/**
* Resolves the resource from the path in the problem, returns <code>null</code> in
* the following cases:
* <ul>
* <li>The resource is not found in the parent project (findMember() returns null)</li>
* <li>The resource is not accessible (isAccessible() returns false</li>
* </ul>
* @param problem the problem to get the resource for
* @return the resource or <code>null</code>
*/
private IResource resolveResource(IApiProblem problem) {
IResource resource = fProject.findMember(new Path(problem.getResourcePath()));
if(resource == null) {
return null;
}
if(!resource.isAccessible()) {
return null;
}
return resource;
}
/**
* Returns if the given {@link IApiProblem} should be filtered from having a problem marker created for it
*
* @param problem the problem that may or may not be filtered
* @return true if the {@link IApiProblem} should not have a marker created, false otherwise
*/
private boolean isProblemFiltered(IApiProblem problem) {
IApiComponent component = ApiPlugin.getDefault().getApiProfileManager().getWorkspaceProfile().getApiComponent(fProject.getName());
if(component != null) {
try {
return component.getFilterStore().isFiltered(problem);
}
catch(CoreException e) {
//ignore, return false
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.pde.api.tools.internal.provisional.builder.IApiProblemReporter#dispose()
*/
public void dispose() {
if(fProblems != null) {
fProblems.clear();
fProblems = null;
}
fProject = null;
}
}