/*******************************************************************************
* Copyright (c) 2009,2010 QNX Software Systems
* 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:
* QNX Software Systems (Alena Laskavaia) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.codan.internal.core.model;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Properties;
import org.eclipse.cdt.codan.core.model.CodanSeverity;
import org.eclipse.cdt.codan.core.model.ICodanProblemMarker;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemCategory;
import org.eclipse.cdt.codan.core.model.IProblemLocation;
import org.eclipse.cdt.codan.core.model.IProblemProfile;
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
/**
* Instance of a problem. Intermediate representation before problem become a
* marker
*
* @since 1.1
*/
public class CodanProblemMarker implements ICodanProblemMarker {
private static final String PROBLEM_ARGS = "args"; //$NON-NLS-1$
private IProblemLocation loc;
private IProblem problem;
private Object args[];
public Object[] getArgs() {
return args;
}
/**
* @param problem
* @param loc
* @param args
*/
public CodanProblemMarker(IProblem problem, IProblemLocation loc, Object[] args) {
this.problem = problem;
this.loc = loc;
this.args = args;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.ICodanProblemMarker#getLocation()
*/
public IProblemLocation getLocation() {
return loc;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.ICodanProblemMarker#getProblem()
*/
public IProblem getProblem() {
return problem;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.ICodanProblemMarker#getResource()
*/
public IResource getResource() {
return loc.getFile();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.ICodanProblemMarker#createMarker()
*/
public IMarker createMarker() throws CoreException {
IResource file = loc.getFile();
int lineNumber = loc.getLineNumber();
int severity = problem.getSeverity().intValue();
String message = createMessage();
IMarker marker = file.createMarker(problem.getMarkerType());
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
marker.setAttribute(ID, problem.getId());
marker.setAttribute(IMarker.CHAR_END, loc.getEndingChar());
marker.setAttribute(IMarker.CHAR_START, loc.getStartingChar());
String propArgs = serializeArgs(args);
marker.setAttribute(PROBLEM_ARGS, propArgs);
IProblemCategory[] cats = CodanProblemCategory.findProblemCategories(getProfile(file).getRoot(), problem.getId());
String cat = cats.length > 0 ? cats[0].getId() : ""; //$NON-NLS-1$
marker.setAttribute(CATEGORY, cat);
return marker;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.codan.core.model.ICodanProblemMarker#createMessage()
*/
public String createMessage() {
String messagePattern = problem.getMessagePattern();
String message = problem.getId();
if (messagePattern == null) {
if (args != null && args.length > 0 && args[0] instanceof String)
message = (String) args[0];
} else {
message = MessageFormat.format(messagePattern, args);
}
return message;
}
/**
* @param args2
* @return
*/
private static String serializeArgs(Object[] args) {
if (args != null) {
Properties prop = new Properties();
prop.put("len", String.valueOf(args.length)); //$NON-NLS-1$
for (int i = 0; i < args.length; i++) {
Object object = args[i];
if (object != null)
prop.put("a" + i, object.toString()); //$NON-NLS-1$
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
prop.store(bout, null);
} catch (IOException e) {
// nope
}
return bout.toString();
}
return ""; //$NON-NLS-1$
}
/**
* Return the argument of a problem that checker passed to "reportProblem"
* method
*
* @param marker - problem marker
* @param index - index of the argument 0 based
* @return problem argument at index, can be null if not set. Can throw AUBE
* if out of bounds.
*/
public static String getProblemArgument(IMarker marker, int index) {
String[] args = getProblemArguments(marker);
return args[index];
}
/**
* Return the arguments of a problem that checker passed to "reportProblem"
* method
*
* @param marker - problem marker
* @return problem arguments, can not be null. Can be 0 sized array.
*/
public static String[] getProblemArguments(IMarker marker) {
String attrs = marker.getAttribute(PROBLEM_ARGS, ""); //$NON-NLS-1$
Properties prop = new Properties();
ByteArrayInputStream bin = new ByteArrayInputStream(attrs.getBytes());
try {
prop.load(bin);
} catch (IOException e) {
// not happening
}
String len = prop.getProperty("len", "0"); //$NON-NLS-1$ //$NON-NLS-2$
int length = Integer.valueOf(len);
String args[] = new String[length];
for (int i = 0; i < length; i++) {
args[i] = prop.getProperty("a" + i); //$NON-NLS-1$
}
return args;
}
/**
* Return problemId from marker
*
* @param marker
* @return codan problemId
*/
public static String getProblemId(IMarker marker) {
try {
return (String) marker.getAttribute(ICodanProblemMarker.ID);
} catch (CoreException e) {
return null;
}
}
/**
* @param marker
* @return problem message
*/
public static String getMessage(IMarker marker) {
return marker.getAttribute(IMarker.MESSAGE, (String) null);
}
/**
* @param marker
* @return codan severity
*/
public static CodanSeverity getSeverity(IMarker marker) {
int sev = marker.getAttribute(IMarker.SEVERITY, 0);
return CodanSeverity.valueOf(sev);
}
/**
* Attempt to restore CodamProblemMaker from the resource marker
*
* @param marker
* @return new instanceof of ICodanProblemMarker or null if marker is not
* codan marker
*/
public static ICodanProblemMarker createCodanProblemMarkerFromResourceMarker(IMarker marker) {
CodanProblem problem = getProblem(marker);
if (problem == null)
return null;
CodanProblemLocation loc = getLocation(marker);
return new CodanProblemMarker(problem, loc, getProblemArguments(marker));
}
/**
* @param marker
* @return
*/
public static CodanProblem getProblem(IMarker marker) {
String id = getProblemId(marker);
if (id == null)
return null;
IResource resource = marker.getResource();
IProblemProfile profile = getProfile(resource);
CodanProblem problem = (CodanProblem) ((CodanProblem) profile.findProblem(id)).clone();
CodanSeverity sev = getSeverity(marker);
problem.setSeverity(sev);
return problem;
}
/**
* @param resource
* @return
*/
public static IProblemProfile getProfile(IResource resource) {
IProblemProfile profile = CheckersRegistry.getInstance().getResourceProfile(resource);
return profile;
}
/**
* @param marker
* @return location object using marker attributes
*/
public static CodanProblemLocation getLocation(IMarker marker) {
int line = marker.getAttribute(IMarker.LINE_NUMBER, -1);
int charend = marker.getAttribute(IMarker.CHAR_END, -1);
int charstart = marker.getAttribute(IMarker.CHAR_START, -1);
CodanProblemLocation loc = new CodanProblemLocation(marker.getResource(), charstart, charend, line);
return loc;
}
/**
* @param marker
* @param res
* @throws CoreException
*/
public static void setProblemArguments(IMarker marker, String[] args) throws CoreException {
String propArgs = serializeArgs(args);
marker.setAttribute(PROBLEM_ARGS, propArgs);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(args);
result = prime * result + ((loc == null) ? 0 : loc.hashCode());
result = prime * result + problem.getId().hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof ICodanProblemMarker))
return false;
CodanProblemMarker other = (CodanProblemMarker) obj;
if (!Arrays.equals(args, other.args))
return false;
if (!loc.equals(other.loc))
return false;
if (!problem.getId().equals(other.problem.getId()))
return false;
return true;
}
}