package com.taskadapter.redmineapi.bean;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* Redmine's Issue
*/
public class Issue implements Identifiable {
/**
* database ID.
*/
private Integer id;
private String subject;
private Integer parentId;
private Float estimatedHours;
private Float spentHours;
private User assignee;
private String priorityText;
private Integer priorityId;
private Integer doneRatio;
private Project project;
private User author;
private Date startDate;
private Date dueDate;
private Tracker tracker;
private String description;
private Date createdOn;
private Date updatedOn;
private Integer statusId;
private String statusName;
private Version targetVersion;
private IssueCategory category;
/**
* Some comment describing the issue update
*/
private String notes;
/**
* can't have two custom fields with the same ID in the collection, that's why it is declared
* as a Set, not a List.
*/
private final Set<CustomField> customFields = new HashSet<CustomField>();
private final Set<Journal> journals = new HashSet<Journal>();
private final Set<IssueRelation> relations = new HashSet<IssueRelation>();
private final Set<Attachment> attachments = new HashSet<Attachment>();
private final Set<Changeset> changesets = new HashSet<Changeset>();
private final Set<Watcher> watchers = new HashSet<Watcher>();
@Override
public void setId(Integer id) {
this.id = id;
}
/**
* @param id database ID.
*/
public Issue(Integer id) {
this.id = id;
}
public Issue() {
this.id = null;
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public Integer getDoneRatio() {
return doneRatio;
}
public void setDoneRatio(Integer doneRatio) {
this.doneRatio = doneRatio;
}
public String getPriorityText() {
return priorityText;
}
/**
* @deprecated This method has no effect when creating issues on Redmine Server, so we might as well just delete it
* in the future releases.
*/
public void setPriorityText(String priority) {
this.priorityText = priority;
}
public User getAssignee() {
return assignee;
}
public void setAssignee(User assignee) {
this.assignee = assignee;
}
public Float getEstimatedHours() {
return estimatedHours;
}
public void setEstimatedHours(Float estimatedTime) {
this.estimatedHours = estimatedTime;
}
public Float getSpentHours() {
return spentHours;
}
public void setSpentHours(Float spentHours) {
this.spentHours = spentHours;
}
/**
* Parent Issue ID, or NULL for issues without a parent.
*
* @return NULL, if there's no parent
*/
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
@Override
/**
* @return id. can be NULL for Issues not added to Redmine yet
*/
public Integer getId() {
return id;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getDueDate() {
return dueDate;
}
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
public Tracker getTracker() {
return tracker;
}
public void setTracker(Tracker tracker) {
this.tracker = tracker;
}
/**
* Description is empty by default, not NULL.
*/
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public Date getUpdatedOn() {
return updatedOn;
}
public void setUpdatedOn(Date updatedOn) {
this.updatedOn = updatedOn;
}
public Integer getStatusId() {
return statusId;
}
public void setStatusId(Integer statusId) {
this.statusId = statusId;
}
public String getStatusName() {
return statusName;
}
public void setStatusName(String statusName) {
this.statusName = statusName;
}
/**
* @return Custom Field objects. the collection may be empty, but it is never NULL.
*/
public Collection<CustomField> getCustomFields() {
return Collections.unmodifiableCollection(customFields);
}
public void clearCustomFields() {
customFields.clear();
}
/**
* NOTE: The custom field(s) <strong>must have correct database ID set</strong> to be saved to Redmine. This is Redmine REST API's limitation.
*/
public void addCustomFields(Collection<CustomField> customFields) {
this.customFields.addAll(customFields);
}
/**
* If there is a custom field with the same ID already present in the Issue,
* the new field replaces the old one.
*
* @param customField the field to add to the issue.
*/
public void addCustomField(CustomField customField) {
customFields.add(customField);
}
public String getNotes() {
return notes;
}
/**
* @param notes Some comment describing the issue update
*/
public void setNotes(String notes) {
this.notes = notes;
}
/**
* Don't forget to use Include.journals flag when loading issue from Redmine server:
* <pre>
* Issue issue = issueManager.getIssueById(3205, Include.journals);
* </pre>
* @return Collection of Journal entries or empty collection if no objects found.
* @see com.taskadapter.redmineapi.Include#journals
*/
public Collection<Journal> getJournals() {
return Collections.unmodifiableCollection(journals);
}
public void addJournals(Collection<Journal> journals) {
this.journals.addAll(journals);
}
/**
* Don't forget to use Include.changesets flag when loading issue from Redmine server:
* <pre>
* Issue issue = issueManager.getIssueById(3205, Include.changesets);
* </pre>
* @return Collection of entries or empty collection if no objects found.
* @see com.taskadapter.redmineapi.Include#changesets
*/
public Collection<Changeset> getChangesets() {
return Collections.unmodifiableCollection(changesets);
}
public void addChangesets(Collection<Changeset> changesets) {
this.changesets.addAll(changesets);
}
/**
* Don't forget to use Include.watchers flag when loading issue from Redmine server:
* <pre>
* Issue issue = issueManager.getIssueById(3205, Include.watchers);
* </pre>
* @return Collection of entries or empty collection if no objects found.
* @see com.taskadapter.redmineapi.Include#watchers
*/
public Collection<Watcher> getWatchers() {
return Collections.unmodifiableCollection(watchers);
}
public void addWatchers(Collection<Watcher> watchers) {
this.watchers.addAll(watchers);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Issue issue = (Issue) o;
if (id != null ? !id.equals(issue.id) : issue.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
/**
* Deprecated. Please use the new getCustomFieldByName() method instead because the return value of this method
* is not consistent with getCustomFieldById().
*
* @return the value or NULL if the field is not found
*
* @see #getCustomFieldByName(String customFieldName)
*/
@Deprecated
public String getCustomField(String fieldName) {
for (CustomField f : customFields) {
if (f.getName().equals(fieldName)) {
return f.getValue();
}
}
return null;
}
/**
* @return the custom field with given Id or NULL if the field is not found
*/
public CustomField getCustomFieldById(int customFieldId) {
if(customFields == null) return null;
for (CustomField customField : customFields) {
if (customFieldId == customField.getId()) {
return customField;
}
}
return null;
}
/**
* @return the custom field with given name or NULL if the field is not found
*/
public CustomField getCustomFieldByName(String customFieldName) {
if(customFields == null) return null;
for (CustomField customField : customFields) {
if (customFieldName.equals(customField.getName())) {
return customField;
}
}
return null;
}
@Override
public String toString() {
return "Issue [id=" + id + ", subject=" + subject + "]";
}
/**
* Relations are only loaded if you include INCLUDE.relations when loading the Issue.
* <pre>
* Issue issue = issueManager.getIssueById(3205, Include.relations);
* </pre>
* @return relations or EMPTY collection if no relations, never returns NULL
* @see com.taskadapter.redmineapi.Include#relations
*/
public Collection<IssueRelation> getRelations() {
return Collections.unmodifiableCollection(relations);
}
public void addRelations(Collection<IssueRelation> collection) {
relations.addAll(collection);
}
public Integer getPriorityId() {
return priorityId;
}
public void setPriorityId(Integer priorityId) {
this.priorityId = priorityId;
}
public Version getTargetVersion() {
return targetVersion;
}
/**
* Don't forget to use <i>Include.attachments</i> flag when loading issue from Redmine server:
* <pre>
* Issue issue = issueManager.getIssueById(3205, Include.attachments);
* </pre>
* @return Collection of entries or empty collection if no objects found.
* @see com.taskadapter.redmineapi.Include#attachments
*/
public Collection<Attachment> getAttachments() {
return Collections.unmodifiableCollection(attachments);
}
public void addAttachments(Collection<Attachment> collection) {
attachments.addAll(collection);
}
public void addAttachment(Attachment attachment) {
attachments.add(attachment);
}
public void setTargetVersion(Version version) {
this.targetVersion = version;
}
public IssueCategory getCategory() {
return category;
}
public void setCategory(IssueCategory category) {
this.category = category;
}
}