package hudson.plugins.analysis.views;
import java.util.Collection;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import com.google.common.collect.Maps;
import hudson.model.Item;
import hudson.model.AbstractBuild;
import hudson.plugins.analysis.Messages;
import hudson.plugins.analysis.core.ResultAction;
import hudson.plugins.analysis.core.BuildResult;
import hudson.plugins.analysis.util.model.AnnotationContainer;
import hudson.plugins.analysis.util.model.DefaultAnnotationContainer;
import hudson.plugins.analysis.util.model.FileAnnotation;
import hudson.plugins.analysis.util.model.LineRange;
/**
* Creates detail objects for the selected element of a annotation container.
*
* @author Ulli Hafner
*/
public class DetailFactory {
/** Default detail builder class. */
private static final DetailFactory DEFAULT_DETAIL_BUILDER = new DetailFactory();
/** Maps plug-ins to detail builders. */
private static Map<Class<? extends ResultAction<? extends BuildResult>>, DetailFactory> factories = Maps.newHashMap();
/**
* Creates a new detail builder.
*
* @param actionType
* the type of the action (i.e., the plug-in) to get the detail
* builder for
* @return the detail builder
*/
public static DetailFactory create(final Class<? extends ResultAction<? extends BuildResult>> actionType) {
if (factories.containsKey(actionType)) {
return factories.get(actionType);
}
return DEFAULT_DETAIL_BUILDER;
}
/**
* Sets the detail builder class to the specified value.
*
* @param actionType
* the type of the action (i.e., the plug-in) to set the detail
* builder for
* @param detailBuilder
* the value to set
*/
public static void addDetailBuilder(final Class<? extends ResultAction<? extends BuildResult>> actionType,
final DetailFactory detailBuilder) {
synchronized (factories) {
factories.put(actionType, detailBuilder);
}
}
/**
* Returns a detail object for the selected element of the specified
* annotation container. The details will include the new and fixed warnings
* trends as well as the errors report.
*
* @param link
* the link to identify the sub page to show
* @param owner
* the build as owner of the detail page
* @param container
* the annotation container to get the details for
* @param fixedAnnotations
* the annotations fixed in this build
* @param newAnnotations
* the annotations new in this build
* @param errors
* the errors in this build
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @param displayName
* the name of the selected object
* @return the dynamic result of this module detail view
*/
// CHECKSTYLE:OFF
public Object createTrendDetails(final String link, final AbstractBuild<?, ?> owner,
final AnnotationContainer container, final Collection<FileAnnotation> fixedAnnotations,
final Collection<FileAnnotation> newAnnotations, final Collection<String> errors,
final String defaultEncoding, final String displayName) {
// CHECKSTYLE:ON
if ("fixed".equals(link)) {
return createFixedWarningsDetail(owner, fixedAnnotations, defaultEncoding, displayName);
}
else if ("new".equals(link)) {
return new NewWarningsDetail(owner, this, newAnnotations, defaultEncoding, displayName);
}
else if ("error".equals(link)) {
return new ErrorDetail(owner, errors);
}
else if (link.startsWith("tab.new")) {
return createTabDetail(owner, newAnnotations, createGenericTabUrl(link), defaultEncoding);
}
else if (link.startsWith("tab.fixed")) {
return createTabDetail(owner, fixedAnnotations, createGenericTabUrl(link), defaultEncoding);
}
else {
return createDetails(link, owner, container, defaultEncoding, displayName);
}
}
/**
* Returns a detail object for the selected element of the specified
* annotation container.
*
* @param link
* the link to identify the sub page to show
* @param owner
* the build as owner of the detail page
* @param container
* the annotation container to get the details for
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @param displayName
* the name of the selected object
* @return the dynamic result of this module detail view
*/
public Object createDetails(final String link, final AbstractBuild<?, ?> owner, final AnnotationContainer container,
final String defaultEncoding, final String displayName) {
PriorityDetailFactory factory = new PriorityDetailFactory(this);
if (factory.isPriority(link)) {
return factory.create(link, owner, container, defaultEncoding, displayName);
}
else if (link.startsWith("module.")) {
return new ModuleDetail(owner, this, container.getModule(createHashCode(link, "module.")), defaultEncoding, displayName);
}
else if (link.startsWith("package.")) {
return new PackageDetail(owner, this, container.getPackage(createHashCode(link, "package.")), defaultEncoding, displayName);
}
else if (link.startsWith("file.")) {
return new FileDetail(owner, this, container.getFile(createHashCode(link, "file.")), defaultEncoding, displayName);
}
else if (link.startsWith("tab.")) {
return createTabDetail(owner, container.getAnnotations(), createGenericTabUrl(link), defaultEncoding);
}
else if (link.startsWith("source.")) {
owner.checkPermission(Item.WORKSPACE);
FileAnnotation annotation = container.getAnnotation(StringUtils.substringAfter(link, "source."));
if (annotation.isInConsoleLog()) {
LineRange lines = annotation.getLineRanges().iterator().next();
return new ConsoleDetail(owner, lines.getStart(), lines.getEnd());
}
else {
return new SourceDetail(owner, annotation, defaultEncoding);
}
}
else if (link.startsWith("category.")) {
DefaultAnnotationContainer category = container.getCategory(createHashCode(link, "category."));
return createAttributeDetail(owner, category, displayName, Messages.CategoryDetail_header(), defaultEncoding);
}
else if (link.startsWith("type.")) {
DefaultAnnotationContainer type = container.getType(createHashCode(link, "type."));
return createAttributeDetail(owner, type, displayName, Messages.TypeDetail_header(), defaultEncoding);
}
return null;
}
/**
* Creates a generic detail tab with the specified link.
*
* @param owner
* the build as owner of the detail page
* @param annotations
* the annotations to display
* @param displayName
* the name of the view
* @param header
* the bread crumb name
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @return the detail view
*/
protected AttributeDetail createAttributeDetail(final AbstractBuild<?, ?> owner, final DefaultAnnotationContainer annotations,
final String displayName, final String header, final String defaultEncoding) {
return new AttributeDetail(owner, this, annotations.getAnnotations(), defaultEncoding, displayName, header + " " + annotations.getName());
}
/**
* Creates a generic detail tab with the specified link.
*
* @param owner
* the build as owner of the detail page
* @param annotations
* the annotations to display
* @param url
* the URL for the details view
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @return the detail view
*/
protected TabDetail createTabDetail(final AbstractBuild<?, ?> owner, final Collection<FileAnnotation> annotations,
final String url, final String defaultEncoding) {
return new TabDetail(owner, this, annotations, url, defaultEncoding);
}
/**
* Creates a generic fixed warnings detail tab with the specified link.
*
* @param owner
* the build as owner of the detail page
* @param fixedAnnotations
* the annotations to display
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @param displayName
* the name of the view
* @return the detail view
*/
protected FixedWarningsDetail createFixedWarningsDetail(final AbstractBuild<?, ?> owner,
final Collection<FileAnnotation> fixedAnnotations, final String defaultEncoding,
final String displayName) {
return new FixedWarningsDetail(owner, this, fixedAnnotations, defaultEncoding, displayName);
}
/**
* Creates the actual URL from the synthetic link.
*
* @param link
* the link
* @return the actual URL
*/
private String createGenericTabUrl(final String link) {
return StringUtils.substringAfter(link, "tab.") + ".jelly";
}
/**
* Extracts the hash code from the given link stripping of the given prefix.
*
* @param link the whole link
* @param prefix the prefix to remove
*
* @return the hash code
*/
private int createHashCode(final String link, final String prefix) {
return Integer.parseInt(StringUtils.substringAfter(link, prefix));
}
}