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