Clover Coverage Report - itracker
Coverage timestamp: Tue May 1 2012 16:42:12 CEST
522   1,694   184   6.61
180   1,035   0.35   79
79     2.33  
1    
 
 
  IssueServiceImpl       Line # 96 522 184 0% 0.0
 
No Tests
 
1    /*
2   
3    * This software was designed and created by Jason Carroll.
4   
5    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
6   
7    * The author can be reached at jcarroll@cowsultants.com
8   
9    * ITracker website: http://www.cowsultants.com
10   
11    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
12   
13    *
14   
15    * This program is free software; you can redistribute it and/or modify
16   
17    * it only under the terms of the GNU General Public License as published by
18   
19    * the Free Software Foundation; either version 2 of the License, or
20   
21    * (at your option) any later version.
22   
23    *
24   
25    * This program is distributed in the hope that it will be useful,
26   
27    * but WITHOUT ANY WARRANTY; without even the implied warranty of
28   
29    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30   
31    * GNU General Public License for more details.
32   
33    */
34   
35    package org.itracker.services.implementations;
36   
37    import java.util.ArrayList;
38    import java.util.Arrays;
39    import java.util.Collection;
40    import java.util.Collections;
41    import java.util.Date;
42    import java.util.HashSet;
43    import java.util.Iterator;
44    import java.util.List;
45    import java.util.Map;
46    import java.util.Set;
47   
48    import org.apache.log4j.Logger;
49    import org.itracker.core.resources.ITrackerResources;
50    import org.itracker.model.AbstractEntity;
51    import org.itracker.model.Component;
52    import org.itracker.model.CustomField;
53    import org.itracker.model.Issue;
54    import org.itracker.model.IssueActivity;
55    import org.itracker.model.IssueActivityType;
56    import org.itracker.model.IssueAttachment;
57    import org.itracker.model.IssueField;
58    import org.itracker.model.IssueHistory;
59    import org.itracker.model.IssueRelation;
60    import org.itracker.model.IssueSearchQuery;
61    import org.itracker.model.Notification;
62    import org.itracker.model.PermissionType;
63    import org.itracker.model.Project;
64    import org.itracker.model.Status;
65    import org.itracker.model.User;
66    import org.itracker.model.Version;
67    import org.itracker.model.Notification.Role;
68    import org.itracker.model.Notification.Type;
69    import org.itracker.persistence.dao.ComponentDAO;
70    import org.itracker.persistence.dao.CustomFieldDAO;
71    import org.itracker.persistence.dao.IssueActivityDAO;
72    import org.itracker.persistence.dao.IssueAttachmentDAO;
73    import org.itracker.persistence.dao.IssueDAO;
74    import org.itracker.persistence.dao.IssueHistoryDAO;
75    import org.itracker.persistence.dao.IssueRelationDAO;
76    import org.itracker.persistence.dao.ProjectDAO;
77    import org.itracker.persistence.dao.UserDAO;
78    import org.itracker.persistence.dao.VersionDAO;
79    import org.itracker.services.IssueService;
80    import org.itracker.services.NotificationService;
81    import org.itracker.services.exceptions.IssueSearchException;
82    import org.itracker.services.exceptions.ProjectException;
83    import org.itracker.services.util.IssueUtilities;
84    import org.itracker.web.util.ServletContextUtils;
85   
86    /**
87    * Issue related service layer. A bit "fat" at this time, because of being a
88    * direct EJB porting. Going go get thinner over time
89    *
90    * @author ricardo
91    *
92    */
93   
94    //TODO: Cleanup this file, go through all issues, todos, etc.
95   
 
96    public class IssueServiceImpl implements IssueService {
97   
98    private static final Logger logger = Logger
99    .getLogger(IssueServiceImpl.class);
100   
101    private CustomFieldDAO customFieldDAO;
102   
103    private UserDAO userDAO;
104   
105    private ProjectDAO projectDAO;
106   
107    private IssueDAO issueDAO;
108   
109    private IssueHistoryDAO issueHistoryDAO;
110   
111    private IssueRelationDAO issueRelationDAO;
112   
113    private IssueAttachmentDAO issueAttachmentDAO;
114   
115    private ComponentDAO componentDAO;
116   
117    private IssueActivityDAO issueActivityDAO;
118   
119    private VersionDAO versionDAO;
120   
121    private NotificationService notificationService;
122   
 
123  0 toggle public IssueServiceImpl(UserDAO userDAO, ProjectDAO projectDAO,
124    IssueDAO issueDAO, IssueHistoryDAO issueHistoryDAO,
125    IssueRelationDAO issueRelationDAO,
126    IssueAttachmentDAO issueAttachmentDAO, ComponentDAO componentDAO,
127    IssueActivityDAO issueActivityDAO, VersionDAO versionDAO,
128    CustomFieldDAO customFieldDAO,
129    NotificationService notificationService) {
130   
131  0 this.userDAO = userDAO;
132  0 this.projectDAO = projectDAO;
133  0 this.issueDAO = issueDAO;
134  0 this.issueHistoryDAO = issueHistoryDAO;
135  0 this.issueRelationDAO = issueRelationDAO;
136  0 this.issueAttachmentDAO = issueAttachmentDAO;
137  0 this.componentDAO = componentDAO;
138  0 this.issueActivityDAO = issueActivityDAO;
139  0 this.versionDAO = versionDAO;
140  0 this.customFieldDAO = customFieldDAO;
141  0 this.notificationService = notificationService;
142    }
143   
 
144  0 toggle public Issue getIssue(Integer issueId) {
145  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
146  0 return issue;
147    }
148   
149    /**
150    * @deprecated don't use to expensive memory use!
151    */
 
152  0 toggle public List<Issue> getAllIssues() {
153  0 logger.warn("getAllIssues: use of deprecated API");
154  0 if (logger.isDebugEnabled()) {
155  0 logger
156    .debug("getAllIssues: stacktrace was",
157    new RuntimeException());
158    }
159  0 return getIssueDAO().findAll();
160    }
161   
162    /**
163    * Added implementation to make proper count of ALL issues, instead select
164    * them in a list and return its size
165    */
 
166  0 toggle public Long getNumberIssues() {
167  0 return getIssueDAO().countAllIssues();
168    }
169   
 
170  0 toggle public List<Issue> getIssuesCreatedByUser(Integer userId) {
171  0 return getIssuesCreatedByUser(userId, true);
172    }
173   
 
174  0 toggle public List<Issue> getIssuesCreatedByUser(Integer userId,
175    boolean availableProjectsOnly) {
176  0 final List<Issue> issues;
177   
178  0 if (availableProjectsOnly) {
179  0 issues = getIssueDAO().findByCreatorInAvailableProjects(userId,
180    IssueUtilities.STATUS_CLOSED);
181    } else {
182  0 issues = getIssueDAO().findByCreator(userId,
183    IssueUtilities.STATUS_CLOSED);
184    }
185  0 return issues;
186    }
187   
 
188  0 toggle public List<Issue> getIssuesOwnedByUser(Integer userId) {
189   
190  0 return getIssuesOwnedByUser(userId, true);
191   
192    }
193   
 
194  0 toggle public List<Issue> getIssuesOwnedByUser(Integer userId,
195    boolean availableProjectsOnly) {
196  0 final List<Issue> issues;
197   
198  0 if (availableProjectsOnly) {
199  0 issues = getIssueDAO().findByOwnerInAvailableProjects(userId,
200    IssueUtilities.STATUS_RESOLVED);
201    } else {
202  0 issues = getIssueDAO().findByOwner(userId,
203    IssueUtilities.STATUS_RESOLVED);
204    }
205  0 return issues;
206    }
207   
 
208  0 toggle public List<Issue> getIssuesWatchedByUser(Integer userId) {
209  0 return getIssuesWatchedByUser(userId, true);
210    }
211   
212    /**
213    * TODO move to {@link NotificationService}
214    */
 
215  0 toggle public List<Issue> getIssuesWatchedByUser(Integer userId,
216    boolean availableProjectsOnly) {
217  0 final List<Issue> issues;
218   
219  0 if (availableProjectsOnly) {
220  0 issues = getIssueDAO().findByNotificationInAvailableProjects(
221    userId, IssueUtilities.STATUS_CLOSED);
222    } else {
223  0 issues = getIssueDAO().findByNotification(userId,
224    IssueUtilities.STATUS_CLOSED);
225    }
226  0 return issues;
227    }
228   
 
229  0 toggle public List<Issue> getUnassignedIssues() {
230  0 return getUnassignedIssues(true);
231    }
232   
 
233  0 toggle public List<Issue> getUnassignedIssues(boolean availableProjectsOnly) {
234  0 final List<Issue> issues;
235   
236  0 if (availableProjectsOnly) {
237  0 issues = getIssueDAO()
238    .findByStatusLessThanEqualToInAvailableProjects(
239    IssueUtilities.STATUS_UNASSIGNED);
240    } else {
241  0 issues = getIssueDAO().findByStatusLessThanEqualTo(
242    IssueUtilities.STATUS_UNASSIGNED);
243    }
244  0 return issues;
245    }
246   
247    /**
248    *
249    * Returns all issues with a status equal to the given status number
250    *
251    *
252    *
253    * @param status
254    *
255    * the status to compare
256    *
257    * @return an array of IssueModels that match the criteria
258    *
259    */
260   
 
261  0 toggle public List<Issue> getIssuesWithStatus(int status) {
262  0 List<Issue> issues = getIssueDAO().findByStatus(status);
263  0 return issues;
264    }
265   
266    /**
267    *
268    * Returns all issues with a status less than the given status number
269    *
270    *
271    *
272    * @param status
273    *
274    * the status to compare
275    *
276    * @return an array of IssueModels that match the criteria
277    */
278   
 
279  0 toggle public List<Issue> getIssuesWithStatusLessThan(int status) {
280  0 List<Issue> issues = getIssueDAO().findByStatusLessThan(status);
281  0 return issues;
282    }
283   
284    /**
285    *
286    * Returns all issues with a severity equal to the given severity number
287    *
288    *
289    *
290    * @param severity
291    *
292    * the severity to compare
293    *
294    * @return an array of IssueModels that match the criteria
295    *
296    */
297   
 
298  0 toggle public List<Issue> getIssuesWithSeverity(int severity) {
299  0 List<Issue> issues = getIssueDAO().findBySeverity(severity);
300  0 return issues;
301   
302    }
303   
 
304  0 toggle public List<Issue> getIssuesByProjectId(Integer projectId) {
305  0 return getIssuesByProjectId(projectId, IssueUtilities.STATUS_END);
306    }
307   
 
308  0 toggle public List<Issue> getIssuesByProjectId(Integer projectId, int status) {
309  0 List<Issue> issues = getIssueDAO().findByProjectAndLowerStatus(
310    projectId, status);
311  0 return issues;
312    }
313   
 
314  0 toggle public User getIssueCreator(Integer issueId) {
315  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
316  0 User user = issue.getCreator();
317  0 return user;
318   
319    }
320   
 
321  0 toggle public User getIssueOwner(Integer issueId) {
322  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
323  0 User user = issue.getOwner();
324   
325  0 return user;
326   
327    }
328   
 
329  0 toggle public List<Component> getIssueComponents(Integer issueId) {
330  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
331  0 List<Component> components = issue.getComponents();
332   
333  0 return components;
334    }
335   
 
336  0 toggle public List<Version> getIssueVersions(Integer issueId) {
337  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
338   
339  0 List<Version> versions = issue.getVersions();
340  0 return versions;
341    }
342   
 
343  0 toggle public List<IssueAttachment> getIssueAttachments(Integer issueId) {
344  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
345   
346  0 List<IssueAttachment> attachments = issue.getAttachments();
347  0 return attachments;
348    }
349   
350    /**
351    * Old implementation is left here, commented, because it checked for
352    * history entry status. This feature was not finished, I think (RJST)
353    */
 
354  0 toggle public List<IssueHistory> getIssueHistory(Integer issueId) {
355  0 return getIssueDAO().findByPrimaryKey(issueId).getHistory();
356    }
357   
 
358  0 toggle public Issue createIssue(Issue issue, Integer projectId, Integer userId,
359    Integer createdById) throws ProjectException {
360  0 Project project = getProjectDAO().findByPrimaryKey(projectId);
361  0 User creator = getUserDAO().findByPrimaryKey(userId);
362   
363  0 if (project.getStatus() != Status.ACTIVE) {
364  0 throw new ProjectException("Project is not active.");
365    }
366   
367  0 IssueActivity activity = new IssueActivity(issue, creator,
368    IssueActivityType.ISSUE_CREATED);
369  0 activity.setDescription(ITrackerResources
370    .getString("itracker.activity.system.createdfor")
371    + " " + creator.getFirstName() + " " + creator.getLastName());
372   
373  0 activity.setIssue(issue);
374   
375  0 if (!(createdById == null || createdById.equals(userId))) {
376   
377  0 User createdBy = getUserDAO().findByPrimaryKey(createdById);
378  0 activity.setUser(createdBy);
379   
380  0 Notification watchModel = new Notification();
381   
382  0 watchModel.setUser(createdBy);
383   
384  0 watchModel.setIssue(issue);
385   
386  0 watchModel.setRole(Notification.Role.CONTRIBUTER);
387   
388  0 issue.getNotifications().add(watchModel);
389   
390    // Does save issue after saving notificaton -> not-null property references a null or transient value: org.itracker.model.Notification.issue
391    // Will be saved by cascade when saving issue
392    // notificationService.addIssueNotification(watchModel);
393   
394    }
395   
396  0 List<IssueActivity> activities = new ArrayList<IssueActivity>();
397  0 activities.add(activity);
398  0 issue.setActivities(activities);
399   
400  0 issue.setProject(project);
401   
402  0 issue.setCreator(creator);
403   
404    // save
405  0 getIssueDAO().save(issue);
406   
407  0 return issue;
408    }
409   
410    /**
411    * Save a modified issue to the persistence layer
412    *
413    * @param issueDirty
414    * the changed, unsaved issue to update on persistency layer
415    * @param userId
416    * the user-id of the changer
417    *
418    */
 
419  0 toggle public Issue updateIssue(final Issue issueDirty, final Integer userId)
420    throws ProjectException {
421   
422  0 String existingTargetVersion = null;
423   
424    // detach the modified Issue form the Hibernate Session
425  0 getIssueDAO().detach(issueDirty);
426    // Retrieve the Issue from Hibernate Session and refresh it from
427    // Hibernate Session to previous state.
428  0 Issue persistedIssue = getIssueDAO().findByPrimaryKey(
429    issueDirty.getId());
430   
431  0 getIssueDAO().refresh(persistedIssue);
432  0 if (logger.isDebugEnabled()) {
433  0 logger.debug("updateIssue: updating issue " + issueDirty
434    + "\n(from " + persistedIssue + ")");
435    }
436   
437  0 User user = getUserDAO().findByPrimaryKey(userId);
438   
439  0 if (persistedIssue.getProject().getStatus() != Status.ACTIVE) {
440  0 throw new ProjectException("Project "
441    + persistedIssue.getProject().getName() + " is not active.");
442    }
443   
444  0 if (!persistedIssue.getDescription().equalsIgnoreCase(
445    issueDirty.getDescription())) {
446   
447  0 if (logger.isDebugEnabled()) {
448  0 logger.debug("updateIssue: updating description from "
449    + persistedIssue.getDescription());
450    }
451  0 IssueActivity activity = new IssueActivity();
452  0 activity.setActivityType(IssueActivityType.DESCRIPTION_CHANGE);
453  0 activity.setDescription(ITrackerResources
454    .getString("itracker.web.generic.from")
455    + ": " + persistedIssue.getDescription());
456  0 activity.setUser(user);
457  0 activity.setIssue(issueDirty);
458  0 issueDirty.getActivities().add(activity);
459   
460    }
461   
462  0 if (persistedIssue.getResolution() != null
463    && !persistedIssue.getResolution().equalsIgnoreCase(
464    issueDirty.getResolution())) {
465   
466  0 IssueActivity activity = new IssueActivity();
467  0 activity.setActivityType(IssueActivityType.RESOLUTION_CHANGE);
468  0 activity.setDescription(ITrackerResources
469    .getString("itracker.web.generic.from")
470    + ": " + persistedIssue.getResolution());
471  0 activity.setUser(user);
472  0 activity.setIssue(issueDirty);
473  0 issueDirty.getActivities().add(activity);
474    }
475   
476  0 if (null == persistedIssue.getStatus()
477    || !persistedIssue.getStatus().equals(issueDirty.getStatus())) {
478  0 IssueActivity activity = new IssueActivity();
479  0 activity.setActivityType(IssueActivityType.STATUS_CHANGE);
480  0 activity.setDescription(IssueUtilities.getStatusName(persistedIssue
481    .getStatus())
482    + " "
483    + ITrackerResources.getString("itracker.web.generic.to")
484    + " "
485    + IssueUtilities.getStatusName(issueDirty.getStatus()));
486  0 activity.setUser(user);
487  0 activity.setIssue(issueDirty);
488  0 issueDirty.getActivities().add(activity);
489    }
490   
491  0 if (issueDirty.getSeverity() != null
492    && !issueDirty.getSeverity().equals(
493    persistedIssue.getSeverity())
494    && issueDirty.getSeverity() != -1) {
495   
496  0 IssueActivity activity = new IssueActivity();
497  0 activity.setActivityType(IssueActivityType.SEVERITY_CHANGE);
498    // FIXME why does it state Critical to Critical when it should Major to Critical!?
499  0 activity.setDescription(IssueUtilities
500    .getSeverityName(persistedIssue.getSeverity())
501    + " "
502    + ITrackerResources.getString("itracker.web.generic.to")
503    + " "
504    + IssueUtilities.getSeverityName(issueDirty.getSeverity()));
505   
506  0 activity.setUser(user);
507  0 activity.setIssue(issueDirty);
508  0 issueDirty.getActivities().add(activity);
509    }
510   
511  0 if (persistedIssue.getTargetVersion() != null
512    && issueDirty.getTargetVersion() != null
513    && !persistedIssue.getTargetVersion().getId().equals(
514    issueDirty.getTargetVersion().getId())) {
515  0 existingTargetVersion = persistedIssue.getTargetVersion()
516    .getNumber();
517  0 Version version = this.getVersionDAO().findByPrimaryKey(
518    issueDirty.getTargetVersion().getId());
519   
520  0 IssueActivity activity = new IssueActivity();
521  0 activity.setActivityType(IssueActivityType.TARGETVERSION_CHANGE);
522  0 String description = existingTargetVersion + " "
523    + ITrackerResources.getString("itracker.web.generic.to")
524    + " ";
525  0 description += version.getNumber();
526  0 activity.setDescription(description);
527  0 activity.setUser(user);
528  0 activity.setIssue(issueDirty);
529  0 issueDirty.getActivities().add(activity);
530    }
531   
532    // (re-)assign issue
533  0 User newOwner = issueDirty.getOwner();
534  0 issueDirty.setOwner(persistedIssue.getOwner());
535  0 if (logger.isDebugEnabled()) {
536  0 logger.debug("updateIssue: assigning from " + issueDirty.getOwner()
537    + " to " + newOwner);
538    }
539  0 assignIssue(issueDirty, newOwner, user, false);
540  0 if (logger.isDebugEnabled()) {
541  0 logger.debug("updateIssue: updated assignment: " + issueDirty);
542    }
543   
544  0 if (logger.isDebugEnabled()) {
545  0 logger.debug("updateIssue: merging issue " + issueDirty + " to "
546    + persistedIssue);
547    }
548   
549  0 persistedIssue = getIssueDAO().merge(issueDirty);
550   
551  0 if (logger.isDebugEnabled()) {
552  0 logger.debug("updateIssue: merged issue for saving: "
553    + persistedIssue);
554    }
555  0 getIssueDAO().saveOrUpdate(persistedIssue);
556  0 if (logger.isDebugEnabled()) {
557  0 logger.debug("updateIssue: saved issue: " + persistedIssue);
558    }
559  0 return persistedIssue;
560    }
561   
562    /**
563    *
564    * Moves an issues from its current project to a new project.
565    *
566    *
567    *
568    * @param issue
569    *
570    * an Issue of the issue to move
571    *
572    * @param projectId
573    *
574    * the id of the target project
575    *
576    * @param userId
577    *
578    * the id of the user that is moving the issue
579    *
580    * @return an Issue of the issue after it has been moved
581    */
582   
 
583  0 toggle public Issue moveIssue(Issue issue, Integer projectId, Integer userId) {
584   
585  0 if (logger.isDebugEnabled()) {
586  0 logger.debug("moveIssue: " + issue + " to project#" + projectId
587    + ", user#" + userId);
588    }
589   
590  0 Project project = getProjectDAO().findByPrimaryKey(projectId);
591  0 User user = getUserDAO().findByPrimaryKey(userId);
592   
593  0 if (logger.isDebugEnabled()) {
594  0 logger.debug("moveIssue: " + issue + " to project: " + project
595    + ", user: " + user);
596    }
597   
598  0 IssueActivity activity = new IssueActivity();
599  0 activity
600    .setActivityType(org.itracker.model.IssueActivityType.ISSUE_MOVE);
601  0 activity.setDescription(issue.getProject().getName() + " "
602    + ITrackerResources.getString("itracker.web.generic.to") + " "
603    + project.getName());
604  0 activity.setUser(user);
605  0 activity.setIssue(issue);
606  0 issue.setProject(project);
607   
608  0 issue.getActivities().add(activity);
609   
610  0 if (logger.isDebugEnabled()) {
611  0 logger.debug("moveIssue: updated issue: " + issue);
612    }
613  0 try {
614  0 getIssueDAO().saveOrUpdate(issue);
615    } catch (Exception e) {
616  0 logger.error("moveIssue: failed to save issue: " + issue, e);
617  0 return null;
618    }
619  0 if (logger.isDebugEnabled()) {
620  0 logger.debug("moveIssue: saved move-issue to " + project);
621    }
622  0 return issue;
623   
624    }
625   
626    /**
627    * this should not exist. adding an history entry should be adding the
628    * history entry to the domain object and saving the object...
629    */
 
630  0 toggle public boolean addIssueHistory(IssueHistory history) {
631  0 getIssueHistoryDAO().saveOrUpdate(history);
632  0 history.getIssue().getHistory().add(history);
633  0 getIssueDAO().saveOrUpdate(history.getIssue());
634  0 return true;
635    }
636   
637    /**
638    * TODO maybe it has no use at all. is it obsolete? when I'd set the
639    * issue-fields on an issue and then save/update issue, would it be good
640    * enough?
641    */
 
642  0 toggle public boolean setIssueFields(Integer issueId, List<IssueField> fields) {
643  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
644   
645  0 setIssueFields(issue, fields, true);
646   
647  0 return true;
648    }
649   
 
650  0 toggle private boolean setIssueFields(Issue issue, List<IssueField> fields,
651    boolean save) {
652   
653  0 List<IssueField> issueFields = issue.getFields();
654   
655  0 if (fields.size() > 0) {
656  0 for (int i = 0; i < fields.size(); i++) {
657   
658  0 IssueField field = fields.get(i);
659  0 if (issueFields.contains(field)) {
660  0 issueFields.remove(field);
661    }
662   
663  0 CustomField customField = getCustomFieldDAO().findByPrimaryKey(
664    fields.get(i).getCustomField().getId());
665  0 field.setCustomField(customField);
666  0 field.setIssue(issue);
667   
668    // what date value?
669    // field.setDateValue(new Timestamp(new Date().getTime()));
670  0 issueFields.add(field);
671    }
672    }
673  0 issue.setFields(issueFields);
674   
675  0 if (save) {
676  0 logger.debug("setIssueFields: save was true");
677  0 getIssueDAO().saveOrUpdate(issue);
678    }
679  0 return true;
680    }
681   
 
682  0 toggle public boolean setIssueComponents(Integer issueId,
683    HashSet<Integer> componentIds, Integer userId) {
684   
685  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
686  0 List<Component> components = new ArrayList<Component>(componentIds
687    .size());
688  0 User user = userDAO.findByPrimaryKey(userId);
689  0 Iterator<Integer> idIt = componentIds.iterator();
690  0 while (idIt.hasNext()) {
691  0 Integer id = (Integer) idIt.next();
692  0 Component c = getComponentDAO().findById(id);
693  0 components.add(c);
694    }
695   
696  0 setIssueComponents(issue, components, user, true);
697  0 return true;
698    }
699   
 
700  0 toggle private boolean setIssueComponents(Issue issue, List<Component> components,
701    User user, boolean save) {
702   
703  0 if (issue.getComponents() == null) {
704  0 if (logger.isInfoEnabled()) {
705  0 logger.info("setIssueComponents: components was null");
706    }
707  0 issue.setComponents(new ArrayList<Component>(components.size()));
708    }
709  0 if (components.isEmpty() && !issue.getComponents().isEmpty()) {
710  0 addComponentsModifiedActivity(issue, user, new StringBuilder(
711    ITrackerResources.getString("itracker.web.generic.all"))
712    .append(" ").append(
713    ITrackerResources
714    .getString("itracker.web.generic.removed"))
715    .toString());
716  0 issue.getComponents().clear();
717    } else {
718  0 Collections.sort(issue.getComponents(), Component.NAME_COMPARATOR);
719   
720  0 for (Iterator<Component> iterator = issue.getComponents()
721  0 .iterator(); iterator.hasNext();) {
722  0 Component component = (Component) iterator.next();
723  0 if (components.contains(component)) {
724  0 components.remove(component);
725    } else {
726  0 addComponentsModifiedActivity(issue, user,
727    new StringBuilder(ITrackerResources
728    .getString("itracker.web.generic.removed"))
729    .append(": ").append(component.getName())
730    .toString());
731  0 iterator.remove();
732    }
733    }
734  0 Collections.sort(components, Component.NAME_COMPARATOR);
735  0 for (Iterator<Component> iterator = components.iterator(); iterator
736    .hasNext();) {
737   
738  0 Component component = iterator.next();
739  0 if (!issue.getComponents().contains(component)) {
740  0 addComponentsModifiedActivity(issue, user,
741    new StringBuilder(ITrackerResources
742    .getString("itracker.web.generic.added"))
743    .append(": ").append(component.getName())
744    .toString());
745  0 issue.getComponents().add(component);
746    }
747    }
748    }
749   
750  0 if (save) {
751  0 if (logger.isDebugEnabled()) {
752  0 logger.debug("setIssueComponents: save was true");
753    }
754  0 getIssueDAO().saveOrUpdate(issue);
755    }
756  0 return true;
757   
758    }
759   
760    /**
761    * used by setIssueComponents for adding change activities
762    *
763    * @param issue
764    * @param user
765    * @param description
766    */
 
767  0 toggle private void addComponentsModifiedActivity(Issue issue, User user,
768    String description) {
769  0 IssueActivity activity = new IssueActivity();
770  0 activity
771    .setActivityType(org.itracker.model.IssueActivityType.COMPONENTS_MODIFIED);
772  0 activity.setDescription(description);
773  0 activity.setIssue(issue);
774  0 activity.setUser(user);
775  0 issue.getActivities().add(activity);
776    }
777   
 
778  0 toggle private boolean setIssueVersions(Issue issue, List<Version> versions,
779    User user, boolean save) {
780   
781  0 if (issue.getVersions() == null) {
782  0 if (logger.isInfoEnabled()) {
783  0 logger.info("setIssueVersions: versions were null!");
784    }
785  0 issue.setVersions(new ArrayList<Version>());
786    }
787   
788  0 if (versions.isEmpty() && !issue.getVersions().isEmpty()) {
789   
790  0 addVersionsModifiedActivity(issue, user, new StringBuilder(
791    ITrackerResources.getString("itracker.web.generic.all"))
792    .append(" ").append(
793    ITrackerResources
794    .getString("itracker.web.generic.removed"))
795    .toString());
796  0 issue.getVersions().clear();
797    } else {
798   
799  0 Collections.sort(issue.getVersions(), Version.VERSION_COMPARATOR);
800   
801  0 StringBuilder changesBuf = new StringBuilder();
802  0 for (Iterator<Version> iterator = issue.getVersions().iterator(); iterator
803    .hasNext();) {
804   
805  0 Version version = iterator.next();
806  0 if (versions.contains(version)) {
807  0 versions.remove(version);
808    } else {
809  0 if (changesBuf.length() > 0) {
810  0 changesBuf.append(", ");
811    }
812  0 changesBuf.append(version.getNumber());
813  0 iterator.remove();
814    }
815    }
816   
817  0 if (changesBuf.length() > 0) {
818  0 addVersionsModifiedActivity(issue, user, new StringBuilder(
819    ITrackerResources
820    .getString("itracker.web.generic.removed"))
821    .append(": ").append(changesBuf).toString());
822    }
823   
824  0 changesBuf = new StringBuilder();
825   
826  0 Collections.sort(versions, Version.VERSION_COMPARATOR);
827  0 for (Iterator<Version> iterator = versions.iterator(); iterator
828    .hasNext();) {
829   
830  0 Version version = iterator.next();
831  0 if (changesBuf.length() > 0) {
832  0 changesBuf.append(", ");
833    }
834  0 changesBuf.append(version.getNumber());
835  0 issue.getVersions().add(version);
836    }
837  0 if (changesBuf.length() > 0) {
838  0 addVersionsModifiedActivity(issue, user, new StringBuilder(
839    ITrackerResources
840    .getString("itracker.web.generic.added"))
841    .append(": ").append(changesBuf).toString());
842    }
843    }
844  0 if (save) {
845  0 if (logger.isDebugEnabled()) {
846  0 logger.debug("setIssueVersions: updating issue: " + issue);
847    }
848  0 getIssueDAO().saveOrUpdate(issue);
849    }
850   
851  0 return true;
852    }
853   
854    /**
855    * used by setIssueComponents for adding change activities
856    *
857    * @param issue
858    * @param user
859    * @param description
860    */
 
861  0 toggle private void addVersionsModifiedActivity(Issue issue, User user,
862    String description) {
863  0 IssueActivity activity = new IssueActivity();
864  0 activity
865    .setActivityType(org.itracker.model.IssueActivityType.TARGETVERSION_CHANGE);
866  0 activity.setDescription(description);
867  0 activity.setIssue(issue);
868  0 activity.setUser(user);
869  0 issue.getActivities().add(activity);
870    }
871   
 
872  0 toggle public boolean setIssueVersions(Integer issueId,
873    HashSet<Integer> versionIds, Integer userId) {
874   
875  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
876  0 User user = userDAO.findByPrimaryKey(userId);
877    // load versions from ids
878  0 ArrayList<Version> versions = new ArrayList<Version>(versionIds.size());
879  0 Iterator<Integer> versionsIdIt = versionIds.iterator();
880  0 while (versionsIdIt.hasNext()) {
881  0 Integer id = versionsIdIt.next();
882  0 versions.add(getVersionDAO().findByPrimaryKey(id));
883    }
884   
885  0 return setIssueVersions(issue, versions, user, true);
886    }
887   
 
888  0 toggle public IssueRelation getIssueRelation(Integer relationId) {
889   
890  0 IssueRelation issueRelation = getIssueRelationDAO().findByPrimaryKey(
891    relationId);
892   
893  0 return issueRelation;
894   
895    }
896   
897    /**
898    * add a relation between two issues.
899    *
900    * TODO: There is no relation saved to database yet?
901    */
 
902  0 toggle public boolean addIssueRelation(Integer issueId, Integer relatedIssueId,
903    int relationType, Integer userId) {
904   
905  0 User user = getUserDAO().findByPrimaryKey(userId);
906   
907  0 if (null == user) {
908  0 throw new IllegalArgumentException("Invalid user-id: " + userId);
909    }
910   
911  0 if (issueId != null && relatedIssueId != null) {
912   
913  0 int matchingRelationType = IssueUtilities
914    .getMatchingRelationType(relationType);
915   
916    // if(matchingRelationType < 0) {
917   
918    // throw new CreateException("Unable to find matching relation type
919   
920    // for type: " + relationType);
921   
922    // }
923   
924  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
925   
926  0 Issue relatedIssue = getIssueDAO().findByPrimaryKey(relatedIssueId);
927   
928  0 IssueRelation relationA = new IssueRelation();
929   
930  0 relationA.setRelationType(relationType);
931   
932    // relationA.setMatchingRelationId(relationBId);
933   
934  0 relationA.setIssue(issue);
935   
936  0 relationA.setRelatedIssue(relatedIssue);
937   
938    // set to 0 first, later reassign to relationB.id
939  0 relationA.setMatchingRelationId(0);
940   
941  0 relationA.setLastModifiedDate(new java.sql.Timestamp(new Date()
942    .getTime()));
943   
944  0 getIssueRelationDAO().saveOrUpdate(relationA);
945   
946  0 IssueRelation relationB = new IssueRelation();
947   
948  0 relationB.setRelationType(matchingRelationType);
949   
950    // relationB.setMatchingRelationId(relationAId);
951   
952  0 relationB.setIssue(relatedIssue);
953   
954  0 relationB.setRelatedIssue(issue);
955   
956  0 relationB.setMatchingRelationId(relationA.getId());
957   
958  0 relationB.setLastModifiedDate(new java.sql.Timestamp(new Date()
959    .getTime()));
960   
961  0 getIssueRelationDAO().saveOrUpdate(relationB);
962   
963  0 relationA.setMatchingRelationId(relationB.getId());
964  0 getIssueRelationDAO().saveOrUpdate(relationA);
965   
966  0 IssueActivity activity = new IssueActivity();
967  0 activity
968    .setActivityType(org.itracker.model.IssueActivityType.RELATION_ADDED);
969  0 activity.setDescription(ITrackerResources.getString(
970    "itracker.activity.relation.add", new Object[] {
971    IssueUtilities.getRelationName(relationType),
972    relatedIssueId }));
973   
974  0 activity.setIssue(issue);
975  0 issue.getActivities().add(activity);
976    // need to set user here
977  0 activity.setUser(user);
978    // need to save here
979  0 getIssueDAO().saveOrUpdate(issue);
980   
981  0 activity = new IssueActivity();
982  0 activity
983    .setActivityType(org.itracker.model.IssueActivityType.RELATION_ADDED);
984  0 activity.setDescription(ITrackerResources.getString(
985    "itracker.activity.relation.add", new Object[] {
986    IssueUtilities
987    .getRelationName(matchingRelationType),
988    issueId }));
989  0 activity.setIssue(relatedIssue);
990  0 activity.setUser(user);
991  0 relatedIssue.getActivities().add(activity);
992  0 getIssueDAO().saveOrUpdate(relatedIssue);
993  0 return true;
994   
995    }
996   
997  0 return false;
998   
999    }
1000   
 
1001  0 toggle public void removeIssueRelation(Integer relationId, Integer userId) {
1002  0 IssueRelation issueRelation = getIssueRelationDAO().findByPrimaryKey(
1003    relationId);
1004  0 Integer issueId = issueRelation.getIssue().getId();
1005   
1006  0 Integer relatedIssueId = issueRelation.getRelatedIssue().getId();
1007   
1008  0 Integer matchingRelationId = issueRelation.getMatchingRelationId();
1009   
1010  0 if (matchingRelationId != null) {
1011  0 IssueActivity activity = new IssueActivity();
1012  0 activity
1013    .setActivityType(org.itracker.model.IssueActivityType.RELATION_REMOVED);
1014  0 activity.setDescription(ITrackerResources.getString(
1015    "itracker.activity.relation.removed", issueId.toString()));
1016    // FIXME need to fix the commented code and save
1017    // activity.setIssue(relatedIssueId);
1018    // activity.setUser(userId);
1019    // IssueRelationDAO.remove(matchingRelationId);
1020    }
1021   
1022  0 IssueActivity activity = new IssueActivity();
1023  0 activity
1024    .setActivityType(org.itracker.model.IssueActivityType.RELATION_REMOVED);
1025  0 activity.setDescription(ITrackerResources
1026    .getString("itracker.activity.relation.removed", relatedIssueId
1027    .toString()));
1028    // activity.setIssue(issueId);
1029    // activity.setUser(userId);
1030    // irHome.remove(relationId);
1031    // need to save
1032   
1033  0 getIssueRelationDAO().delete(issueRelation);
1034    }
1035   
 
1036  0 toggle public boolean assignIssue(Integer issueId, Integer userId) {
1037  0 return assignIssue(issueId, userId, userId);
1038    }
1039   
1040    /**
1041    * only use for updating issue from actions..
1042    */
 
1043  0 toggle public boolean assignIssue(Integer issueId, Integer userId,
1044    Integer assignedByUserId) {
1045   
1046  0 return assignIssue(getIssueDAO().findByPrimaryKey(issueId),
1047    getUserDAO().findByPrimaryKey(userId), getUserDAO()
1048    .findByPrimaryKey(assignedByUserId), true);
1049    }
1050   
1051    /**
1052    * Only for use
1053    *
1054    * @param issueId
1055    * @param userId
1056    * @param assignedByUserId
1057    * @param save
1058    * save issue and send notification
1059    * @return
1060    */
 
1061  0 toggle private boolean assignIssue(Issue issue, User user, User assignedByUser,
1062    final boolean save) {
1063   
1064  0 if (issue.getOwner() == user
1065    || (null != issue.getOwner() && issue.getOwner().equals(user))) {
1066    // nothing to do.
1067  0 if (logger.isDebugEnabled()) {
1068  0 logger.debug("assignIssue: attempted to reassign " + issue
1069    + " to current owner " + user);
1070    }
1071  0 return false;
1072    }
1073   
1074  0 if (null == user) {
1075  0 if (logger.isInfoEnabled()) {
1076  0 logger.info("assignIssue: call to unasign " + issue);
1077    }
1078   
1079  0 return unassignIssue(issue, assignedByUser, save);
1080    }
1081   
1082  0 if (logger.isInfoEnabled()) {
1083  0 logger.info("assignIssue: assigning " + issue + " to " + user);
1084    }
1085   
1086  0 User currOwner = issue.getOwner();
1087   
1088  0 if (!user.equals(currOwner)) {
1089  0 if (currOwner != null
1090    && !notificationService.hasIssueNotification(issue,
1091    currOwner.getId(), Role.IP)) {
1092    // Notification notification = new Notification();
1093  0 Notification notification = new Notification(currOwner, issue,
1094    Role.IP);
1095  0 if (save) {
1096  0 notificationService.addIssueNotification(notification);
1097    } else {
1098  0 issue.getNotifications().add(notification);
1099    }
1100    }
1101   
1102  0 IssueActivity activity = new IssueActivity();
1103  0 activity
1104    .setActivityType(org.itracker.model.IssueActivityType.OWNER_CHANGE);
1105  0 activity.setDescription((currOwner == null ? "["
1106    + ITrackerResources
1107    .getString("itracker.web.generic.unassigned") + "]"
1108    : currOwner.getLogin())
1109    + " "
1110    + ITrackerResources.getString("itracker.web.generic.to")
1111    + " " + user.getLogin());
1112  0 activity.setUser(assignedByUser);
1113  0 activity.setIssue(issue);
1114  0 issue.getActivities().add(activity);
1115   
1116  0 issue.setOwner(user);
1117   
1118  0 if (logger.isDebugEnabled()) {
1119  0 logger.debug("assignIssue: current status: "
1120    + issue.getStatus());
1121    }
1122  0 if (issue.getStatus() < IssueUtilities.STATUS_ASSIGNED) {
1123  0 issue.setStatus(IssueUtilities.STATUS_ASSIGNED);
1124  0 if (logger.isDebugEnabled()) {
1125  0 logger.debug("assignIssue: new status set to "
1126    + issue.getStatus());
1127    }
1128    }
1129   
1130    // send assignment notification
1131    // TODO: configurationService should be set from context
1132  0 if (save) {
1133  0 if (logger.isDebugEnabled()) {
1134  0 logger.debug("assignIssue: saving re-assigned issue");
1135    }
1136  0 getIssueDAO().saveOrUpdate(issue);
1137  0 notificationService.sendNotification(issue, Type.ASSIGNED,
1138    ServletContextUtils.getItrackerServices()
1139    .getConfigurationService().getSystemBaseURL());
1140   
1141    }
1142    }
1143  0 return true;
1144   
1145    }
1146   
1147    /**
1148    *
1149    * @param issue
1150    * @param unassignedByUser
1151    * @param save
1152    * save issue and send notification
1153    * @return
1154    */
 
1155  0 toggle private boolean unassignIssue(Issue issue, User unassignedByUser,
1156    boolean save) {
1157  0 if (logger.isDebugEnabled()) {
1158  0 logger.debug("unassignIssue: " + issue);
1159    }
1160  0 if (issue.getOwner() != null) {
1161   
1162  0 if (logger.isDebugEnabled()) {
1163  0 logger.debug("unassignIssue: unassigning from "
1164    + issue.getOwner());
1165    }
1166  0 if (!notificationService.hasIssueNotification(issue, issue
1167    .getOwner().getId(), Role.CONTRIBUTER)) {
1168    // Notification notification = new Notification();
1169  0 Notification notification = new Notification(issue.getOwner(),
1170    issue, Role.CONTRIBUTER);
1171  0 if (save) {
1172  0 notificationService.addIssueNotification(notification);
1173    } else {
1174  0 issue.getNotifications().add(notification);
1175    }
1176    }
1177  0 IssueActivity activity = new IssueActivity(issue, unassignedByUser,
1178    IssueActivityType.OWNER_CHANGE);
1179  0 activity
1180    .setDescription(issue.getOwner().getLogin()
1181    + " "
1182    + ITrackerResources
1183    .getString("itracker.web.generic.to")
1184    + " ["
1185    + ITrackerResources
1186    .getString("itracker.web.generic.unassigned")
1187    + "]");
1188   
1189  0 issue.setOwner(null);
1190   
1191  0 if (issue.getStatus() >= IssueUtilities.STATUS_ASSIGNED) {
1192  0 issue.setStatus(IssueUtilities.STATUS_UNASSIGNED);
1193    }
1194  0 if (save) {
1195  0 if (logger.isDebugEnabled()) {
1196  0 logger.debug("unassignIssue: saving unassigned issue..");
1197    }
1198  0 getIssueDAO().saveOrUpdate(issue);
1199  0 notificationService.sendNotification(issue, Type.ASSIGNED,
1200    ServletContextUtils.getItrackerServices()
1201    .getConfigurationService().getSystemBaseURL());
1202    }
1203    }
1204   
1205  0 return true;
1206    }
1207   
1208    /**
1209    * System-Update an issue, adds the action to the issue and updates the
1210    * issue
1211    */
 
1212  0 toggle public Issue systemUpdateIssue(Issue updateissue, Integer userId)
1213    throws ProjectException {
1214   
1215  0 IssueActivity activity = new IssueActivity();
1216  0 activity.setActivityType(IssueActivityType.SYSTEM_UPDATE);
1217  0 activity.setDescription(ITrackerResources
1218    .getString("itracker.activity.system.status"));
1219  0 ArrayList<IssueActivity> activities = new ArrayList<IssueActivity>();
1220   
1221  0 activity.setIssue(updateissue);
1222  0 activity.setUser(getUserDAO().findByPrimaryKey(userId));
1223  0 updateissue.getActivities().add(activity);
1224   
1225  0 Issue updated = updateIssue(updateissue, userId);
1226  0 updated.getActivities().addAll(activities);
1227  0 getIssueDAO().saveOrUpdate(updated);
1228   
1229  0 return updated;
1230    }
1231   
1232    /*
1233    * public boolean addIssueActivity(IssueActivityModel model) {
1234    *
1235    * Issue issue = ifHome.findByPrimaryKey(model.getIssueId());
1236    *
1237    * User user = ufHome.findByPrimaryKey(model.getUserId());
1238    *
1239    * //return addIssueActivity(model, issue, user); return
1240    * addIssueActivity(null, issue, user); }
1241    */
1242   
1243    /*
1244    * public boolean addIssueActivity(IssueActivityModel model, Issue issue) {
1245    *
1246    * User user = ufHome.findByPrimaryKey(model.getUserId());
1247    *
1248    * return true;//addIssueActivity(model, issue, user); }
1249    */
1250   
1251    /**
1252    * I think this entire method is useless - RJST TODO move to
1253    * {@link NotificationService}
1254    *
1255    * @param model
1256    * @param issue
1257    * @param user
1258    * @return
1259    */
1260    /*
1261    * public boolean addIssueActivity(IssueActivityBean model, Issue issue,
1262    * User user) {
1263    *
1264    * IssueActivityBean activity = new IssueActivityBean();
1265    *
1266    * //activity.setModel(model);
1267    *
1268    * activity.setIssue(issue);
1269    *
1270    * activity.setUser(user);
1271    *
1272    * return true; }
1273    */
1274   
 
1275  0 toggle public void updateIssueActivityNotification(Integer issueId,
1276    boolean notificationSent) {
1277   
1278  0 if (issueId == null) {
1279   
1280  0 return;
1281   
1282    }
1283   
1284  0 Collection<IssueActivity> activity = getIssueActivityDAO()
1285    .findByIssueId(issueId);
1286   
1287  0 for (Iterator<IssueActivity> iter = activity.iterator(); iter.hasNext();) {
1288   
1289  0 ((IssueActivity) iter.next()).setNotificationSent(notificationSent);
1290   
1291    }
1292   
1293    }
1294   
1295    /**
1296    * Adds an attachment to an issue
1297    *
1298    * @param model
1299    * The attachment data
1300    * @param data
1301    * The byte data
1302    */
 
1303  0 toggle public boolean addIssueAttachment(IssueAttachment attachment, byte[] data) {
1304  0 Issue issue = attachment.getIssue();
1305    // User user = attachment.getUser();
1306   
1307  0 attachment.setFileName("attachment_issue_" + issue.getId() + "_"
1308    + attachment.getOriginalFileName());
1309  0 attachment.setFileData((data == null ? new byte[0] : data));
1310   
1311    // attachment.setIssue(issue);
1312    // attachment.setUser(user);
1313   
1314    // TODO: activity for adding attachment?
1315    // IssueActivity activityAdd = new IssueActivity(attachment.getIssue(),
1316    // user, IssueActivity.Type.ATTACHEMENT_ADDED)
1317   
1318  0 if (logger.isDebugEnabled()) {
1319  0 logger.debug("addIssueAttachment: adding attachment " + attachment);
1320    }
1321    // add attachment to issue
1322  0 issue.getAttachments().add(attachment);
1323  0 if (logger.isDebugEnabled()) {
1324  0 logger.debug("addIssueAttachment: saving updated issue " + issue);
1325    }
1326  0 this.getIssueDAO().saveOrUpdate(issue);
1327  0 return true;
1328    }
1329   
 
1330  0 toggle public boolean setIssueAttachmentData(Integer attachmentId, byte[] data) {
1331   
1332  0 if (attachmentId != null && data != null) {
1333   
1334  0 IssueAttachment attachment = getIssueAttachmentDAO()
1335    .findByPrimaryKey(attachmentId);
1336   
1337  0 attachment.setFileData(data);
1338   
1339  0 return true;
1340   
1341    }
1342   
1343  0 return false;
1344   
1345    }
1346   
 
1347  0 toggle public boolean setIssueAttachmentData(String fileName, byte[] data) {
1348   
1349  0 if (fileName != null && data != null) {
1350   
1351  0 IssueAttachment attachment = getIssueAttachmentDAO()
1352    .findByFileName(fileName);
1353   
1354  0 attachment.setFileData(data);
1355   
1356  0 return true;
1357   
1358    }
1359   
1360  0 return false;
1361   
1362    }
1363   
1364    /**
1365    * Removes a attachement (deletes it)
1366    *
1367    * @param attachmentId
1368    * the id of the <code>IssueAttachmentBean</code>
1369    */
 
1370  0 toggle public boolean removeIssueAttachment(Integer attachmentId) {
1371   
1372  0 IssueAttachment attachementBean = this.getIssueAttachmentDAO()
1373    .findByPrimaryKey(attachmentId);
1374   
1375  0 getIssueAttachmentDAO().delete(attachementBean);
1376   
1377  0 return true;
1378    }
1379   
 
1380  0 toggle public Integer removeIssueHistoryEntry(Integer entryId, Integer userId) {
1381   
1382  0 IssueHistory history = getIssueHistoryDAO().findByPrimaryKey(entryId);
1383   
1384  0 if (history != null) {
1385   
1386  0 history.setStatus(IssueUtilities.HISTORY_STATUS_REMOVED);
1387   
1388    // moved date stuff to BaseHibernateDAO
1389    // history.setLastModifiedDate(new Timestamp(new Date().getTime()));
1390   
1391  0 IssueActivity activity = new IssueActivity();
1392  0 activity
1393    .setActivityType(org.itracker.model.IssueActivityType.REMOVE_HISTORY);
1394  0 activity.setDescription(ITrackerResources
1395    .getString("itracker.web.generic.entry")
1396    + " "
1397    + entryId
1398    + " "
1399    + ITrackerResources
1400    .getString("itracker.web.generic.removed") + ".");
1401   
1402  0 getIssueHistoryDAO().delete(history);
1403   
1404    // need to fix this - RJST
1405    // activity.setIssue(history.getIssue().getId());
1406    // activity.setUser(userId);
1407  0 return history.getIssue().getId();
1408   
1409    }
1410   
1411  0 return Integer.valueOf(-1);
1412   
1413    }
1414   
 
1415  0 toggle public Project getIssueProject(Integer issueId) {
1416  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
1417  0 Project project = issue.getProject();
1418   
1419  0 return project;
1420    }
1421   
 
1422  0 toggle public HashSet<Integer> getIssueComponentIds(Integer issueId) {
1423   
1424  0 HashSet<Integer> componentIds = new HashSet<Integer>();
1425  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
1426  0 Collection<Component> components = issue.getComponents();
1427   
1428  0 for (Iterator<Component> iterator = components.iterator(); iterator
1429    .hasNext();) {
1430  0 componentIds.add(((Component) iterator.next()).getId());
1431    }
1432   
1433  0 return componentIds;
1434   
1435    }
1436   
 
1437  0 toggle public HashSet<Integer> getIssueVersionIds(Integer issueId) {
1438   
1439  0 HashSet<Integer> versionIds = new HashSet<Integer>();
1440   
1441  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
1442   
1443  0 Collection<Version> versions = issue.getVersions();
1444   
1445  0 for (Iterator<Version> iterator = versions.iterator(); iterator
1446    .hasNext();) {
1447   
1448  0 versionIds.add(((Version) iterator.next()).getId());
1449   
1450    }
1451   
1452  0 return versionIds;
1453   
1454    }
1455   
 
1456  0 toggle public List<IssueActivity> getIssueActivity(Integer issueId) {
1457   
1458  0 int i = 0;
1459   
1460  0 Collection<IssueActivity> activity = getIssueActivityDAO()
1461    .findByIssueId(issueId);
1462   
1463  0 IssueActivity[] activityArray = new IssueActivity[activity.size()];
1464   
1465  0 for (Iterator<IssueActivity> iterator = activity.iterator(); iterator
1466    .hasNext(); i++) {
1467   
1468  0 activityArray[i] = ((IssueActivity) iterator.next());
1469   
1470    }
1471   
1472  0 return Arrays.asList(activityArray);
1473   
1474    }
1475   
1476    /**
1477    * TODO move to {@link NotificationService} ?
1478    */
 
1479  0 toggle public List<IssueActivity> getIssueActivity(Integer issueId,
1480    boolean notificationSent) {
1481   
1482  0 int i = 0;
1483   
1484  0 Collection<IssueActivity> activity = getIssueActivityDAO()
1485    .findByIssueIdAndNotification(issueId, notificationSent);
1486   
1487  0 IssueActivity[] activityArray = new IssueActivity[activity.size()];
1488   
1489  0 for (Iterator<IssueActivity> iterator = activity.iterator(); iterator
1490    .hasNext(); i++) {
1491   
1492  0 activityArray[i] = ((IssueActivity) iterator.next());
1493   
1494    }
1495   
1496  0 return Arrays.asList(activityArray);
1497   
1498    }
1499   
 
1500  0 toggle public Long getAllIssueAttachmentCount() {
1501  0 return getIssueAttachmentDAO().countAll().longValue();
1502    }
1503   
1504    /**
1505    * @deprecated do not use this due to expensive memory use! use explicit
1506    * hsqldb queries instead.
1507    */
 
1508  0 toggle public List<IssueAttachment> getAllIssueAttachments() {
1509  0 logger.warn("getAllIssueAttachments: use of deprecated API");
1510  0 if (logger.isDebugEnabled()) {
1511  0 logger.debug("getAllIssueAttachments: stacktrace was",
1512    new RuntimeException());
1513    }
1514   
1515  0 List<IssueAttachment> attachments = getIssueAttachmentDAO().findAll();
1516   
1517  0 return attachments;
1518    }
1519   
 
1520  0 toggle public IssueAttachment getIssueAttachment(Integer attachmentId) {
1521  0 IssueAttachment attachment = getIssueAttachmentDAO().findByPrimaryKey(
1522    attachmentId);
1523   
1524  0 return attachment;
1525   
1526    }
1527   
 
1528  0 toggle public byte[] getIssueAttachmentData(Integer attachmentId) {
1529   
1530  0 byte[] data;
1531   
1532  0 IssueAttachment attachment = getIssueAttachmentDAO().findByPrimaryKey(
1533    attachmentId);
1534   
1535  0 data = attachment.getFileData();
1536   
1537  0 return data;
1538   
1539    }
1540   
 
1541  0 toggle public int getIssueAttachmentCount(Integer issueId) {
1542   
1543  0 int i = 0;
1544   
1545  0 Issue issue = getIssueDAO().findByPrimaryKey(issueId);
1546   
1547  0 Collection<IssueAttachment> attachments = issue.getAttachments();
1548   
1549  0 i = attachments.size();
1550   
1551  0 return i;
1552   
1553    }
1554   
1555    /**
1556    *
1557    * Returns the latest issue history entry for a particular issue.
1558    *
1559    *
1560    *
1561    * @param issueId
1562    *
1563    * the id of the issue to return the history entry for.
1564    *
1565    * @return the latest IssueHistory, or null if no entries could be found
1566    */
 
1567  0 toggle public IssueHistory getLastIssueHistory(Integer issueId) {
1568   
1569  0 List<IssueHistory> history = getIssueHistoryDAO()
1570    .findByIssueId(issueId);
1571   
1572  0 if (null != history && history.size() > 0) {
1573    // sort ascending by id
1574  0 Collections.sort(history, AbstractEntity.ID_COMPARATOR);
1575    // return last entry in list
1576  0 return history.get(history.size() - 1);
1577    }
1578   
1579  0 return null;
1580   
1581    }
1582   
 
1583  0 toggle public int getOpenIssueCountByProjectId(Integer projectId) {
1584   
1585  0 Collection<Issue> issues = getIssueDAO().findByProjectAndLowerStatus(
1586    projectId, IssueUtilities.STATUS_RESOLVED);
1587   
1588  0 return issues.size();
1589   
1590    }
1591   
 
1592  0 toggle public int getResolvedIssueCountByProjectId(Integer projectId) {
1593   
1594  0 Collection<Issue> issues = getIssueDAO().findByProjectAndHigherStatus(
1595    projectId, IssueUtilities.STATUS_RESOLVED);
1596   
1597  0 return issues.size();
1598   
1599    }
1600   
 
1601  0 toggle public int getTotalIssueCountByProjectId(Integer projectId) {
1602   
1603  0 Collection<Issue> issues = getIssueDAO().findByProject(projectId);
1604   
1605  0 return issues.size();
1606   
1607    }
1608   
 
1609  0 toggle public Date getLatestIssueDateByProjectId(Integer projectId) {
1610   
1611  0 return getIssueDAO().latestModificationDate(projectId);
1612   
1613    }
1614   
 
1615  0 toggle public boolean canViewIssue(Integer issueId, User user) {
1616   
1617  0 Issue issue = getIssue(issueId);
1618   
1619  0 Map<Integer, Set<PermissionType>> permissions = getUserDAO()
1620    .getUsersMapOfProjectsAndPermissionTypes(user);
1621   
1622  0 return IssueUtilities.canViewIssue(issue, user.getId(), permissions);
1623   
1624    }
1625   
 
1626  0 toggle public boolean canViewIssue(Issue issue, User user) {
1627   
1628  0 Map<Integer, Set<PermissionType>> permissions = getUserDAO()
1629    .getUsersMapOfProjectsAndPermissionTypes(user);
1630   
1631  0 return IssueUtilities.canViewIssue(issue, user.getId(), permissions);
1632   
1633    }
1634   
 
1635  0 toggle private UserDAO getUserDAO() {
1636  0 return userDAO;
1637    }
1638   
 
1639  0 toggle private IssueDAO getIssueDAO() {
1640  0 return issueDAO;
1641    }
1642   
 
1643  0 toggle private ProjectDAO getProjectDAO() {
1644  0 return projectDAO;
1645    }
1646   
 
1647  0 toggle private IssueActivityDAO getIssueActivityDAO() {
1648  0 return issueActivityDAO;
1649    }
1650   
 
1651  0 toggle private VersionDAO getVersionDAO() {
1652  0 return this.versionDAO;
1653    }
1654   
 
1655  0 toggle private ComponentDAO getComponentDAO() {
1656  0 return this.componentDAO;
1657    }
1658   
 
1659  0 toggle private CustomFieldDAO getCustomFieldDAO() {
1660  0 return customFieldDAO;
1661    }
1662   
 
1663  0 toggle private IssueHistoryDAO getIssueHistoryDAO() {
1664  0 return issueHistoryDAO;
1665    }
1666   
 
1667  0 toggle private IssueRelationDAO getIssueRelationDAO() {
1668  0 return issueRelationDAO;
1669    }
1670   
 
1671  0 toggle private IssueAttachmentDAO getIssueAttachmentDAO() {
1672  0 return issueAttachmentDAO;
1673    }
1674   
1675    /**
1676    * get total size of all attachments in database
1677    */
 
1678  0 toggle public Long getAllIssueAttachmentSize() {
1679   
1680  0 return getIssueAttachmentDAO().totalAttachmentsSize().longValue() / 1024;
1681   
1682    }
1683   
 
1684  0 toggle public List<Issue> searchIssues(IssueSearchQuery queryModel, User user,
1685    Map<Integer, Set<PermissionType>> userPermissions)
1686    throws IssueSearchException {
1687  0 return getIssueDAO().query(queryModel, user, userPermissions);
1688    }
1689   
 
1690  0 toggle public Long totalSystemIssuesAttachmentSize() {
1691  0 return getIssueAttachmentDAO().totalAttachmentsSize();
1692    }
1693   
1694    }