blob: bd95a5b74a153ac91cc06fff583c3741e5c17acc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.bugzilla.core;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.eclipse.mylyn.internal.bugzilla.core.IBugzillaConstants.BUGZILLA_REPORT_STATUS;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskOperation;
/**
* Class describing the configuration of products and components for a given Bugzilla installation.
*
* @author Rob Elves
*/
public class RepositoryConfiguration implements Serializable {
private static final long serialVersionUID = -3600257926613730005L;
private String repositoryUrl = "<unknown>"; //$NON-NLS-1$
private final Map<String, ProductEntry> products = new HashMap<String, ProductEntry>();
private final List<String> platforms = new ArrayList<String>();
private final List<String> operatingSystems = new ArrayList<String>();
private final List<String> priorities = new ArrayList<String>();
private final List<String> severities = new ArrayList<String>();
private final List<String> bugStatus = new ArrayList<String>();
private final List<String> openStatusValues = new ArrayList<String>();
private final List<String> resolutionValues = new ArrayList<String>();
private final List<String> keywords = new ArrayList<String>();
// master lists
private final List<String> versions = new ArrayList<String>();
private final List<String> components = new ArrayList<String>();
private final List<String> milestones = new ArrayList<String>();
private final List<BugzillaCustomField> customFields = new ArrayList<BugzillaCustomField>();
private final List<BugzillaFlag> flags = new ArrayList<BugzillaFlag>();
private BugzillaVersion version = BugzillaVersion.MIN_VERSION;
public RepositoryConfiguration() {
super();
}
public void addStatus(String status) {
bugStatus.add(status);
}
public List<String> getStatusValues() {
return bugStatus;
}
public void addResolution(String res) {
resolutionValues.add(res);
}
public List<String> getResolutions() {
return resolutionValues;
}
/**
* Adds a product to the configuration.
*/
public void addProduct(String name) {
if (!products.containsKey(name)) {
ProductEntry product = new ProductEntry(name);
products.put(name, product);
}
}
/**
* Returns an array of names of current products.
*/
public List<String> getProducts() {
ArrayList<String> productList = new ArrayList<String>(products.keySet());
Collections.sort(productList);
return productList;
}
/**
* Returns an array of names of component that exist for a given product or <code>null</code> if the product does
* not exist.
*/
public List<String> getComponents(String product) {
ProductEntry entry = products.get(product);
if (entry != null) {
return entry.getComponents();
} else {
return Collections.emptyList();
}
}
/**
* Returns an array of names of versions that exist for a given product or <code>null</code> if the product does not
* exist.
*/
public List<String> getVersions(String product) {
ProductEntry entry = products.get(product);
if (entry != null) {
return entry.getVersions();
} else {
return Collections.emptyList();
}
}
/**
* Returns an array of names of valid severity values.
*/
public List<String> getSeverities() {
return severities;
}
/**
* Returns an array of names of valid OS values.
*/
public List<String> getOSs() {
return operatingSystems;
}
public void addOS(String os) {
operatingSystems.add(os);
}
/**
* Returns an array of names of valid platform values.
*/
public List<String> getPlatforms() {
return platforms;
}
/**
* Returns an array of names of valid platform values.
*/
public List<String> getPriorities() {
return priorities;
}
/**
* Adds a component to the given product.
*/
public void addComponent(String product, String component) {
if (!components.contains(component)) {
components.add(component);
}
ProductEntry entry = products.get(product);
if (entry == null) {
entry = new ProductEntry(product);
products.put(product, entry);
}
entry.addComponent(component);
}
public void addVersion(String product, String version) {
if (!versions.contains(version)) {
versions.add(version);
}
ProductEntry entry = products.get(product);
if (entry == null) {
entry = new ProductEntry(product);
products.put(product, entry);
}
entry.addVersion(version);
}
public void addKeyword(String keyword) {
keywords.add(keyword);
}
public List<String> getKeywords() {
return keywords;
}
public void addPlatform(String platform) {
platforms.add(platform);
}
public void addPriority(String priority) {
priorities.add(priority);
}
public void addSeverity(String severity) {
severities.add(severity);
}
public void setInstallVersion(String version) {
this.version = new BugzillaVersion(version);
}
public BugzillaVersion getInstallVersion() {
return version;
}
public void addTargetMilestone(String product, String target) {
if (!milestones.contains(target)) {
milestones.add(target);
}
ProductEntry entry = products.get(product);
if (entry == null) {
entry = new ProductEntry(product);
products.put(product, entry);
}
entry.addTargetMilestone(target);
}
public List<String> getTargetMilestones(String product) {
ProductEntry entry = products.get(product);
if (entry != null) {
return entry.getTargetMilestones();
} else {
return Collections.emptyList();
}
}
/**
* Container for product information: name, components.
*/
private static class ProductEntry implements Serializable {
private static final long serialVersionUID = 4120139521246741120L;
String productName;
List<String> components = new ArrayList<String>();
List<String> versions = new ArrayList<String>();
List<String> milestones = new ArrayList<String>();
ProductEntry(String name) {
this.productName = name;
}
List<String> getComponents() {
return components;
}
void addComponent(String componentName) {
if (!components.contains(componentName)) {
components.add(componentName);
}
}
List<String> getVersions() {
return versions;
}
void addVersion(String name) {
if (!versions.contains(name)) {
versions.add(name);
}
}
List<String> getTargetMilestones() {
return milestones;
}
void addTargetMilestone(String target) {
milestones.add(target);
}
}
public List<String> getOpenStatusValues() {
return openStatusValues;
}
public void addOpenStatusValue(String value) {
openStatusValues.add(value);
}
public List<String> getComponents() {
return components;
}
public List<String> getTargetMilestones() {
return milestones;
}
public List<String> getVersions() {
return versions;
}
public String getRepositoryUrl() {
return repositoryUrl;
}
public void setRepositoryUrl(String repositoryUrl) {
this.repositoryUrl = repositoryUrl;
}
/*
* Intermediate step until configuration is made generic.
*/
public List<String> getOptionValues(BugzillaAttribute element, String product) {
switch (element) {
case PRODUCT:
return getProducts();
case TARGET_MILESTONE:
return getTargetMilestones(product);
case BUG_STATUS:
return getStatusValues();
case VERSION:
return getVersions(product);
case COMPONENT:
return getComponents(product);
case REP_PLATFORM:
return getPlatforms();
case OP_SYS:
return getOSs();
case PRIORITY:
return getPriorities();
case BUG_SEVERITY:
return getSeverities();
case KEYWORDS:
return getKeywords();
case RESOLUTION:
return getResolutions();
default:
return Collections.emptyList();
}
}
/**
* Adds a field to the configuration.
*/
public void addCustomField(BugzillaCustomField newField) {
customFields.add(newField);
}
public List<BugzillaCustomField> getCustomFields() {
return customFields;
}
public void configureTaskData(TaskData taskData) {
if (taskData != null) {
addMissingFlags(taskData);
updateAttributeOptions(taskData);
addValidOperations(taskData);
}
}
private void addMissingFlags(TaskData taskData) {
List<String> existingFlags = new ArrayList<String>();
List<BugzillaFlag> flags = getFlags();
for (TaskAttribute attribute : new HashSet<TaskAttribute>(taskData.getRoot().getAttributes().values())) {
if (attribute.getId().startsWith("task.common.kind.flag")) { //$NON-NLS-1$
TaskAttribute state = attribute.getAttribute("state"); //$NON-NLS-1$
if (state != null) {
String nameValue = state.getMetaData().getLabel();
if (!existingFlags.contains(nameValue)) {
existingFlags.add(nameValue);
}
String desc = attribute.getMetaData().getLabel();
if (desc == null || desc.equals("")) { //$NON-NLS-1$
for (BugzillaFlag bugzillaFlag : flags) {
if (bugzillaFlag.getType().equals("attachment")) { //$NON-NLS-1$
continue;
}
if (bugzillaFlag.getName().equals(nameValue)) {
attribute.getMetaData().setLabel(bugzillaFlag.getDescription());
}
}
}
}
}
}
TaskAttribute productAttribute = taskData.getRoot().getMappedAttribute(BugzillaAttribute.PRODUCT.getKey());
TaskAttribute componentAttribute = taskData.getRoot().getMappedAttribute(BugzillaAttribute.COMPONENT.getKey());
for (BugzillaFlag bugzillaFlag : flags) {
if (bugzillaFlag.getType().equals("attachment")) { //$NON-NLS-1$
continue;
}
if (!bugzillaFlag.isUsedIn(productAttribute.getValue(), componentAttribute.getValue())) {
continue;
}
if (existingFlags.contains(bugzillaFlag.getName()) && !bugzillaFlag.isMultiplicable()) {
continue;
}
BugzillaFlagMapper mapper = new BugzillaFlagMapper();
mapper.setRequestee(""); //$NON-NLS-1$
mapper.setSetter(""); //$NON-NLS-1$
mapper.setState(" "); //$NON-NLS-1$
mapper.setFlagId(bugzillaFlag.getName());
mapper.setNumber(0);
mapper.setDescription(bugzillaFlag.getDescription());
TaskAttribute attribute = taskData.getRoot().createAttribute(
"task.common.kind.flag_type" + bugzillaFlag.getFlagId()); //$NON-NLS-1$
mapper.applyTo(attribute);
}
setFlagsRequestee(taskData);
}
private void setFlagsRequestee(TaskData taskData) {
for (TaskAttribute attribute : new HashSet<TaskAttribute>(taskData.getRoot().getAttributes().values())) {
if (attribute.getId().startsWith("task.common.kind.flag")) { //$NON-NLS-1$
TaskAttribute state = attribute.getAttribute("state"); //$NON-NLS-1$
if (state != null) {
String nameValue = state.getMetaData().getLabel();
for (BugzillaFlag bugzillaFlag : flags) {
if (nameValue.equals(bugzillaFlag.getName())) {
TaskAttribute requestee = attribute.getAttribute("requestee"); //$NON-NLS-1$
if (requestee == null) {
requestee = attribute.createMappedAttribute("requestee"); //$NON-NLS-1$
requestee.getMetaData().defaults().setType(TaskAttribute.TYPE_SHORT_TEXT);
requestee.setValue(""); //$NON-NLS-1$
}
requestee.getMetaData().setReadOnly(!bugzillaFlag.isSpecifically_requestable());
}
}
}
}
}
}
public void updateAttributeOptions(TaskData existingReport) {
TaskAttribute attributeProduct = existingReport.getRoot()
.getMappedAttribute(BugzillaAttribute.PRODUCT.getKey());
if (attributeProduct == null) {
return;
}
String product = attributeProduct.getValue();
for (TaskAttribute attribute : new HashSet<TaskAttribute>(existingReport.getRoot().getAttributes().values())) {
List<String> optionValues = getAttributeOptions(product, attribute);
if (attribute.getId().equals(BugzillaAttribute.TARGET_MILESTONE.getKey()) && optionValues.isEmpty()) {
existingReport.getRoot().removeAttribute(BugzillaAttribute.TARGET_MILESTONE.getKey());
continue;
}
if (attribute.getId().startsWith("task.common.kind.flag")) { //$NON-NLS-1$
attribute = attribute.getAttribute("state"); //$NON-NLS-1$
}
attribute.clearOptions();
for (String option : optionValues) {
attribute.putOption(option, option);
}
}
}
public List<String> getAttributeOptions(String product, TaskAttribute attribute) {
List<String> options = new ArrayList<String>();
if (attribute.getId().startsWith(BugzillaCustomField.CUSTOM_FIELD_PREFIX)) {
for (BugzillaCustomField bugzillaCustomField : customFields) {
if (bugzillaCustomField.getName().equals(attribute.getId())) {
options = bugzillaCustomField.getOptions();
break;
}
}
} else if (attribute.getId().startsWith("task.common.kind.flag")) { //$NON-NLS-1$
TaskAttribute state = attribute.getAttribute("state"); //$NON-NLS-1$
if (state != null) {
String nameValue = state.getMetaData().getLabel();
options.add(""); //$NON-NLS-1$
for (BugzillaFlag bugzillaFlag : flags) {
if (nameValue.equals(bugzillaFlag.getName())) {
if (nameValue.equals(bugzillaFlag.getName())) {
if (bugzillaFlag.isRequestable()) {
options.add("?"); //$NON-NLS-1$
}
break;
}
}
}
options.add("+"); //$NON-NLS-1$
options.add("-"); //$NON-NLS-1$
}
}
else {
String type = attribute.getMetaData().getType();
if (type != null && type.equals(IBugzillaConstants.EDITOR_TYPE_FLAG)) {
options.add(""); //$NON-NLS-1$
options.add("?"); //$NON-NLS-1$
options.add("+"); //$NON-NLS-1$
options.add("-"); //$NON-NLS-1$
} else {
BugzillaAttribute element;
try {
element = BugzillaAttribute.valueOf(attribute.getId().trim().toUpperCase(Locale.ENGLISH));
} catch (RuntimeException e) {
if (e instanceof IllegalArgumentException) {
// ignore unrecognized tags
return options;
}
throw e;
}
options = getOptionValues(element, product);
if (element != BugzillaAttribute.RESOLUTION && element != BugzillaAttribute.OP_SYS
&& element != BugzillaAttribute.BUG_SEVERITY && element != BugzillaAttribute.PRIORITY
&& element != BugzillaAttribute.BUG_STATUS) {
Collections.sort(options);
}
}
}
return options;
}
public void addValidOperations(TaskData bugReport) {
TaskAttribute attributeStatus = bugReport.getRoot().getMappedAttribute(TaskAttribute.STATUS);
BUGZILLA_REPORT_STATUS status = BUGZILLA_REPORT_STATUS.NEW;
if (attributeStatus != null) {
try {
status = BUGZILLA_REPORT_STATUS.valueOf(attributeStatus.getValue());
} catch (RuntimeException e) {
// StatusHandler.log(new Status(IStatus.INFO, BugzillaCorePlugin.PLUGIN_ID, "Unrecognized status: "
// + attributeStatus.getValue(), e));
status = BUGZILLA_REPORT_STATUS.NEW;
}
}
switch (status) {
case UNCONFIRMED:
case REOPENED:
case NEW:
addOperation(bugReport, BugzillaOperation.none);
addOperation(bugReport, BugzillaOperation.accept);
addOperation(bugReport, BugzillaOperation.resolve);
addOperation(bugReport, BugzillaOperation.duplicate);
break;
case ASSIGNED:
addOperation(bugReport, BugzillaOperation.none);
addOperation(bugReport, BugzillaOperation.resolve);
addOperation(bugReport, BugzillaOperation.duplicate);
break;
case RESOLVED:
addOperation(bugReport, BugzillaOperation.none);
addOperation(bugReport, BugzillaOperation.reopen);
addOperation(bugReport, BugzillaOperation.verify);
addOperation(bugReport, BugzillaOperation.close);
break;
case CLOSED:
addOperation(bugReport, BugzillaOperation.none);
addOperation(bugReport, BugzillaOperation.reopen);
break;
case VERIFIED:
addOperation(bugReport, BugzillaOperation.none);
addOperation(bugReport, BugzillaOperation.reopen);
addOperation(bugReport, BugzillaOperation.close);
}
BugzillaVersion bugzillaVersion = getInstallVersion();
if (bugzillaVersion == null) {
bugzillaVersion = BugzillaVersion.MIN_VERSION;
}
if (bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_0) < 0) {
// Product change is only supported for Versions >= 3.0 without verify html page
TaskAttribute productAttribute = bugReport.getRoot().getMappedAttribute(BugzillaAttribute.PRODUCT.getKey());
productAttribute.getMetaData().setReadOnly(true);
}
if (status == BUGZILLA_REPORT_STATUS.NEW || status == BUGZILLA_REPORT_STATUS.ASSIGNED
|| status == BUGZILLA_REPORT_STATUS.REOPENED || status == BUGZILLA_REPORT_STATUS.UNCONFIRMED) {
if (bugzillaVersion.compareMajorMinorOnly(BugzillaVersion.BUGZILLA_3_0) <= 0) {
// old bugzilla workflow is used
addOperation(bugReport, BugzillaOperation.reassign);
addOperation(bugReport, BugzillaOperation.reassignbycomponent);
} else {
BugzillaAttribute key = BugzillaAttribute.SET_DEFAULT_ASSIGNEE;
TaskAttribute operationAttribute = bugReport.getRoot().getAttribute(key.getKey());
if (operationAttribute == null) {
operationAttribute = bugReport.getRoot().createAttribute(key.getKey());
operationAttribute.getMetaData()
.defaults()
.setReadOnly(key.isReadOnly())
.setKind(key.getKind())
.setLabel(key.toString())
.setType(key.getType());
operationAttribute.setValue("0"); //$NON-NLS-1$
}
operationAttribute = bugReport.getRoot().getMappedAttribute(TaskAttribute.USER_ASSIGNED);
if (operationAttribute != null) {
operationAttribute.getMetaData().setReadOnly(false);
}
}
}
}
public void addOperation(TaskData bugReport, BugzillaOperation opcode) {
TaskAttribute attribute;
TaskAttribute operationAttribute = bugReport.getRoot().getAttribute(TaskAttribute.OPERATION);
if (operationAttribute == null) {
operationAttribute = bugReport.getRoot().createAttribute(TaskAttribute.OPERATION);
}
switch (opcode) {
case none:
attribute = bugReport.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + opcode.toString());
String label = "Leave"; //$NON-NLS-1$
TaskAttribute attributeStatus = bugReport.getRoot().getMappedAttribute(TaskAttribute.STATUS);
TaskAttribute attributeResolution = bugReport.getRoot().getMappedAttribute(TaskAttribute.RESOLUTION);
if (attributeStatus != null && attributeResolution != null) {
label = String.format(opcode.getLabel(), attributeStatus.getValue(), attributeResolution.getValue());
}
TaskOperation.applyTo(attribute, opcode.toString(), label);
// set as default
TaskOperation.applyTo(operationAttribute, opcode.toString(), label);
break;
case resolve:
attribute = bugReport.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + opcode.toString());
TaskOperation.applyTo(attribute, opcode.toString(), opcode.getLabel());
TaskAttribute attrResolvedInput = attribute.getTaskData().getRoot().createAttribute(opcode.getInputId());
attrResolvedInput.getMetaData().setType(opcode.getInputType());
attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, opcode.getInputId());
for (String resolution : getResolutions()) {
// DUPLICATE and MOVED have special meanings so do not show as resolution
if (resolution.compareTo("DUPLICATE") != 0 && resolution.compareTo("MOVED") != 0) { //$NON-NLS-1$ //$NON-NLS-2$
attrResolvedInput.putOption(resolution, resolution);
}
}
if (getResolutions().size() > 0) {
attrResolvedInput.setValue(getResolutions().get(0));
}
break;
default:
attribute = bugReport.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + opcode.toString());
TaskOperation.applyTo(attribute, opcode.toString(), opcode.getLabel());
if (opcode.getInputId() != null) {
TaskAttribute attrInput = bugReport.getRoot().createAttribute(opcode.getInputId());
attrInput.getMetaData().defaults().setReadOnly(false).setType(opcode.getInputType());
attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, opcode.getInputId());
}
break;
}
}
/**
* Adds a flag to the configuration.
*/
public void addFlag(BugzillaFlag newFlag) {
flags.add(newFlag);
}
public List<BugzillaFlag> getFlags() {
return flags;
}
public BugzillaFlag getFlagWithId(Integer id) {
for (BugzillaFlag bugzillaFlag : flags) {
if (bugzillaFlag.getFlagId() == id) {
return bugzillaFlag;
}
}
return null;
}
}