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