IssueServiceImpl.java
/*
* This software was designed and created by Jason Carroll.
* Copyright (c) 2002, 2003, 2004 Jason Carroll.
* The author can be reached at jcarroll@cowsultants.com
* ITracker website: http://www.cowsultants.com
* ITracker forums: http://www.cowsultants.com/phpBB/index.php
*
* This program is free software; you can redistribute it and/or modify
* it only under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package org.itracker.services.implementations;
import org.apache.log4j.Logger;
import org.itracker.IssueSearchException;
import org.itracker.ProjectException;
import org.itracker.core.resources.ITrackerResources;
import org.itracker.model.*;
import org.itracker.model.Notification.Role;
import org.itracker.model.Notification.Type;
import org.itracker.model.util.IssueUtilities;
import org.itracker.persistence.dao.*;
import org.itracker.services.ConfigurationService;
import org.itracker.services.IssueService;
import org.itracker.services.NotificationService;
import java.util.*;
/**
* Issue related service layer. A bit "fat" at this time, because of being a* direct EJB porting. Going go get thinner over time** @author ricardo
* */
//TODO: Cleanup this file, go through all issues, todos, etc.
public class IssueServiceImpl implements IssueService {
private static final Logger logger = Logger
.getLogger(IssueServiceImpl.class);
private ConfigurationService configurationService;
private CustomFieldDAO customFieldDAO;
private ProjectDAO projectDAO;
private IssueDAO issueDAO;
private IssueHistoryDAO issueHistoryDAO;
private IssueRelationDAO issueRelationDAO;
private IssueAttachmentDAO issueAttachmentDAO;
private ComponentDAO componentDAO;
private IssueActivityDAO issueActivityDAO;
private VersionDAO versionDAO;
private NotificationService notificationService;
private UserDAO userDAO;
public IssueServiceImpl() {
}
public Issue getIssue(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
return issue;
}
/**
* @deprecated don't use to expensive memory use!
*/
public List<Issue> getAllIssues() {
logger.warn("getAllIssues: use of deprecated API");
if (logger.isDebugEnabled()) {
logger
.debug("getAllIssues: stacktrace was",
new RuntimeException());
}
return getIssueDAO().findAll();
}
/**
* Added implementation to make proper count of ALL issues, instead select
* them in a list and return its size
*/
public Long getNumberIssues() {
return getIssueDAO().countAllIssues();
}
public List<Issue> getIssuesCreatedByUser(Integer userId) {
return getIssuesCreatedByUser(userId, true);
}
public List<Issue> getIssuesCreatedByUser(Integer userId,
boolean availableProjectsOnly) {
final List<Issue> issues;
if (availableProjectsOnly) {
issues = getIssueDAO().findByCreatorInAvailableProjects(userId,
IssueUtilities.STATUS_CLOSED);
} else {
issues = getIssueDAO().findByCreator(userId,
IssueUtilities.STATUS_CLOSED);
}
return issues;
}
public List<Issue> getIssuesOwnedByUser(Integer userId) {
return getIssuesOwnedByUser(userId, true);
}
public List<Issue> getIssuesOwnedByUser(Integer userId,
boolean availableProjectsOnly) {
final List<Issue> issues;
if (availableProjectsOnly) {
issues = getIssueDAO().findByOwnerInAvailableProjects(userId,
IssueUtilities.STATUS_RESOLVED);
} else {
issues = getIssueDAO().findByOwner(userId,
IssueUtilities.STATUS_RESOLVED);
}
return issues;
}
public List<Issue> getIssuesWatchedByUser(Integer userId) {
return getIssuesWatchedByUser(userId, true);
}
/**
* TODO move to {@link NotificationService}
*/
public List<Issue> getIssuesWatchedByUser(Integer userId,
boolean availableProjectsOnly) {
final List<Issue> issues;
if (availableProjectsOnly) {
issues = getIssueDAO().findByNotificationInAvailableProjects(
userId, IssueUtilities.STATUS_CLOSED);
} else {
issues = getIssueDAO().findByNotification(userId,
IssueUtilities.STATUS_CLOSED);
}
return issues;
}
public List<Issue> getUnassignedIssues() {
return getUnassignedIssues(true);
}
public List<Issue> getUnassignedIssues(boolean availableProjectsOnly) {
final List<Issue> issues;
if (availableProjectsOnly) {
issues = getIssueDAO()
.findByStatusLessThanEqualToInAvailableProjects(
IssueUtilities.STATUS_UNASSIGNED);
} else {
issues = getIssueDAO().findByStatusLessThanEqualTo(
IssueUtilities.STATUS_UNASSIGNED);
}
return issues;
}
/**
* Returns all issues with a status equal to the given status number
*
* @param status the status to compare
* @return an array of IssueModels that match the criteria
*/
public List<Issue> getIssuesWithStatus(int status) {
List<Issue> issues = getIssueDAO().findByStatus(status);
return issues;
}
/**
* Returns all issues with a status less than the given status number
*
* @param status the status to compare
* @return an array of IssueModels that match the criteria
*/
public List<Issue> getIssuesWithStatusLessThan(int status) {
List<Issue> issues = getIssueDAO().findByStatusLessThan(status);
return issues;
}
/**
* Returns all issues with a severity equal to the given severity number
*
* @param severity the severity to compare
* @return an array of IssueModels that match the criteria
*/
public List<Issue> getIssuesWithSeverity(int severity) {
List<Issue> issues = getIssueDAO().findBySeverity(severity);
return issues;
}
public List<Issue> getIssuesByProjectId(Integer projectId) {
return getIssuesByProjectId(projectId, IssueUtilities.STATUS_END);
}
public List<Issue> getIssuesByProjectId(Integer projectId, int status) {
List<Issue> issues = getIssueDAO().findByProjectAndLowerStatus(
projectId, status);
return issues;
}
public User getIssueCreator(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
User user = issue.getCreator();
return user;
}
public User getIssueOwner(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
User user = issue.getOwner();
return user;
}
public List<Component> getIssueComponents(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
List<Component> components = issue.getComponents();
return components;
}
public List<Version> getIssueVersions(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
List<Version> versions = issue.getVersions();
return versions;
}
public List<IssueAttachment> getIssueAttachments(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
List<IssueAttachment> attachments = issue.getAttachments();
return attachments;
}
/**
* Old implementation is left here, commented, because it checked for
* history entry status. This feature was not finished, I think (RJST)
*/
public List<IssueHistory> getIssueHistory(Integer issueId) {
return getIssueDAO().findByPrimaryKey(issueId).getHistory();
}
public Issue createIssue(Issue issue, Integer projectId, Integer userId,
Integer createdById) throws ProjectException {
Project project = getProjectDAO().findByPrimaryKey(projectId);
User creator = getUserDAO().findByPrimaryKey(userId);
if (project.getStatus() != Status.ACTIVE) {
throw new ProjectException("Project is not active.");
}
IssueActivity activity = new IssueActivity(issue, creator,
IssueActivityType.ISSUE_CREATED);
activity.setDescription(ITrackerResources
.getString("itracker.activity.system.createdfor")
+ " " + creator.getFirstName() + " " + creator.getLastName());
activity.setIssue(issue);
if (!(createdById == null || createdById.equals(userId))) {
User createdBy = getUserDAO().findByPrimaryKey(createdById);
activity.setUser(createdBy);
Notification watchModel = new Notification();
watchModel.setUser(createdBy);
watchModel.setIssue(issue);
watchModel.setRole(Notification.Role.CONTRIBUTER);
issue.getNotifications().add(watchModel);
}
List<IssueActivity> activities = new ArrayList<IssueActivity>();
activities.add(activity);
issue.setActivities(activities);
issue.setProject(project);
issue.setCreator(creator);
// save
getIssueDAO().save(issue);
return issue;
}
/**
* Save a modified issue to the persistence layer
*
* @param issueDirty the changed, unsaved issue to update on persistency layer
* @param userId the user-id of the changer
*/
public Issue updateIssue(final Issue issueDirty, final Integer userId)
throws ProjectException {
String existingTargetVersion = null;
// detach the modified Issue form the Hibernate Session
getIssueDAO().detach(issueDirty);
// Retrieve the Issue from Hibernate Session and refresh it from
// Hibernate Session to previous state.
Issue persistedIssue = getIssueDAO().findByPrimaryKey(
issueDirty.getId());
getIssueDAO().refresh(persistedIssue);
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: updating issue " + issueDirty
+ "\n(from " + persistedIssue + ")");
}
User user = getUserDAO().findByPrimaryKey(userId);
if (persistedIssue.getProject().getStatus() != Status.ACTIVE) {
throw new ProjectException("Project "
+ persistedIssue.getProject().getName() + " is not active.");
}
if (!persistedIssue.getDescription().equalsIgnoreCase(
issueDirty.getDescription())) {
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: updating description from "
+ persistedIssue.getDescription());
}
IssueActivity activity = new IssueActivity();
activity.setActivityType(IssueActivityType.DESCRIPTION_CHANGE);
activity.setDescription(ITrackerResources
.getString("itracker.web.generic.from")
+ ": " + persistedIssue.getDescription());
activity.setUser(user);
activity.setIssue(issueDirty);
issueDirty.getActivities().add(activity);
}
if (persistedIssue.getResolution() != null
&& !persistedIssue.getResolution().equalsIgnoreCase(
issueDirty.getResolution())) {
IssueActivity activity = new IssueActivity();
activity.setActivityType(IssueActivityType.RESOLUTION_CHANGE);
activity.setDescription(ITrackerResources
.getString("itracker.web.generic.from")
+ ": " + persistedIssue.getResolution());
activity.setUser(user);
activity.setIssue(issueDirty);
issueDirty.getActivities().add(activity);
}
if (null == persistedIssue.getStatus()
|| !persistedIssue.getStatus().equals(issueDirty.getStatus())) {
IssueActivity activity = new IssueActivity();
activity.setActivityType(IssueActivityType.STATUS_CHANGE);
activity.setDescription(IssueUtilities.getStatusName(persistedIssue
.getStatus())
+ " "
+ ITrackerResources.getString("itracker.web.generic.to")
+ " "
+ IssueUtilities.getStatusName(issueDirty.getStatus()));
activity.setUser(user);
activity.setIssue(issueDirty);
issueDirty.getActivities().add(activity);
}
if (issueDirty.getSeverity() != null
&& !issueDirty.getSeverity().equals(
persistedIssue.getSeverity())
&& issueDirty.getSeverity() != -1) {
IssueActivity activity = new IssueActivity();
activity.setActivityType(IssueActivityType.SEVERITY_CHANGE);
// FIXME why does it state Critical to Critical when it should Major to Critical!?
activity.setDescription(IssueUtilities
.getSeverityName(persistedIssue.getSeverity())
+ " "
+ ITrackerResources.getString("itracker.web.generic.to")
+ " "
+ IssueUtilities.getSeverityName(issueDirty.getSeverity()));
activity.setUser(user);
activity.setIssue(issueDirty);
issueDirty.getActivities().add(activity);
}
if (persistedIssue.getTargetVersion() != null
&& issueDirty.getTargetVersion() != null
&& !persistedIssue.getTargetVersion().getId().equals(
issueDirty.getTargetVersion().getId())) {
existingTargetVersion = persistedIssue.getTargetVersion()
.getNumber();
Version version = this.getVersionDAO().findByPrimaryKey(
issueDirty.getTargetVersion().getId());
IssueActivity activity = new IssueActivity();
activity.setActivityType(IssueActivityType.TARGETVERSION_CHANGE);
String description = existingTargetVersion + " "
+ ITrackerResources.getString("itracker.web.generic.to")
+ " ";
description += version.getNumber();
activity.setDescription(description);
activity.setUser(user);
activity.setIssue(issueDirty);
issueDirty.getActivities().add(activity);
}
// (re-)assign issue
User newOwner = issueDirty.getOwner();
issueDirty.setOwner(persistedIssue.getOwner());
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: assigning from " + issueDirty.getOwner()
+ " to " + newOwner);
}
assignIssue(issueDirty, newOwner, user, false);
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: updated assignment: " + issueDirty);
}
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: merging issue " + issueDirty + " to "
+ persistedIssue);
}
persistedIssue = getIssueDAO().merge(issueDirty);
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: merged issue for saving: "
+ persistedIssue);
}
getIssueDAO().saveOrUpdate(persistedIssue);
if (logger.isDebugEnabled()) {
logger.debug("updateIssue: saved issue: " + persistedIssue);
}
return persistedIssue;
}
/**
* Moves an issues from its current project to a new project.
*
* @param issue an Issue of the issue to move
* @param projectId the id of the target project
* @param userId the id of the user that is moving the issue
* @return an Issue of the issue after it has been moved
*/
public Issue moveIssue(Issue issue, Integer projectId, Integer userId) {
if (logger.isDebugEnabled()) {
logger.debug("moveIssue: " + issue + " to project#" + projectId
+ ", user#" + userId);
}
Project project = getProjectDAO().findByPrimaryKey(projectId);
User user = getUserDAO().findByPrimaryKey(userId);
if (logger.isDebugEnabled()) {
logger.debug("moveIssue: " + issue + " to project: " + project
+ ", user: " + user);
}
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.ISSUE_MOVE);
activity.setDescription(issue.getProject().getName() + " "
+ ITrackerResources.getString("itracker.web.generic.to") + " "
+ project.getName());
activity.setUser(user);
activity.setIssue(issue);
issue.setProject(project);
issue.getActivities().add(activity);
if (logger.isDebugEnabled()) {
logger.debug("moveIssue: updated issue: " + issue);
}
try {
getIssueDAO().saveOrUpdate(issue);
} catch (Exception e) {
logger.error("moveIssue: failed to save issue: " + issue, e);
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("moveIssue: saved move-issue to " + project);
}
return issue;
}
/**
* this should not exist. adding an history entry should be adding the
* history entry to the domain object and saving the object...
*/
public boolean addIssueHistory(IssueHistory history) {
getIssueHistoryDAO().saveOrUpdate(history);
history.getIssue().getHistory().add(history);
getIssueDAO().saveOrUpdate(history.getIssue());
return true;
}
/**
* TODO maybe it has no use at all. is it obsolete? when I'd set the
* issue-fields on an issue and then save/update issue, would it be good
* enough?
*/
public boolean setIssueFields(Integer issueId, List<IssueField> fields) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
setIssueFields(issue, fields, true);
return true;
}
private boolean setIssueFields(Issue issue, List<IssueField> fields,
boolean save) {
List<IssueField> issueFields = issue.getFields();
if (fields.size() > 0) {
for (int i = 0; i < fields.size(); i++) {
IssueField field = fields.get(i);
if (issueFields.contains(field)) {
issueFields.remove(field);
}
CustomField customField = getCustomFieldDAO().findByPrimaryKey(
fields.get(i).getCustomField().getId());
field.setCustomField(customField);
field.setIssue(issue);
issueFields.add(field);
}
}
issue.setFields(issueFields);
if (save) {
logger.debug("setIssueFields: save was true");
getIssueDAO().saveOrUpdate(issue);
}
return true;
}
public boolean setIssueComponents(Integer issueId,
HashSet<Integer> componentIds, Integer userId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
List<Component> components = new ArrayList<Component>(componentIds
.size());
User user = userDAO.findByPrimaryKey(userId);
Iterator<Integer> idIt = componentIds.iterator();
while (idIt.hasNext()) {
Integer id = (Integer) idIt.next();
Component c = getComponentDAO().findById(id);
components.add(c);
}
setIssueComponents(issue, components, user, true);
return true;
}
private boolean setIssueComponents(Issue issue, List<Component> components,
User user, boolean save) {
if (issue.getComponents() == null) {
if (logger.isInfoEnabled()) {
logger.info("setIssueComponents: components was null");
}
issue.setComponents(new ArrayList<Component>(components.size()));
}
if (components.isEmpty() && !issue.getComponents().isEmpty()) {
addComponentsModifiedActivity(issue, user, new StringBuilder(
ITrackerResources.getString("itracker.web.generic.all"))
.append(" ").append(
ITrackerResources
.getString("itracker.web.generic.removed"))
.toString());
issue.getComponents().clear();
} else {
Collections.sort(issue.getComponents(), Component.NAME_COMPARATOR);
for (Iterator<Component> iterator = issue.getComponents()
.iterator(); iterator.hasNext(); ) {
Component component = (Component) iterator.next();
if (components.contains(component)) {
components.remove(component);
} else {
addComponentsModifiedActivity(issue, user,
new StringBuilder(ITrackerResources
.getString("itracker.web.generic.removed"))
.append(": ").append(component.getName())
.toString());
iterator.remove();
}
}
Collections.sort(components, Component.NAME_COMPARATOR);
for (Iterator<Component> iterator = components.iterator(); iterator
.hasNext(); ) {
Component component = iterator.next();
if (!issue.getComponents().contains(component)) {
addComponentsModifiedActivity(issue, user,
new StringBuilder(ITrackerResources
.getString("itracker.web.generic.added"))
.append(": ").append(component.getName())
.toString());
issue.getComponents().add(component);
}
}
}
if (save) {
if (logger.isDebugEnabled()) {
logger.debug("setIssueComponents: save was true");
}
getIssueDAO().saveOrUpdate(issue);
}
return true;
}
/**
* used by setIssueComponents for adding change activities
*/
private void addComponentsModifiedActivity(Issue issue, User user,
String description) {
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.COMPONENTS_MODIFIED);
activity.setDescription(description);
activity.setIssue(issue);
activity.setUser(user);
issue.getActivities().add(activity);
}
private boolean setIssueVersions(Issue issue, List<Version> versions,
User user, boolean save) {
if (issue.getVersions() == null) {
if (logger.isInfoEnabled()) {
logger.info("setIssueVersions: versions were null!");
}
issue.setVersions(new ArrayList<Version>());
}
if (versions.isEmpty() && !issue.getVersions().isEmpty()) {
addVersionsModifiedActivity(issue, user, new StringBuilder(
ITrackerResources.getString("itracker.web.generic.all"))
.append(" ").append(
ITrackerResources
.getString("itracker.web.generic.removed"))
.toString());
issue.getVersions().clear();
} else {
Collections.sort(issue.getVersions(), Version.VERSION_COMPARATOR);
StringBuilder changesBuf = new StringBuilder();
for (Iterator<Version> iterator = issue.getVersions().iterator(); iterator
.hasNext(); ) {
Version version = iterator.next();
if (versions.contains(version)) {
versions.remove(version);
} else {
if (changesBuf.length() > 0) {
changesBuf.append(", ");
}
changesBuf.append(version.getNumber());
iterator.remove();
}
}
if (changesBuf.length() > 0) {
addVersionsModifiedActivity(issue, user, new StringBuilder(
ITrackerResources
.getString("itracker.web.generic.removed"))
.append(": ").append(changesBuf).toString());
}
changesBuf = new StringBuilder();
Collections.sort(versions, Version.VERSION_COMPARATOR);
for (Iterator<Version> iterator = versions.iterator(); iterator
.hasNext(); ) {
Version version = iterator.next();
if (changesBuf.length() > 0) {
changesBuf.append(", ");
}
changesBuf.append(version.getNumber());
issue.getVersions().add(version);
}
if (changesBuf.length() > 0) {
addVersionsModifiedActivity(issue, user, new StringBuilder(
ITrackerResources
.getString("itracker.web.generic.added"))
.append(": ").append(changesBuf).toString());
}
}
if (save) {
if (logger.isDebugEnabled()) {
logger.debug("setIssueVersions: updating issue: " + issue);
}
getIssueDAO().saveOrUpdate(issue);
}
return true;
}
/**
* used by setIssueComponents for adding change activities
*/
private void addVersionsModifiedActivity(Issue issue, User user,
String description) {
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.TARGETVERSION_CHANGE);
activity.setDescription(description);
activity.setIssue(issue);
activity.setUser(user);
issue.getActivities().add(activity);
}
public boolean setIssueVersions(Integer issueId,
HashSet<Integer> versionIds, Integer userId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
User user = userDAO.findByPrimaryKey(userId);
// load versions from ids
ArrayList<Version> versions = new ArrayList<Version>(versionIds.size());
Iterator<Integer> versionsIdIt = versionIds.iterator();
while (versionsIdIt.hasNext()) {
Integer id = versionsIdIt.next();
versions.add(getVersionDAO().findByPrimaryKey(id));
}
return setIssueVersions(issue, versions, user, true);
}
public IssueRelation getIssueRelation(Integer relationId) {
IssueRelation issueRelation = getIssueRelationDAO().findByPrimaryKey(
relationId);
return issueRelation;
}
/**
* add a relation between two issues.
* <p/>
* TODO: There is no relation saved to database yet?
*/
public boolean addIssueRelation(Integer issueId, Integer relatedIssueId,
IssueRelation.Type relationType, Integer userId) {
User user = getUserDAO().findByPrimaryKey(userId);
if (null == user) {
throw new IllegalArgumentException("Invalid user-id: " + userId);
}
if (issueId != null && relatedIssueId != null) {
IssueRelation.Type matchingRelationType = IssueUtilities
.getMatchingRelationType(relationType);
// if(matchingRelationType < 0) {
// throw new CreateException("Unable to find matching relation type
// for type: " + relationType);
// }
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
Issue relatedIssue = getIssueDAO().findByPrimaryKey(relatedIssueId);
IssueRelation relationA = new IssueRelation();
relationA.setRelationType(relationType);
// relationA.setMatchingRelationId(relationBId);
relationA.setIssue(issue);
relationA.setRelatedIssue(relatedIssue);
// set to 0 first, later reassign to relationB.id
relationA.setMatchingRelationId(0);
relationA.setLastModifiedDate(new java.sql.Timestamp(new Date()
.getTime()));
getIssueRelationDAO().saveOrUpdate(relationA);
IssueRelation relationB = new IssueRelation();
relationB.setRelationType(matchingRelationType);
// relationB.setMatchingRelationId(relationAId);
relationB.setIssue(relatedIssue);
relationB.setRelatedIssue(issue);
relationB.setMatchingRelationId(relationA.getId());
relationB.setLastModifiedDate(new java.sql.Timestamp(new Date()
.getTime()));
getIssueRelationDAO().saveOrUpdate(relationB);
relationA.setMatchingRelationId(relationB.getId());
getIssueRelationDAO().saveOrUpdate(relationA);
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.RELATION_ADDED);
activity.setDescription(ITrackerResources.getString(
"itracker.activity.relation.add", new Object[]{
IssueUtilities.getRelationName(relationType),
relatedIssueId}));
activity.setIssue(issue);
issue.getActivities().add(activity);
// need to set user here
activity.setUser(user);
// need to save here
getIssueDAO().saveOrUpdate(issue);
activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.RELATION_ADDED);
activity.setDescription(ITrackerResources.getString(
"itracker.activity.relation.add", new Object[]{
IssueUtilities
.getRelationName(matchingRelationType),
issueId}));
activity.setIssue(relatedIssue);
activity.setUser(user);
relatedIssue.getActivities().add(activity);
getIssueDAO().saveOrUpdate(relatedIssue);
return true;
}
return false;
}
public void removeIssueRelation(Integer relationId, Integer userId) {
IssueRelation issueRelation = getIssueRelationDAO().findByPrimaryKey(
relationId);
Integer issueId = issueRelation.getIssue().getId();
Integer relatedIssueId = issueRelation.getRelatedIssue().getId();
Integer matchingRelationId = issueRelation.getMatchingRelationId();
if (matchingRelationId != null) {
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.RELATION_REMOVED);
activity.setDescription(ITrackerResources.getString(
"itracker.activity.relation.removed", issueId.toString()));
// FIXME need to fix the commented code and save
// activity.setIssue(relatedIssueId);
// activity.setUser(userId);
// IssueRelationDAO.remove(matchingRelationId);
}
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.RELATION_REMOVED);
activity.setDescription(ITrackerResources
.getString("itracker.activity.relation.removed", relatedIssueId
.toString()));
// activity.setIssue(issueId);
// activity.setUser(userId);
// irHome.remove(relationId);
// need to save
getIssueRelationDAO().delete(issueRelation);
}
public boolean assignIssue(Integer issueId, Integer userId) {
return assignIssue(issueId, userId, userId);
}
/**
* only use for updating issue from actions..
*/
public boolean assignIssue(Integer issueId, Integer userId,
Integer assignedByUserId) {
return assignIssue(getIssueDAO().findByPrimaryKey(issueId),
getUserDAO().findByPrimaryKey(userId), getUserDAO()
.findByPrimaryKey(assignedByUserId), true);
}
/**
* Only for use
*
* @param save save issue and send notification
*/
private boolean assignIssue(Issue issue, User user, User assignedByUser,
final boolean save) {
if (issue.getOwner() == user
|| (null != issue.getOwner() && issue.getOwner().equals(user))) {
// nothing to do.
if (logger.isDebugEnabled()) {
logger.debug("assignIssue: attempted to reassign " + issue
+ " to current owner " + user);
}
return false;
}
if (null == user) {
if (logger.isInfoEnabled()) {
logger.info("assignIssue: call to unasign " + issue);
}
return unassignIssue(issue, assignedByUser, save);
}
if (logger.isInfoEnabled()) {
logger.info("assignIssue: assigning " + issue + " to " + user);
}
User currOwner = issue.getOwner();
if (!user.equals(currOwner)) {
if (currOwner != null
&& !notificationService.hasIssueNotification(issue,
currOwner.getId(), Role.IP)) {
// Notification notification = new Notification();
Notification notification = new Notification(currOwner, issue,
Role.IP);
if (save) {
notificationService.addIssueNotification(notification);
} else {
issue.getNotifications().add(notification);
}
}
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.OWNER_CHANGE);
activity.setDescription((currOwner == null ? "["
+ ITrackerResources
.getString("itracker.web.generic.unassigned") + "]"
: currOwner.getLogin())
+ " "
+ ITrackerResources.getString("itracker.web.generic.to")
+ " " + user.getLogin());
activity.setUser(assignedByUser);
activity.setIssue(issue);
issue.getActivities().add(activity);
issue.setOwner(user);
if (logger.isDebugEnabled()) {
logger.debug("assignIssue: current status: "
+ issue.getStatus());
}
if (issue.getStatus() < IssueUtilities.STATUS_ASSIGNED) {
issue.setStatus(IssueUtilities.STATUS_ASSIGNED);
if (logger.isDebugEnabled()) {
logger.debug("assignIssue: new status set to "
+ issue.getStatus());
}
}
// send assignment notification
if (save) {
if (logger.isDebugEnabled()) {
logger.debug("assignIssue: saving re-assigned issue");
}
getIssueDAO().saveOrUpdate(issue);
notificationService.sendNotification(issue, Type.ASSIGNED,
getConfigurationService().getSystemBaseURL());
}
}
return true;
}
/**
* @param save save issue and send notification
*/
private boolean unassignIssue(Issue issue, User unassignedByUser,
boolean save) {
if (logger.isDebugEnabled()) {
logger.debug("unassignIssue: " + issue);
}
if (issue.getOwner() != null) {
if (logger.isDebugEnabled()) {
logger.debug("unassignIssue: unassigning from "
+ issue.getOwner());
}
if (!notificationService.hasIssueNotification(issue, issue
.getOwner().getId(), Role.CONTRIBUTER)) {
// Notification notification = new Notification();
Notification notification = new Notification(issue.getOwner(),
issue, Role.CONTRIBUTER);
if (save) {
notificationService.addIssueNotification(notification);
} else {
issue.getNotifications().add(notification);
}
}
IssueActivity activity = new IssueActivity(issue, unassignedByUser,
IssueActivityType.OWNER_CHANGE);
activity
.setDescription(issue.getOwner().getLogin()
+ " "
+ ITrackerResources
.getString("itracker.web.generic.to")
+ " ["
+ ITrackerResources
.getString("itracker.web.generic.unassigned")
+ "]");
issue.setOwner(null);
if (issue.getStatus() >= IssueUtilities.STATUS_ASSIGNED) {
issue.setStatus(IssueUtilities.STATUS_UNASSIGNED);
}
if (save) {
if (logger.isDebugEnabled()) {
logger.debug("unassignIssue: saving unassigned issue..");
}
getIssueDAO().saveOrUpdate(issue);
notificationService.sendNotification(issue, Type.ASSIGNED,
getConfigurationService().getSystemBaseURL());
}
}
return true;
}
/**
* System-Update an issue, adds the action to the issue and updates the
* issue
*/
public Issue systemUpdateIssue(Issue updateissue, Integer userId)
throws ProjectException {
IssueActivity activity = new IssueActivity();
activity.setActivityType(IssueActivityType.SYSTEM_UPDATE);
activity.setDescription(ITrackerResources
.getString("itracker.activity.system.status"));
ArrayList<IssueActivity> activities = new ArrayList<IssueActivity>();
activity.setIssue(updateissue);
activity.setUser(getUserDAO().findByPrimaryKey(userId));
updateissue.getActivities().add(activity);
Issue updated = updateIssue(updateissue, userId);
updated.getActivities().addAll(activities);
getIssueDAO().saveOrUpdate(updated);
return updated;
}
/*
* public boolean addIssueActivity(IssueActivityModel model) {
*
* Issue issue = ifHome.findByPrimaryKey(model.getIssueId());
*
* User user = ufHome.findByPrimaryKey(model.getUserId());
*
* //return addIssueActivity(model, issue, user); return
* addIssueActivity(null, issue, user); }
*/
/*
* public boolean addIssueActivity(IssueActivityModel model, Issue issue) {
*
* User user = ufHome.findByPrimaryKey(model.getUserId());
*
* return true;//addIssueActivity(model, issue, user); }
*/
/**
* I think this entire method is useless - RJST TODO move to
* {@link NotificationService}
*/
/*
* public boolean addIssueActivity(IssueActivityBean model, Issue issue,
* User user) {
*
* IssueActivityBean activity = new IssueActivityBean();
*
* //activity.setModel(model);
*
* activity.setIssue(issue);
*
* activity.setUser(user);
*
* return true; }
*/
public void updateIssueActivityNotification(Integer issueId,
boolean notificationSent) {
if (issueId == null) {
return;
}
Collection<IssueActivity> activity = getIssueActivityDAO()
.findByIssueId(issueId);
for (Iterator<IssueActivity> iter = activity.iterator(); iter.hasNext(); ) {
((IssueActivity) iter.next()).setNotificationSent(notificationSent);
}
}
/**
* Adds an attachment to an issue
*
* @param attachment The attachment data
* @param data The byte data
*/
public boolean addIssueAttachment(IssueAttachment attachment, byte[] data) {
Issue issue = attachment.getIssue();
attachment.setFileName("attachment_issue_" + issue.getId() + "_"
+ attachment.getOriginalFileName());
attachment.setFileData((data == null ? new byte[0] : data));
// TODO: translate activity for adding attachments
// IssueActivity activityAdd = new IssueActivity(issue,
// attachment.getUser(), IssueActivityType.ATTACHMENT_ADDED);
// activityAdd.setDescription(attachment.getOriginalFileName());
// issue.getActivities().add(activityAdd);
if (logger.isDebugEnabled()) {
logger.debug("addIssueAttachment: adding attachment " + attachment);
}
// add attachment to issue
issue.getAttachments().add(attachment);
if (logger.isDebugEnabled()) {
logger.debug("addIssueAttachment: saving updated issue " + issue);
}
this.getIssueDAO().saveOrUpdate(issue);
return true;
}
public boolean setIssueAttachmentData(Integer attachmentId, byte[] data) {
if (attachmentId != null && data != null) {
IssueAttachment attachment = getIssueAttachmentDAO()
.findByPrimaryKey(attachmentId);
attachment.setFileData(data);
return true;
}
return false;
}
public boolean setIssueAttachmentData(String fileName, byte[] data) {
if (fileName != null && data != null) {
IssueAttachment attachment = getIssueAttachmentDAO()
.findByFileName(fileName);
attachment.setFileData(data);
return true;
}
return false;
}
/**
* Removes a attachement (deletes it)
*
* @param attachmentId the id of the <code>IssueAttachmentBean</code>
*/
public boolean removeIssueAttachment(Integer attachmentId) {
IssueAttachment attachementBean = this.getIssueAttachmentDAO()
.findByPrimaryKey(attachmentId);
getIssueAttachmentDAO().delete(attachementBean);
return true;
}
public Integer removeIssueHistoryEntry(Integer entryId, Integer userId) {
IssueHistory history = getIssueHistoryDAO().findByPrimaryKey(entryId);
if (history != null) {
history.setStatus(IssueUtilities.HISTORY_STATUS_REMOVED);
IssueActivity activity = new IssueActivity();
activity
.setActivityType(org.itracker.model.IssueActivityType.REMOVE_HISTORY);
activity.setDescription(ITrackerResources
.getString("itracker.web.generic.entry")
+ " "
+ entryId
+ " "
+ ITrackerResources
.getString("itracker.web.generic.removed") + ".");
getIssueHistoryDAO().delete(history);
return history.getIssue().getId();
}
return Integer.valueOf(-1);
}
public Project getIssueProject(Integer issueId) {
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
Project project = issue.getProject();
return project;
}
public HashSet<Integer> getIssueComponentIds(Integer issueId) {
HashSet<Integer> componentIds = new HashSet<Integer>();
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
Collection<Component> components = issue.getComponents();
for (Iterator<Component> iterator = components.iterator(); iterator
.hasNext(); ) {
componentIds.add(((Component) iterator.next()).getId());
}
return componentIds;
}
public HashSet<Integer> getIssueVersionIds(Integer issueId) {
HashSet<Integer> versionIds = new HashSet<Integer>();
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
Collection<Version> versions = issue.getVersions();
for (Iterator<Version> iterator = versions.iterator(); iterator
.hasNext(); ) {
versionIds.add(((Version) iterator.next()).getId());
}
return versionIds;
}
public List<IssueActivity> getIssueActivity(Integer issueId) {
int i = 0;
Collection<IssueActivity> activity = getIssueActivityDAO()
.findByIssueId(issueId);
IssueActivity[] activityArray = new IssueActivity[activity.size()];
for (Iterator<IssueActivity> iterator = activity.iterator(); iterator
.hasNext(); i++) {
activityArray[i] = ((IssueActivity) iterator.next());
}
return Arrays.asList(activityArray);
}
/**
* TODO move to {@link NotificationService} ?
*/
public List<IssueActivity> getIssueActivity(Integer issueId,
boolean notificationSent) {
int i = 0;
Collection<IssueActivity> activity = getIssueActivityDAO()
.findByIssueIdAndNotification(issueId, notificationSent);
IssueActivity[] activityArray = new IssueActivity[activity.size()];
for (Iterator<IssueActivity> iterator = activity.iterator(); iterator
.hasNext(); i++) {
activityArray[i] = ((IssueActivity) iterator.next());
}
return Arrays.asList(activityArray);
}
public Long getAllIssueAttachmentCount() {
return getIssueAttachmentDAO().countAll().longValue();
}
public List<IssueAttachment> getAllIssueAttachments() {
logger.warn("getAllIssueAttachments: use of deprecated API");
if (logger.isDebugEnabled()) {
logger.debug("getAllIssueAttachments: stacktrace was",
new RuntimeException());
}
List<IssueAttachment> attachments = getIssueAttachmentDAO().findAll();
return attachments;
}
public IssueAttachment getIssueAttachment(Integer attachmentId) {
IssueAttachment attachment = getIssueAttachmentDAO().findByPrimaryKey(
attachmentId);
return attachment;
}
public byte[] getIssueAttachmentData(Integer attachmentId) {
byte[] data;
IssueAttachment attachment = getIssueAttachmentDAO().findByPrimaryKey(
attachmentId);
data = attachment.getFileData();
return data;
}
public int getIssueAttachmentCount(Integer issueId) {
int i = 0;
Issue issue = getIssueDAO().findByPrimaryKey(issueId);
Collection<IssueAttachment> attachments = issue.getAttachments();
i = attachments.size();
return i;
}
/**
* Returns the latest issue history entry for a particular issue.
*
* @param issueId the id of the issue to return the history entry for.
* @return the latest IssueHistory, or null if no entries could be found
*/
public IssueHistory getLastIssueHistory(Integer issueId) {
List<IssueHistory> history = getIssueHistoryDAO()
.findByIssueId(issueId);
if (null != history && history.size() > 0) {
// sort ascending by id
Collections.sort(history, AbstractEntity.ID_COMPARATOR);
// return last entry in list
return history.get(history.size() - 1);
}
return null;
}
public int getOpenIssueCountByProjectId(Integer projectId) {
Collection<Issue> issues = getIssueDAO().findByProjectAndLowerStatus(
projectId, IssueUtilities.STATUS_RESOLVED);
return issues.size();
}
public int getResolvedIssueCountByProjectId(Integer projectId) {
Collection<Issue> issues = getIssueDAO().findByProjectAndHigherStatus(
projectId, IssueUtilities.STATUS_RESOLVED);
return issues.size();
}
public int getTotalIssueCountByProjectId(Integer projectId) {
Collection<Issue> issues = getIssueDAO().findByProject(projectId);
return issues.size();
}
public Date getLatestIssueDateByProjectId(Integer projectId) {
return getIssueDAO().latestModificationDate(projectId);
}
public List<Issue> getNextIssues(Integer issueId) {
return getIssueDAO().findNextIssues(issueId);
}
public List<Issue> getPreviousIssues(Integer issueId) {
return getIssueDAO().findPreviousIssues(issueId);
}
public boolean canViewIssue(Integer issueId, User user) {
Issue issue = getIssue(issueId);
Map<Integer, Set<PermissionType>> permissions = getUserDAO()
.getUsersMapOfProjectsAndPermissionTypes(user);
return IssueUtilities.canViewIssue(issue, user.getId(), permissions);
}
public boolean canViewIssue(Issue issue, User user) {
Map<Integer, Set<PermissionType>> permissions = getUserDAO()
.getUsersMapOfProjectsAndPermissionTypes(user);
return IssueUtilities.canViewIssue(issue, user.getId(), permissions);
}
private UserDAO getUserDAO() {
return userDAO;
}
private IssueDAO getIssueDAO() {
return issueDAO;
}
private ProjectDAO getProjectDAO() {
return projectDAO;
}
private IssueActivityDAO getIssueActivityDAO() {
return issueActivityDAO;
}
private VersionDAO getVersionDAO() {
return this.versionDAO;
}
private ComponentDAO getComponentDAO() {
return this.componentDAO;
}
private CustomFieldDAO getCustomFieldDAO() {
return customFieldDAO;
}
private IssueHistoryDAO getIssueHistoryDAO() {
return issueHistoryDAO;
}
private IssueRelationDAO getIssueRelationDAO() {
return issueRelationDAO;
}
private IssueAttachmentDAO getIssueAttachmentDAO() {
return issueAttachmentDAO;
}
/**
* get total size of all attachments in database
*/
public Long getAllIssueAttachmentSize() {
return getIssueAttachmentDAO().totalAttachmentsSize().longValue() / 1024;
}
public List<Issue> searchIssues(IssueSearchQuery queryModel, User user,
Map<Integer, Set<PermissionType>> userPermissions)
throws IssueSearchException {
return getIssueDAO().query(queryModel, user, userPermissions);
}
public Long totalSystemIssuesAttachmentSize() {
return getIssueAttachmentDAO().totalAttachmentsSize();
}
public ConfigurationService getConfigurationService() {
return configurationService;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
public void setCustomFieldDAO(CustomFieldDAO customFieldDAO) {
this.customFieldDAO = customFieldDAO;
}
public void setProjectDAO(ProjectDAO projectDAO) {
this.projectDAO = projectDAO;
}
public void setIssueDAO(IssueDAO issueDAO) {
this.issueDAO = issueDAO;
}
public void setIssueHistoryDAO(IssueHistoryDAO issueHistoryDAO) {
this.issueHistoryDAO = issueHistoryDAO;
}
public void setIssueRelationDAO(IssueRelationDAO issueRelationDAO) {
this.issueRelationDAO = issueRelationDAO;
}
public void setIssueAttachmentDAO(IssueAttachmentDAO issueAttachmentDAO) {
this.issueAttachmentDAO = issueAttachmentDAO;
}
public void setComponentDAO(ComponentDAO componentDAO) {
this.componentDAO = componentDAO;
}
public void setIssueActivityDAO(IssueActivityDAO issueActivityDAO) {
this.issueActivityDAO = issueActivityDAO;
}
public void setVersionDAO(VersionDAO versionDAO) {
this.versionDAO = versionDAO;
}
public void setNotificationService(NotificationService notificationService) {
this.notificationService = notificationService;
}
}