/*******************************************************************************
* Copyright (c) 2008 - 2008 Standards for Technology in Automotive Retail
* 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:
* David Carver - STAR - adapted from Bugzilla mylyn 3.0 implementation.
* Robert Munteanu - various fixes and improvements
*******************************************************************************/
package com.itsolut.mantis.core;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.mylyn.tasks.core.*;
import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
import org.eclipse.mylyn.tasks.core.data.*;
import org.eclipse.osgi.util.NLS;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.itsolut.mantis.core.MantisAttributeMapper.Attribute;
import com.itsolut.mantis.core.MantisCommentMapper.CommentMapping;
import com.itsolut.mantis.core.exception.MantisException;
import com.itsolut.mantis.core.exception.TicketNotFoundException;
import com.itsolut.mantis.core.model.*;
import com.itsolut.mantis.core.model.MantisRelationship.RelationType;
import com.itsolut.mantis.core.model.MantisTicket.Key;
import com.itsolut.mantis.core.util.MantisUtils;
/**
* @author Dave Carver
*/
@Singleton
public class MantisTaskDataHandler extends AbstractTaskDataHandler {
private final IMantisClientManager clientManager;
private final StatusFactory statusFactory;
private final MantisCommentMapper commentMapper;
private final MantisTaskDataMigrator migrator = new MantisTaskDataMigrator();
private final Tracer tracer;
private static final String CONTEXT_ATTACHMENT_FILENAME = "mylyn-context.zip";
private static final String CONTEXT_ATTACHMENT_DESCRIPTION = "mylyn/context/zip";
private static final String CONTEXT_ATTACHMENT_DESCRIPTION_LEGACY = "mylar/context/zip";
private static final String CONTEXT_ATTACHMENT_FILENAME_LEGACY = "mylar-context.zip";
private static final Map<Attribute, RelationType> attributeToRelationType = new EnumMap<Attribute, RelationType>(Attribute.class);
{
attributeToRelationType.put(Attribute.RELATED_TO, RelationType.RELATED);
attributeToRelationType.put(Attribute.DUPLICATE_OF, RelationType.DUPLICATE);
attributeToRelationType.put(Attribute.HAS_DUPLICATE, RelationType.HAS_DUPLICATE);
attributeToRelationType.put(Attribute.PARENT_OF, RelationType.PARENT);
attributeToRelationType.put(Attribute.CHILD_OF, RelationType.CHILD);
}
private static final Map<RelationType, Attribute> relationTypeToAttribute = new EnumMap<RelationType, Attribute>(RelationType.class);
{
for ( Map.Entry<Attribute, RelationType> entry : attributeToRelationType.entrySet() )
relationTypeToAttribute.put(entry.getValue(), entry.getKey());
}
private final static Map<MantisCustomFieldType, String> customFieldTypeToTaskType = new EnumMap<MantisCustomFieldType, String>(MantisCustomFieldType.class);
{
customFieldTypeToTaskType.put(MantisCustomFieldType.CHECKBOX, TaskAttribute.TYPE_MULTI_SELECT);
customFieldTypeToTaskType.put(MantisCustomFieldType.DATE, TaskAttribute.TYPE_DATE);
customFieldTypeToTaskType.put(MantisCustomFieldType.EMAIL, TaskAttribute.TYPE_SHORT_TEXT);
customFieldTypeToTaskType.put(MantisCustomFieldType.ENUM, TaskAttribute.TYPE_SINGLE_SELECT);
customFieldTypeToTaskType.put(MantisCustomFieldType.FLOAT, TaskAttribute.TYPE_SHORT_TEXT);
customFieldTypeToTaskType.put(MantisCustomFieldType.LIST , TaskAttribute.TYPE_SINGLE_SELECT);
customFieldTypeToTaskType.put(MantisCustomFieldType.MULTILIST, TaskAttribute.TYPE_MULTI_SELECT);
customFieldTypeToTaskType.put(MantisCustomFieldType.NUMERIC, TaskAttribute.TYPE_SHORT_TEXT);
customFieldTypeToTaskType.put(MantisCustomFieldType.RADIO, TaskAttribute.TYPE_SINGLE_SELECT);
customFieldTypeToTaskType.put(MantisCustomFieldType.STRING, TaskAttribute.TYPE_SHORT_TEXT);
customFieldTypeToTaskType.put(MantisCustomFieldType.TEXTAREA, TaskAttribute.TYPE_LONG_TEXT);
}
@Inject
public MantisTaskDataHandler(IMantisClientManager clientManager, StatusFactory statusFactory, MantisCommentMapper commentMapper, Tracer tracer) {
this.clientManager = clientManager;
this.statusFactory = statusFactory;
this.commentMapper = commentMapper;
this.tracer = tracer;
}
@Override
public TaskAttributeMapper getAttributeMapper(TaskRepository taskRepository) {
return new MantisAttributeMapper(taskRepository);
}
@Override
public boolean initializeTaskData(TaskRepository repository, TaskData data,
ITaskMapping initializationData, IProgressMonitor monitor)
throws CoreException {
try {
IMantisClient client = clientManager.getRepository(repository);
// project name
TaskAttribute projectAttribute = getAttribute(data, MantisAttributeMapper.Attribute.PROJECT.getKey());
projectAttribute.setValue(initializationData.getProduct());
createDefaultAttributes(data, client, initializationData.getProduct(), monitor, false);
createProjectSpecificAttributes(data, client, monitor);
CustomFieldValueSource customFieldValueSource;
if ( initializationData instanceof MantisTaskMapper)
customFieldValueSource = new TaskDataCustomFieldValueSource(initializationData.getTaskData());
else
customFieldValueSource = new DefaultCustomFieldValueSource();
createCustomFieldAttributes(data, client, customFieldValueSource, monitor);
return true;
} catch (MantisException e) {
throw new CoreException(statusFactory.toStatus(null, e, repository));
}
}
@Override
public RepositoryResponse postTaskData(TaskRepository repository,
TaskData taskData, Set<TaskAttribute> oldAttributes,
IProgressMonitor monitor) throws CoreException {
// https://sourceforge.net/apps/mantisbt/mylyn-mantis/view.php?id=253
boolean receivedOldAttributes = oldAttributes != null;
try {
IMantisClient client = clientManager.getRepository( repository);
processOperation(taskData, client, monitor);
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=337251
if ( taskData.isNew() )
oldAttributes = Collections.emptySet();
TaskRelationshipChangeFinder changeFinder = new TaskRelationshipChangeFinder(this);
List<TaskRelationshipChange> changes = changeFinder.findChanges(taskData, oldAttributes);
MantisTicket ticket = getMantisTicket(taskData);
if (taskData.isNew()) {
int id = client.createTicket(ticket, monitor, changes);
return new RepositoryResponse(ResponseKind.TASK_UPDATED, String.valueOf(id) );
} else {
MantisTicketComment note = extractTicketComment(repository, taskData);
boolean submitTaskChanges = false;
for ( TaskAttribute attribute : oldAttributes ) {
if ( !attribute.getId().equals(MantisAttributeMapper.Attribute.NEW_COMMENT.getKey()) ) {
submitTaskChanges = true;
break;
}
}
if ( submitTaskChanges || !receivedOldAttributes )
client.updateTicket(ticket, note, changes, monitor);
else if ( note.hasContent() )
client.addIssueComment(ticket.getId(), note, monitor);
else
throw new CoreException(new Status(IStatus.WARNING, MantisCorePlugin.PLUGIN_ID, "No changes were found. Please add a comment or change at least one of the fields."));
return new RepositoryResponse(ResponseKind.TASK_UPDATED, String.valueOf(ticket.getId()) );
}
} catch (MantisException e) {
throw new CoreException(statusFactory.toStatus(null, e, repository));
}
}
private MantisTicketComment extractTicketComment(TaskRepository repository, TaskData taskData) throws CoreException {
String newComment = "";
TaskAttribute newCommentAttribute = taskData.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW);
if (newCommentAttribute != null)
newComment = newCommentAttribute.getValue();
TaskAttribute timeTrackingAttribute = taskData.getRoot().getAttribute(MantisAttributeMapper.Attribute.TIME_SPENT_NEW.getKey());
int timeTracking = 0;
if( timeTrackingAttribute != null && timeTrackingAttribute.getValue() != null && timeTrackingAttribute.getValue().length() != 0 ) {
try {
timeTracking = Integer.parseInt(timeTrackingAttribute.getValue());
} catch ( NumberFormatException e) {
throw new CoreException(statusFactory.toStatus("Invalid time tracking value " + timeTrackingAttribute.getValue() + " must be an integer.", new MantisException(e), repository));
}
}
return new MantisTicketComment(newComment, timeTracking);
}
/**
* Apply the effects of the operation (if any) to an existing task data
*
* @param taskData
* @param client
* @param monitor
*/
private void processOperation(TaskData taskData, IMantisClient client, IProgressMonitor monitor) {
TaskAttribute attributeOperation = taskData.getRoot().getMappedAttribute(TaskAttribute.OPERATION);
if ( attributeOperation == null || "".equals(attributeOperation.getValue()))
return; // i.e. no operation
MantisOperation type = MantisOperation.valueOf(attributeOperation.getValue());
type.performPostOperation(taskData, attributeOperation, client, monitor);
}
private MantisTicket getMantisTicket(TaskData data) throws MantisException {
MantisTicket ticket;
if (data.getTaskId() == null || data.getTaskId().length() == 0)
ticket = new MantisTicket();
else
ticket = new MantisTicket(Integer.parseInt(data.getTaskId()));
Collection<TaskAttribute> attributes = data.getRoot().getAttributes().values();
for (TaskAttribute attribute : attributes) {
if ( attribute.getId().equals("project")) {
ticket.putValue(attribute.getId(), attribute.getValue());
continue;
}
if ( attribute.getId().equals(Key.MONITORS.toString())) {
List<String> monitorsToRemove = new ArrayList<String>(attribute.getValues());
List<String> originalMonitors = MantisUtils.fromCsvString(attribute.getMetaData().getValue(MantisAttributeMapper.TASK_ATTRIBUTE_ORIGINAL_MONITORS));
tracer.trace(TraceLocation.MAIN, "Original monitors : {0}, to remove: {1}", originalMonitors, monitorsToRemove );
originalMonitors.removeAll(monitorsToRemove);
ticket.putValue(attribute.getId(), MantisUtils.toCsvString(originalMonitors));
continue;
}
if( attribute.getId().equals(Key.TAGS.getKey()) ) {
List<String> tagIds = attribute.getValues();
List<MantisTag> tags = Lists.newArrayList();
for ( String tagId : tagIds )
tags.add(new MantisTag(attribute.getOption(tagId), Integer.parseInt(tagId)));
ticket.setTags(tags);
}
if (attribute.getId().equals(TaskAttribute.OPERATION) || attribute.getId().equals(TaskAttribute.TASK_KEY) ||
attribute.getMetaData().isReadOnly() || MantisOperation.isOperationRelated(attribute))
continue;
ticket.putValue(attribute.getId(), attribute.getValue());
}
return ticket;
}
public TaskData getTaskData(TaskRepository repository, String taskId,
IProgressMonitor monitor) throws CoreException {
int id = Integer.parseInt(taskId);
try {
IMantisClient client = clientManager.getRepository(repository);
MantisTicket ticket = client.getTicket(id, monitor);
return createTaskDataFromTicket(client, repository, ticket, monitor);
} catch ( TicketNotFoundException e) {
throw new CoreException(statusFactory.toStatus(e.getMessage(), e, repository));
} catch (MantisException e) {
throw new CoreException(statusFactory.toStatus("Ticket download from "
+ repository.getRepositoryUrl() + " for task " + id + " failed : " + e.getMessage() + " .", e, repository));
}
}
private void updateTaskData(TaskRepository repository,
TaskData data, IMantisClient client,
MantisTicket ticket, IProgressMonitor monitor) throws CoreException, MantisException {
if (ticket.getCreated() != null)
data.getRoot().getAttribute(
MantisAttributeMapper.Attribute.DATE_SUBMITTED.getKey())
.setValue(
MantisUtils.toMantisTime(ticket.getCreated()) + "");
Date lastChanged = ticket.getLastChanged();
copyValuesFromTicket(data, ticket);
addTags(data, ticket);
addComments(data, ticket, client, monitor);
addAttachments(repository, data, ticket, client, monitor);
addRelationships(data, ticket);
addMonitors(data, ticket, client, repository, monitor);
addOperation(data, MantisOperation.LEAVE, client, monitor);
if ( client.isTimeTrackingEnabled(monitor))
addOperation(data, MantisOperation.TRACK_TIME, client, monitor);
addOperation(data, MantisOperation.RESOLVE_AS, client, monitor);
addOperation(data, MantisOperation.ASSIGN_TO, client, monitor);
if (lastChanged != null)
data.getRoot().getAttribute(
MantisAttributeMapper.Attribute.LAST_UPDATED.getKey())
.setValue(MantisUtils.toMantisTime(lastChanged) + "");
}
private void copyValuesFromTicket(TaskData data, MantisTicket ticket) {
boolean warningLogged = false;
Map<String, String> valueByKey = ticket.getValues();
for (String key : valueByKey.keySet()) {
String value = valueByKey.get(key);
if (value == null)
value = "";
TaskAttribute attribute = getAttribute(data, key);
boolean isPersonAttribute = TaskAttribute.TYPE_PERSON.equals(attribute.getMetaData().getType());
// no options, just copy the value
if ( attribute.getOptions().isEmpty() || isPersonAttribute) {
attribute.setValue(value);
} else {
// map string to ids
String keyFromOption = null;
for ( Map.Entry<String, String> optionEntry : attribute.getOptions().entrySet() ) {
if ( optionEntry.getValue().equals(value) ) {
keyFromOption = optionEntry.getKey();
attribute.setValue(keyFromOption);
break;
}
}
if ( keyFromOption == null && !warningLogged ) {
MantisCorePlugin.warn(NLS.bind("Task {0} : Unable to find match for {1} value {2} in repository-supplied options {3}. Further similar warnings will be suppressed for this task, but errors may occur when submitting.", new Object[] { ticket.getId(), key, value, attribute.getOptions() } ));
warningLogged = true;
}
}
}
}
private void addTags(TaskData data, MantisTicket ticket) throws MantisException {
List<MantisTag> tags = ticket.getTags();
if ( tags == null )
return;
List<String> values = Lists.newArrayList();
for ( MantisTag tag : tags )
values.add(String.valueOf(tag.getValue()));
data.getRoot().getAttribute(Attribute.TAGS.getKey()).setValues(values);
}
private void addOperation(TaskData data, MantisOperation operation, IMantisClient client, IProgressMonitor monitor) {
TaskAttribute operationAttribute = data.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + operation.toString());
String label;
if ( operation == MantisOperation.LEAVE) {
TaskAttribute statusAttribute = data.getRoot().getAttribute(MantisAttributeMapper.Attribute.STATUS.getKey());
label = operation.getLabel() + " " + statusAttribute.getOption(statusAttribute.getValue());
} else {
label = operation.getLabel();
}
TaskOperation.applyTo(operationAttribute, operation.toString(), label);
operation.preOperation(data, operationAttribute, client, monitor);
}
private void addRelationships(TaskData data, MantisTicket ticket) {
// relationships - support only child issues
MantisRelationship[] relationsShips = ticket.getRelationships();
for (MantisRelationship mantisRelationship : relationsShips) {
Attribute attribute = null;
switch (mantisRelationship.getType()) {
case PARENT:
attribute = Attribute.PARENT_OF;
break;
case CHILD:
attribute = Attribute.CHILD_OF;
break;
case DUPLICATE:
attribute = Attribute.DUPLICATE_OF;
break;
case HAS_DUPLICATE:
attribute = Attribute.HAS_DUPLICATE;
break;
case RELATED:
attribute = Attribute.RELATED_TO;
break;
case UNKNOWN:
default:
break;
}
if (attribute == null)
continue;
int targetId = mantisRelationship.getTargetId();
TaskAttribute taskAttribute = data.getRoot().getAttribute(attribute.getKey());
String storedRelationshipIds;
if ( taskAttribute == null)
taskAttribute = data.getRoot().createAttribute(attribute.getKey());
if ( MantisUtils.isEmpty(taskAttribute.getValue()) )
taskAttribute.getMetaData().putValue(MantisAttributeMapper.TASK_ATTRIBUTE_RELATIONSHIP_IDS, "");
storedRelationshipIds = taskAttribute.getMetaData().getValue(MantisAttributeMapper.TASK_ATTRIBUTE_RELATIONSHIP_IDS);
if ( MantisUtils.isEmpty(storedRelationshipIds) )
storedRelationshipIds = String.valueOf(mantisRelationship.getId());
else
storedRelationshipIds += "," + mantisRelationship.getId();
taskAttribute.getMetaData().putValue(MantisAttributeMapper.TASK_ATTRIBUTE_RELATIONSHIP_IDS, storedRelationshipIds);
taskAttribute.addValue(String.valueOf(targetId));
}
}
private void addMonitors(TaskData data, MantisTicket ticket, IMantisClient client, TaskRepository repository, IProgressMonitor monitor) throws MantisException {
if ( ticket.getMonitors() == null )
return;
createAttribute(data, MantisAttributeMapper.Attribute.ADD_SELF_TO_MONITORS);
if ( ticket.getMonitors().length == 0 )
return;
TaskAttribute attribute = createAttribute(data, Attribute.MONITORS);
List<String> originalValues = new ArrayList<String>();
for ( MantisUser issueMonitor: ticket.getMonitors() ) {
IRepositoryPerson person = newPerson(repository, issueMonitor.getKey() , client, monitor);
attribute.putOption(person.getPersonId(), person.toString());
originalValues.add(person.getPersonId());
}
attribute.getMetaData().putValue(MantisAttributeMapper.TASK_ATTRIBUTE_ORIGINAL_MONITORS, MantisUtils.toCsvString(originalValues));
}
private void addAttachments(TaskRepository repository, TaskData data, MantisTicket ticket, IMantisClient client, IProgressMonitor monitor) throws MantisException {
int i = 1;
if (ticket.getAttachments() == null)
return;
for (MantisAttachment attachment : ticket.getAttachments()) {
TaskAttribute attribute = data.getRoot().createAttribute(
TaskAttribute.PREFIX_ATTACHMENT + i);
TaskAttachmentMapper taskAttachment = TaskAttachmentMapper
.createFrom(attribute);
taskAttachment.setFileName(attachment.getFilename());
if (CONTEXT_ATTACHMENT_FILENAME.equals(attachment.getFilename()))
taskAttachment.setDescription(CONTEXT_ATTACHMENT_DESCRIPTION);
else if (CONTEXT_ATTACHMENT_FILENAME_LEGACY.equals(attachment
.getFilename()))
taskAttachment
.setDescription(CONTEXT_ATTACHMENT_DESCRIPTION_LEGACY);
else
taskAttachment.setDescription(attachment.getFilename());
taskAttachment.setLength(Long.parseLong(Integer.toString(attachment
.getSize())));
taskAttachment.setCreationDate(attachment.getCreated());
taskAttachment.setUrl(MantisRepositoryLocations.create(repository
.getRepositoryUrl()).getAttachmentDownloadLocation(attachment.getId()));
taskAttachment
.setAttachmentId(Integer.toString(attachment.getId()));
taskAttachment.setAuthor(newPerson(repository, attachment.getUserId(), client, monitor));
taskAttachment.applyTo(attribute);
i++;
}
}
private IRepositoryPerson newPerson(TaskRepository repository, int userId, IMantisClient client, IProgressMonitor monitor) throws MantisException {
String userName = client.getCache(monitor).getUserNameById(userId);
return newPerson(repository, userName, client, monitor);
}
private void addComments(TaskData data, MantisTicket ticket, IMantisClient client, IProgressMonitor monitor) throws MantisException {
if (ticket.getComments() == null)
return;
int commentNumber = 1;
for (MantisComment comment : ticket.getComments()) {
TaskAttribute attribute = data.getRoot().createAttribute(
TaskAttribute.PREFIX_COMMENT + commentNumber);
TaskCommentMapper taskComment = TaskCommentMapper .createFrom(attribute);
taskComment.setCommentId(String.valueOf(comment.getId()));
taskComment.setAuthor(newPerson(data.getAttributeMapper().getTaskRepository(), comment.getReporter(), client, monitor));
taskComment.setNumber(commentNumber);
taskComment.setIsPrivate(comment.getIsPrivate());
taskComment.setText(comment.getText());
taskComment.setCreationDate(comment.getDateSubmitted());
taskComment.applyTo(attribute);
commentMapper.registerCommentNumber(comment.getId(), new CommentMapping(ticket.getId(), commentNumber));
commentNumber++;
}
}
private IRepositoryPerson newPerson(TaskRepository repository, String personId, IMantisClient client, IProgressMonitor monitor) throws MantisException {
if ( personId == null )
return repository.createPerson("unknown");
IRepositoryPerson person = repository.createPerson(personId);
MantisUser user = client.getCache(monitor).getUserByUsername(personId);
if ( user != null )
person.setName(user.getRealName());
return person;
}
private void createDefaultAttributes(TaskData data,
IMantisClient client, String projectName, IProgressMonitor monitor, boolean existingTask) throws CoreException {
// The order here is important as it controls how it appears in the Editor
data.setVersion(String.valueOf(migrator.getCurrent().getValue()));
try {
MantisCache cache = client.getCache(monitor);
createAttribute(data, MantisAttributeMapper.Attribute.PROJECT, null).setValue(projectName);
createAttribute(data, MantisAttributeMapper.Attribute.CATEGORY, null);
createAttribute(data, MantisAttributeMapper.Attribute.RESOLUTION,
cache.getTicketResolutions(), String.valueOf(cache.getDefaultResolution().getValue()));
createAttribute(data, MantisAttributeMapper.Attribute.STATUS, cache
.getTicketStatus(), String.valueOf(cache.getSubmitStatus().getValue()));
createAttribute(data, MantisAttributeMapper.Attribute.PRIORITY, cache
.getPriorities(), String.valueOf(cache.getDefaultPriority().getValue()));
createAttribute(data, MantisAttributeMapper.Attribute.SEVERITY, cache
.getSeverities(), String.valueOf(cache.getDefaultSeverity().getValue()));
createAttribute(data, MantisAttributeMapper.Attribute.REPRODUCIBILITY,
cache.getReproducibility(), String.valueOf(cache.getDefaultReproducibility().getValue()));
createAttribute(data, MantisAttributeMapper.Attribute.VERSION, null);
createAttribute(data, MantisAttributeMapper.Attribute.FIXED_IN, null);
if ( client.getCache(monitor).getRepositoryVersion().isHasTargetVersionSupport())
createAttribute(data, MantisAttributeMapper.Attribute.TARGET_VERSION, null);
if ( cache.isProjectionEnabled())
createAttribute(data, MantisAttributeMapper.Attribute.PROJECTION, cache.getProjection(),
String.valueOf(cache.getDefaultProjection().getValue()));
if ( cache.isEtaEnabled() )
createAttribute(data, MantisAttributeMapper.Attribute.ETA, cache.getETA(),
String.valueOf(cache.getDefaultEta().getValue()));
if ( cache.isEnableProfiles()) {
createAttribute(data, MantisAttributeMapper.Attribute.PLATFORM, null);
createAttribute(data, MantisAttributeMapper.Attribute.OS, null);
createAttribute(data, MantisAttributeMapper.Attribute.OS_BUILD, null);
}
if ( client.isDueDateEnabled(monitor))
createAttribute(data, MantisAttributeMapper.Attribute.DUE_DATE, null);
if (client.isTimeTrackingEnabled(monitor)) {
createAttribute(data, MantisAttributeMapper.Attribute.TIME_SPENT, null);
createAttribute(data, MantisAttributeMapper.Attribute.TIME_SPENT_NEW, null);
}
if ( client.getCache(monitor).getRepositoryVersion().isHasProperTaskRelations())
createTaskRelations(data);
createAttribute(data, MantisAttributeMapper.Attribute.DESCRIPTION);
createAttribute(data,
MantisAttributeMapper.Attribute.STEPS_TO_REPRODUCE).setValue(cache.getDefaultStepsToReproduce());
createAttribute(data, MantisAttributeMapper.Attribute.ADDITIONAL_INFO).setValue(cache.getDefaultAdditionalInfo());
if ( !data.isNew() )
createAttribute(data, MantisAttributeMapper.Attribute.NEW_COMMENT, null);
createAttribute(data, MantisAttributeMapper.Attribute.VIEW_STATE,
cache.getViewState(), String.valueOf(cache.getDefaultViewState().getValue()));
createAttribute(data, MantisAttributeMapper.Attribute.ASSIGNED_TO, cache.getDevelopersByProjectName(projectName, monitor), true);
if (existingTask)
createAttribute(data, MantisAttributeMapper.Attribute.REPORTER, cache.getUsersByProjectName(projectName, monitor), false);
createAttribute(data, MantisAttributeMapper.Attribute.SUMMARY);
createAttribute(data, MantisAttributeMapper.Attribute.DATE_SUBMITTED);
createAttribute(data, MantisAttributeMapper.Attribute.LAST_UPDATED);
createAttribute(data, MantisAttributeMapper.Attribute.COMPLETION_DATE);
if ( client.getCache(monitor).getRepositoryVersion().isHasTagSupport() ) {
List<MantisTag> repositoryTags = client.getCache(monitor).getTags();
createAttribute(data, Attribute.TAGS, repositoryTags.toArray(new MantisTag[repositoryTags.size()]));
}
// operations
data.getRoot().createAttribute(TaskAttribute.OPERATION).getMetaData() .setType(TaskAttribute.TYPE_OPERATION);
} catch (MantisException e) {
throw new CoreException(statusFactory.toStatus(null, e, null));
}
}
private void createTaskRelations(TaskData data) {
createAttribute(data, MantisAttributeMapper.Attribute.PARENT_OF, null);
createAttribute(data, MantisAttributeMapper.Attribute.CHILD_OF, null);
createAttribute(data, MantisAttributeMapper.Attribute.DUPLICATE_OF, null);
createAttribute(data, MantisAttributeMapper.Attribute.HAS_DUPLICATE, null);
createAttribute(data, MantisAttributeMapper.Attribute.RELATED_TO, null);
}
private void createProjectSpecificAttributes(TaskData data, IMantisClient client, IProgressMonitor monitor) throws MantisException {
// categories
TaskAttribute attr = getAttribute(data,
MantisAttributeMapper.Attribute.CATEGORY.getKey());
attr.clearOptions();
boolean first = MantisUtils.isEmpty(attr.getValue());
TaskAttribute projectAttribute = data.getRoot().getAttribute( MantisAttributeMapper.Attribute.PROJECT.getKey());
for (MantisProjectCategory mp : client.getCache(monitor).getProjectCategories(projectAttribute.getValue())) {
if (first) {
attr.setValue(mp.toString());
first = false;
}
attr.putOption(mp.toString(), mp.toString());
}
// versions
TaskAttribute repInVerAttr = getAttribute(data,
MantisAttributeMapper.Attribute.VERSION.getKey());
repInVerAttr.clearOptions();
repInVerAttr.putOption("none", ""); // empty option
TaskAttribute fixInVerAttr = getAttribute(data,
MantisAttributeMapper.Attribute.FIXED_IN.getKey());
fixInVerAttr.clearOptions();
fixInVerAttr.putOption("none", "");// Add empty option
TaskAttribute targetVersionAttr = null;
if ( client.getCache(monitor).getRepositoryVersion().isHasTargetVersionSupport()) {
targetVersionAttr = getAttribute(data,
MantisAttributeMapper.Attribute.TARGET_VERSION.getKey());
targetVersionAttr.clearOptions();
targetVersionAttr.putOption("none", "");// Add empty option
}
for (MantisVersion v : client.getCache(monitor).getVersionsByProjectName(getAttribute(data,
MantisAttributeMapper.Attribute.PROJECT.getKey())
.getValue())) {
/*
* Only display released versions for the reported in field,
* matches the behaviour of the mantis web interface.
*/
if (v.isReleased())
repInVerAttr.putOption(v.getName(), v.getName());
fixInVerAttr.putOption(v.getName(), v.getName());
if ( client.getCache(monitor).getRepositoryVersion().isHasTargetVersionSupport())
targetVersionAttr.putOption(v.getName(), v.getName());
}
/* If the value is empty then the issue has not yet been fixed */
if (MantisUtils.isEmpty(fixInVerAttr.getValue()))
fixInVerAttr.setValue("none");
if (MantisUtils.isEmpty(repInVerAttr.getValue()))
repInVerAttr.setValue("none");
if ( client.getCache(monitor).getRepositoryVersion().isHasTargetVersionSupport() && MantisUtils.isEmpty(targetVersionAttr.getValue()))
targetVersionAttr.setValue("none");
}
private TaskAttribute createAttribute(TaskData data, MantisAttributeMapper.Attribute attribute,
MantisTicketAttribute[] values, boolean allowEmpty) {
boolean readOnly = data.isNew() ? attribute.isReadOnlyForNewTask() : attribute.isReadOnlyForExistingTask();
TaskAttribute attr = data.getRoot().createAttribute(attribute.getKey());
attr.getMetaData().setReadOnly(readOnly).setLabel(attribute.toString())
.setKind(attribute.getKind()).setType( attribute.getType());
if (values != null && values.length > 0) {
if (allowEmpty)
attr.putOption("", "");
for (MantisTicketAttribute value : values)
attr.putOption(value.getKey(), value.getName());
}
return attr;
}
private TaskAttribute createAttribute(TaskData data,
MantisAttributeMapper.Attribute attribute) {
boolean readOnly = data.isNew() ? attribute.isReadOnlyForNewTask() : attribute.isReadOnlyForExistingTask();
TaskAttribute attr = data.getRoot().createAttribute(attribute.getKey());
attr.getMetaData().setReadOnly(readOnly).setLabel(
attribute.toString()).setKind(attribute.getKind()).setType(
attribute.getType());
return attr;
}
private TaskAttribute createAttribute(TaskData data,
MantisAttributeMapper.Attribute attribute, MantisTicketAttribute[] values,
String defaultValue) {
TaskAttribute rta = createAttribute(data, attribute, values, false);
rta.setValue(defaultValue);
return rta;
}
private TaskAttribute getAttribute(TaskData data, String key) {
TaskAttribute attribute = data.getRoot().getAttribute(key);
if (attribute == null)
attribute = data.getRoot().createAttribute(key);
return attribute;
}
private TaskAttribute createAttribute(TaskData data,
MantisAttributeMapper.Attribute attribute, MantisTicketAttribute[] values) {
return createAttribute(data, attribute, values, false);
}
/**
* Given a Mantis Ticket create the necessary TaskData object
*
* @param IMantisClient
* client
* @param TaskRepository
* repository
* @param MantisTicket
* ticket
* @param IProgressMontiro
* monitor
*
* @since 3.0
*/
public TaskData createTaskDataFromTicket(IMantisClient client,
TaskRepository repository, MantisTicket ticket,
IProgressMonitor monitor) throws CoreException {
TaskData taskData = newTaskData(repository, ticket);
try {
String projectName = ticket.getValue(Key.PROJECT);
createDefaultAttributes(taskData, client, projectName, monitor, true);
updateTaskData(repository, taskData,
client, ticket, monitor);
createProjectSpecificAttributes(taskData, client, monitor);
createCustomFieldAttributes(taskData, client, new MantisTicketCustomFieldValueSource(ticket), monitor);
return taskData;
} catch (MantisException e) {
throw new CoreException(statusFactory.toStatus(null, e, repository));
}
}
public TaskData createTaskDataFromPartialTicket(IMantisClient client,
TaskRepository repository, MantisTicket ticket,
IProgressMonitor monitor) throws CoreException, MantisException {
MantisCache cache = client.getCache(monitor);
TaskData taskData = newTaskData(repository, ticket);
taskData.setPartial(true);
createAttribute(taskData, MantisAttributeMapper.Attribute.PROJECT).setValue(ticket.getValue(Key.PROJECT));
createAttribute(taskData, MantisAttributeMapper.Attribute.SUMMARY).setValue(ticket.getValue(Key.SUMMARY));
createAttribute(taskData, MantisAttributeMapper.Attribute.STATUS, cache.getTicketStatus()).setValue(ticket.getValue(Key.STATUS));
createAttribute(taskData, MantisAttributeMapper.Attribute.RESOLUTION, cache.getTicketResolutions()).setValue(ticket.getValue(Key.RESOLUTION));
createAttribute(taskData, MantisAttributeMapper.Attribute.PRIORITY, cache.getPriorities()).setValue(ticket.getValue(Key.PRIORITY));
createAttribute(taskData, MantisAttributeMapper.Attribute.SEVERITY, cache.getSeverities()).setValue(ticket.getValue(Key.SEVERITY));
if ( ticket.getLastChanged() != null ) // XXX Remove once we have a fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=331733
createAttribute(taskData, MantisAttributeMapper.Attribute.LAST_UPDATED).setValue(String.valueOf(MantisUtils.toMantisTime(ticket.getLastChanged())));
if ( ticket.getValue(Key.COMPLETION_DATE) != null )
createAttribute(taskData, MantisAttributeMapper.Attribute.COMPLETION_DATE).setValue(ticket.getValue(Key.COMPLETION_DATE));
return taskData;
}
private TaskData newTaskData(TaskRepository repository, MantisTicket ticket) {
TaskData taskData = new TaskData(getAttributeMapper(repository), MantisCorePlugin.REPOSITORY_KIND, repository.getRepositoryUrl(), String.valueOf(ticket.getId()));
// explicitly set the task key from the id
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=497412
getAttribute(taskData, TaskAttribute.TASK_KEY).setValue(taskData.getTaskId());
return taskData;
}
/**
* @param taskData
* @param client
* @param ticket the existing ticket, or null
* @param monitor
* @throws MantisException
*/
private void createCustomFieldAttributes(TaskData taskData, IMantisClient client,
CustomFieldValueSource customFieldValueSource, IProgressMonitor monitor) throws MantisException {
TaskAttribute projectAttribute = taskData.getRoot().getAttribute( MantisAttributeMapper.Attribute.PROJECT.getKey());
for ( MantisCustomField customField : client.getCache(monitor).getCustomFieldsByProjectName(projectAttribute.getValue()) ) {
TaskAttribute customAttribute = taskData.getRoot().createAttribute(customField.getName());
customAttribute.getMetaData().setReadOnly(false);
customAttribute.getMetaData().setLabel(customField.getName());
customAttribute.getMetaData().setKind(TaskAttribute.KIND_DEFAULT);
customAttribute.getMetaData().setType(customFieldTypeToTaskType.get(customField.getType()));
customAttribute.setValue(customFieldValueSource.getCustomFieldValue(customField));
if ( customField.getPossibleValues() != null)
for ( String possibleValue : customField.getPossibleValues())
customAttribute.putOption(possibleValue, possibleValue);
}
}
@Override
public boolean canInitializeSubTaskData(TaskRepository taskRepository,
ITask task) {
if( taskRepository == null )
return false;
return MantisRepositoryConfiguration.isSupportsSubTasks(taskRepository);
}
@Override
public boolean initializeSubTaskData(TaskRepository repository,
TaskData taskData, TaskData parentTaskData, IProgressMonitor monitor)
throws CoreException {
validateSupportsSubtasks(repository, parentTaskData);
try {
IMantisClient client = clientManager.getRepository( repository);
createAttributesForTaskData(repository, taskData, parentTaskData, monitor);
copyAttributesFromParent(taskData, parentTaskData);
clearTaskRelations(taskData);
setChildAttribute(taskData, parentTaskData);
createCustomFieldAttributes(taskData, client, new TaskDataCustomFieldValueSource(parentTaskData), monitor);
return true;
} catch (MantisException e) {
throw new CoreException(statusFactory.toStatus("Failed updating attributes.", e, repository));
}
}
private void validateSupportsSubtasks(TaskRepository repository, TaskData parentTaskData) throws CoreException {
if ( parentTaskData.getRoot().getAttribute(MantisAttributeMapper.Attribute.PARENT_OF.getKey()) == null)
throw new CoreException(statusFactory.toStatus("The repository does not support subtasks.", null, repository));
}
private void createAttributesForTaskData(TaskRepository repository, TaskData taskData, TaskData parentTaskData,
IProgressMonitor monitor) throws MantisException, CoreException {
IMantisClient client = clientManager.getRepository( repository);
TaskAttribute projectAttribute = parentTaskData.getRoot().getAttribute(MantisAttributeMapper.Attribute.PROJECT.getKey());
createDefaultAttributes(taskData, client, projectAttribute.getValue(), monitor, false);
getAttribute(taskData, MantisAttributeMapper.Attribute.PROJECT.getKey()).setValue(projectAttribute.getValue());
createProjectSpecificAttributes(taskData, client, monitor);
}
private void copyAttributesFromParent(TaskData taskData, TaskData parentTaskData) {
TaskMapper mapper = new TaskMapper(taskData);
mapper.merge(new TaskMapper(parentTaskData));
mapper.setDescription("");
mapper.setSummary("");
}
private void clearTaskRelations(TaskData taskData) {
for (Key taskRelationKey : MantisAttributeMapper.taskRelationKeys())
taskData.getRoot().getAttribute(taskRelationKey.getKey()).clearValues();
}
private void setChildAttribute(TaskData taskData, TaskData parentTaskData) {
TaskAttribute attribute = taskData.getRoot().getAttribute(MantisAttributeMapper.Attribute.CHILD_OF.getKey());
attribute.setValue(parentTaskData.getTaskId());
}
public RelationType getRelationTypeForAttribute(Attribute attribute) {
RelationType relationType = attributeToRelationType.get(attribute);
if ( relationType == null )
throw new RuntimeException("No relationType for attribute " + attribute);
return relationType;
}
public MantisCommentMapper getCommentMapper() {
return commentMapper;
}
private static interface CustomFieldValueSource {
String getCustomFieldValue(MantisCustomField customField);
}
private static class MantisTicketCustomFieldValueSource implements CustomFieldValueSource {
private final MantisTicket ticket;
public MantisTicketCustomFieldValueSource(MantisTicket ticket) {
this.ticket = ticket;
}
public String getCustomFieldValue(MantisCustomField customField) {
String valueToSet = ticket != null ? ticket.getCustomFieldValue(customField.getName()) : customField.getDefaultValue();
if ( valueToSet == null)
valueToSet = "";
return valueToSet;
}
}
private static class TaskDataCustomFieldValueSource implements CustomFieldValueSource {
private final TaskData taskData;
public TaskDataCustomFieldValueSource(TaskData taskData) {
Assert.isNotNull(taskData);
this.taskData = taskData;
}
public String getCustomFieldValue(MantisCustomField customField) {
return taskData.getRoot().getAttribute(customField.getName()).getValue();
}
}
private static class DefaultCustomFieldValueSource implements CustomFieldValueSource {
public String getCustomFieldValue(MantisCustomField customField) {
return customField.getDefaultValue();
}
}
@Override
public void migrateTaskData(TaskRepository repository, TaskData taskData) {
try {
migrator.migrateTaskData(repository, taskData, clientManager.getRepository(repository));
} catch (Exception e) {
MantisCorePlugin.error("Failed getting a client for repository " + repository, e);
}
}
}