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 java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Date;
25 import java.util.HashSet;
26 import java.util.Hashtable;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Set;
32
33 import javax.mail.internet.InternetAddress;
34
35 import org.apache.log4j.Logger;
36 import org.itracker.core.resources.ITrackerResources;
37 import org.itracker.model.Component;
38 import org.itracker.model.Issue;
39 import org.itracker.model.IssueActivity;
40 import org.itracker.model.IssueHistory;
41 import org.itracker.model.Notification;
42 import org.itracker.model.Project;
43 import org.itracker.model.User;
44 import org.itracker.model.Version;
45 import org.itracker.model.Notification.Role;
46 import org.itracker.model.Notification.Type;
47 import org.itracker.persistence.dao.IssueActivityDAO;
48 import org.itracker.persistence.dao.IssueDAO;
49 import org.itracker.persistence.dao.NotificationDAO;
50 import org.itracker.services.IssueService;
51 import org.itracker.services.NotificationService;
52 import org.itracker.services.ProjectService;
53 import org.itracker.services.util.EmailService;
54 import org.itracker.services.util.HTMLUtilities;
55 import org.itracker.services.util.IssueUtilities;
56 import org.itracker.services.util.ProjectUtilities;
57 import org.itracker.services.util.UserUtilities;
58 import org.itracker.web.util.ServletContextUtils;
59
60 public class NotificationServiceImpl implements NotificationService {
61
62
63
64 private EmailService emailService;
65 private NotificationDAO notificationDao;
66 private ProjectService projectService;
67 private IssueActivityDAO issueActivityDao;
68 private IssueDAO issueDao;
69
70 private static final Logger logger = Logger
71 .getLogger(NotificationServiceImpl.class);
72
73 public NotificationServiceImpl() {
74
75 this.emailService = null;
76 this.projectService = null;
77 this.notificationDao = null;
78 }
79
80 public NotificationServiceImpl(EmailService emailService,
81 ProjectService projectService, NotificationDAO notificationDao, IssueActivityDAO issueActivityDao, IssueDAO issueDao) {
82 this();
83 this.setEmailService(emailService);
84 this.setProjectService(projectService);
85 this.setNotificationDao(notificationDao);
86 this.setIssueActivityDao(issueActivityDao);
87 this.setIssueDao(issueDao);
88 }
89
90 public void sendNotification(Notification notification, Type type,
91 String url) {
92
93 if (logger.isDebugEnabled()) {
94 logger.debug("sendNotification: called with notification: "
95 + notification + ", type: " + url + ", url: " + url);
96 }
97 if (null == notification) {
98 throw new IllegalArgumentException("notification must not be null");
99 }
100 if (null == this.emailService || null == this.notificationDao) {
101 throw new IllegalStateException("service not initialized yet");
102 }
103 if (type == Type.SELF_REGISTER) {
104 this.handleSelfRegistrationNotification(notification.getUser()
105 .getLogin(), notification.getUser().getEmailAddress(), url);
106 } else {
107 handleIssueNotification(notification.getIssue(), type, url);
108
109 }
110
111 }
112
113 public void sendNotification(Issue issue, Type type, String baseURL) {
114 if (logger.isDebugEnabled()) {
115 logger.debug("sendNotification: called with issue: " + issue
116 + ", type: " + type + ", baseURL: " + baseURL);
117 }
118 handleIssueNotification(issue, type, baseURL);
119
120 }
121
122 public void setEmailService(EmailService emailService) {
123
124 if (null == emailService)
125 throw new IllegalArgumentException("email service must not be null");
126
127 if (null != this.emailService) {
128 throw new IllegalStateException("email service allready set");
129 }
130 this.emailService = emailService;
131
132 }
133
134
135
136
137
138
139 private void handleSelfRegistrationNotification(String login,
140 InternetAddress toAddress, String url) {
141 if (logger.isDebugEnabled()) {
142 logger
143 .debug("handleSelfRegistrationNotification: called with login: "
144 + login
145 + ", toAddress"
146 + toAddress
147 + ", url: "
148 + url);
149 }
150 try {
151
152 if (toAddress != null && !"".equals(toAddress.getAddress())) {
153 String subject = ITrackerResources
154 .getString("itracker.email.selfreg.subject");
155 String msgText = ITrackerResources.getString(
156 "itracker.email.selfreg.body", ITrackerResources
157 .getDefaultLocale(), new Object[] { login,
158 url + "/login.do" });
159 emailService.sendEmail(toAddress, subject, msgText);
160 } else {
161 throw new IllegalArgumentException(
162 "To-address must be set for self registration notification.");
163 }
164 } catch (RuntimeException e) {
165 logger.error("failed to handle self registration notification for "
166 + toAddress, e);
167 throw e;
168 }
169 }
170
171
172
173
174
175
176
177
178 private void handleIssueNotification(Issue issue, Type type, String url) {
179
180 if (logger.isDebugEnabled()) {
181 logger.debug("handleIssueNotification: called with issue: " + issue
182 + ", type: " + type + "url: " + url);
183 }
184 this.handleIssueNotification(issue, type, url, null, null);
185 }
186
187
188
189
190
191
192
193
194 private void handleIssueNotification(Issue issue, Type type, String url,
195 InternetAddress[] receipients, Integer lastModifiedDays) {
196 try {
197
198 if (logger.isDebugEnabled()) {
199 logger
200 .debug("handleIssueNotificationhandleIssueNotification: called with issue: "
201 + issue
202 + ", type: "
203 + type
204 + "url: "
205 + url
206 + ", receipients: "
207 + (null == receipients ? "<null>" : String
208 .valueOf(Arrays.asList(receipients)))
209 + ", lastModifiedDays: " + lastModifiedDays);
210 }
211 List<Notification> notifications;
212
213 if (issue == null) {
214 logger
215 .warn("handleIssueNotification: issue was null. Notification will not be handled");
216 return;
217 }
218
219 if (lastModifiedDays == null || lastModifiedDays.intValue() < 0) {
220 lastModifiedDays = Integer
221 .valueOf(org.itracker.web.scheduler.tasks.ReminderNotification.DEFAULT_ISSUE_AGE);
222 }
223
224 if (receipients == null) {
225 ArrayList<InternetAddress> recList = new ArrayList<InternetAddress>();
226 notifications = this.getIssueNotifications(issue);
227 Iterator<Notification> it = notifications.iterator();
228 User currentUser;
229 while (it.hasNext()) {
230 currentUser = it.next().getUser();
231 if (null != currentUser
232 && null != currentUser.getEmailAddress()
233 && null != currentUser.getEmail()
234 && (!recList
235 .contains(currentUser.getEmailAddress()))
236 && currentUser.getEmail().indexOf('@') >= 0) {
237
238 recList.add(currentUser.getEmailAddress());
239 }
240 }
241 receipients = recList.toArray(new InternetAddress[] {});
242 }
243
244 List<IssueActivity> activity = getIssueService().getIssueActivity(
245 issue.getId(), false);
246 issue.getActivities();
247 List<IssueHistory> histories = issue.getHistory();
248 Iterator<IssueHistory> it = histories.iterator();
249 IssueHistory history = null, currentHistory;
250 history = getIssueService().getLastIssueHistory(issue.getId());
251
252 Integer historyId = 0;
253
254 while (it.hasNext()) {
255 currentHistory = (IssueHistory) it.next();
256 if (logger.isDebugEnabled()) {
257 logger.debug("handleIssueNotification: found history: "
258 + currentHistory.getDescription() + " (time: "
259 + currentHistory.getCreateDate());
260 }
261 if (currentHistory.getId() > historyId) {
262 historyId = currentHistory.getId();
263 history = currentHistory;
264 }
265 }
266 if (logger.isDebugEnabled() && null != history) {
267 logger
268 .debug("handleIssueNotification: got most recent history: "
269 + history
270 + " ("
271 + history.getDescription()
272 + ")");
273 }
274
275 List<Component> components = issue.getComponents();
276
277
278
279 List<Version> versions = issue.getVersions();
280
281
282 if (receipients.length > 0) {
283 String subject = "";
284 if (type == Type.CREATED) {
285 subject = ITrackerResources.getString(
286 "itracker.email.issue.subject.created",
287 new Object[] { issue.getId(),
288 issue.getProject().getName(),
289 lastModifiedDays });
290 } else if (type == Type.ASSIGNED) {
291 subject = ITrackerResources.getString(
292 "itracker.email.issue.subject.assigned",
293 new Object[] { issue.getId(),
294 issue.getProject().getName(),
295 lastModifiedDays });
296 } else if (type == Type.CLOSED) {
297 subject = ITrackerResources.getString(
298 "itracker.email.issue.subject.closed",
299 new Object[] { issue.getId(),
300 issue.getProject().getName(),
301 lastModifiedDays });
302 } else if (type == Type.ISSUE_REMINDER) {
303 subject = ITrackerResources.getString(
304 "itracker.email.issue.subject.reminder",
305 new Object[] { issue.getId(),
306 issue.getProject().getName(),
307 lastModifiedDays });
308 } else {
309 subject = ITrackerResources.getString(
310 "itracker.email.issue.subject.updated",
311 new Object[] { issue.getId(),
312 issue.getProject().getName(),
313 lastModifiedDays });
314 }
315
316 String activityString;
317 String componentString = "";
318 String versionString = "";
319 StringBuffer sb = new StringBuffer();
320 for (int i = 0; i < activity.size(); i++) {
321 sb.append(
322 IssueUtilities.getActivityName(activity.get(i)
323 .getActivityType())).append(": ").append(
324 activity.get(i).getDescription()).append("\n");
325
326 }
327 activityString = sb.toString();
328 for (int i = 0; i < components.size(); i++) {
329 componentString += (i != 0 ? ", " : "")
330 + components.get(i).getName();
331 }
332 for (int i = 0; i < versions.size(); i++) {
333 versionString += (i != 0 ? ", " : "")
334 + versions.get(i).getNumber();
335 }
336
337 String msgText = "";
338 if (type == Type.ISSUE_REMINDER) {
339 msgText = ITrackerResources
340 .getString(
341 "itracker.email.issue.body.reminder",
342 new Object[] {
343 url
344 + "/module-projects/view_issue.do?id="
345 + issue.getId(),
346 issue.getProject().getName(),
347 issue.getDescription(),
348 IssueUtilities.getStatusName(issue
349 .getStatus()),
350 IssueUtilities
351 .getSeverityName(issue
352 .getSeverity()),
353 (issue.getOwner().getFirstName() != null ? issue
354 .getOwner().getFirstName()
355 : "")
356 + " "
357 + (issue.getOwner()
358 .getLastName() != null ? issue
359 .getOwner()
360 .getLastName()
361 : ""),
362 componentString,
363 (history == null ? "" : history
364 .getUser().getFirstName()
365 + " "
366 + history.getUser()
367 .getLastName()),
368 (history == null ? ""
369 : HTMLUtilities
370 .removeMarkup(history
371 .getDescription())),
372 lastModifiedDays, activityString });
373 } else {
374 String resolution = (issue.getResolution() == null ? ""
375 : issue.getResolution());
376 if (!resolution.equals("")
377 && ProjectUtilities
378 .hasOption(
379 ProjectUtilities.OPTION_PREDEFINED_RESOLUTIONS,
380 issue.getProject().getOptions())) {
381 resolution = IssueUtilities.getResolutionName(
382 resolution, ITrackerResources.getLocale());
383 }
384
385 msgText = ITrackerResources
386 .getString(
387 "itracker.email.issue.body.standard",
388 new Object[] {
389 new StringBuffer(url).append("/module-projects/view_issue.do?id=").append(issue.getId()).toString(),
390 issue.getProject().getName(),
391 issue.getDescription(),
392 IssueUtilities.getStatusName(issue
393 .getStatus()),
394 resolution,
395 IssueUtilities
396 .getSeverityName(issue
397 .getSeverity()),
398 (null != issue.getOwner() && null != issue.getOwner().getFirstName() ? issue
399 .getOwner().getFirstName()
400 : "")
401 + " "
402 + (null != issue.getOwner() && null != issue.getOwner()
403 .getLastName() ? issue
404 .getOwner()
405 .getLastName()
406 : ""),
407 componentString,
408 (history == null ? "" : history
409 .getUser().getFirstName()
410 + " "
411 + history.getUser()
412 .getLastName()),
413 (history == null ? ""
414 : HTMLUtilities
415 .removeMarkup(history
416 .getDescription())),
417 activityString });
418 }
419 emailService.sendEmail(receipients, subject, msgText);
420
421 updateIssueActivityNotification(issue, true);
422 }
423
424 } catch (Exception e) {
425 logger
426 .error(
427 "handleIssueNotification: unexpected exception caught, throwing runtime exception",
428 e);
429 throw new RuntimeException(e);
430 }
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445 @SuppressWarnings("unused")
446 private void handleLocalizedIssueNotification(final Issue issue, final Type type, final String url,
447 final InternetAddress[] receipients, Integer lastModifiedDays) {
448 try {
449
450 if (logger.isDebugEnabled()) {
451 logger
452 .debug("handleIssueNotificationhandleIssueNotification: running as thread, called with issue: "
453 + issue
454 + ", type: "
455 + type
456 + "url: "
457 + url
458 + ", receipients: "
459 + (null == receipients ? "<null>" : String
460 .valueOf(Arrays.asList(receipients)))
461 + ", lastModifiedDays: " + lastModifiedDays);
462 }
463
464 final Integer notModifiedSince;
465
466 if (lastModifiedDays == null || lastModifiedDays.intValue() < 0) {
467 notModifiedSince = Integer
468 .valueOf(org.itracker.web.scheduler.tasks.ReminderNotification.DEFAULT_ISSUE_AGE);
469 } else {
470 notModifiedSince = lastModifiedDays;
471 }
472
473 try {
474 if (logger.isDebugEnabled()) {
475 logger
476 .debug("handleIssueNotificationhandleIssueNotification.run: running as thread, called with issue: "
477 + issue
478 + ", type: "
479 + type
480 + "url: "
481 + url
482 + ", receipients: "
483 + (null == receipients ? "<null>" : String
484 .valueOf(Arrays.asList(receipients)))
485 + ", notModifiedSince: " + notModifiedSince);
486 }
487 final List<Notification> notifications;
488 if (issue == null) {
489 logger
490 .warn("handleIssueNotification: issue was null. Notification will not be handled");
491 return;
492 }
493 Map<InternetAddress, Locale> localeMapping = null;
494
495 if (receipients == null) {
496
497
498 notifications = this.getIssueNotifications(issue);
499
500 localeMapping = new Hashtable<InternetAddress, Locale>(notifications.size());
501 Iterator<Notification> it = notifications.iterator();
502 User currentUser;
503 while (it.hasNext()) {
504 currentUser = it.next().getUser();
505 if (null != currentUser
506 && null != currentUser.getEmailAddress()
507 && null != currentUser.getEmail()
508 && (!localeMapping.keySet()
509 .contains(currentUser.getEmailAddress()))) {
510
511 try {
512 localeMapping.put(currentUser.getEmailAddress(), ITrackerResources.getLocale(currentUser.getPreferences().getUserLocale()));
513 } catch (RuntimeException re) {
514 localeMapping.put(currentUser.getEmailAddress(), ITrackerResources.getLocale());
515 }
516 }
517 }
518 } else {
519 localeMapping = new Hashtable<InternetAddress, Locale>(1);
520 Locale locale = ITrackerResources.getLocale();
521 Iterator<InternetAddress> it = Arrays.asList(receipients).iterator();
522 while (it.hasNext()) {
523 InternetAddress internetAddress = (InternetAddress) it
524 .next();
525 localeMapping.put(internetAddress, locale);
526 }
527 }
528
529 this.handleNotification(issue, type, notModifiedSince, localeMapping, url);
530 } catch (Exception e) {
531 logger.error("run: failed to process notification", e);
532 }
533
534 } catch (Exception e) {
535 logger
536 .error(
537 "handleIssueNotification: unexpected exception caught, throwing runtime exception",
538 e);
539 throw new RuntimeException(e);
540 }
541 }
542
543
544
545
546
547
548
549
550
551 private void handleNotification(Issue issue, Type type, Integer notModifiedSince, Map<InternetAddress, Locale> recipientsLocales, final String url) {
552 Set<InternetAddress> recipients = recipientsLocales.keySet();
553 Map<Locale, Set<InternetAddress>> localeRecipients = new Hashtable<Locale, Set<InternetAddress>>();
554
555 List<Component> components = issue.getComponents();
556 List<Version> versions = issue.getVersions();
557
558 List<IssueActivity> activity = getIssueService().getIssueActivity(
559 issue.getId(), false);
560 issue.getActivities();
561 List<IssueHistory> histories = issue.getHistory();
562 Iterator<IssueHistory> it = histories.iterator();
563 IssueHistory history = null, currentHistory;
564 history = getIssueService().getLastIssueHistory(issue.getId());
565
566 Integer historyId = 0;
567
568 while (it.hasNext()) {
569 currentHistory = (IssueHistory) it.next();
570 if (logger.isDebugEnabled()) {
571 logger.debug("handleIssueNotification: found history: "
572 + currentHistory.getDescription() + " (time: "
573 + currentHistory.getCreateDate());
574 }
575 if (currentHistory.getId() > historyId) {
576 historyId = currentHistory.getId();
577 history = currentHistory;
578 }
579 }
580 if (logger.isDebugEnabled() && null != history) {
581 logger
582 .debug("handleIssueNotification: got most recent history: "
583 + history
584 + " ("
585 + history.getDescription()
586 + ")");
587 }
588
589 Iterator<InternetAddress> iaIt = recipientsLocales.keySet().iterator();
590 while (iaIt.hasNext()) {
591 InternetAddress internetAddress = (InternetAddress) iaIt.next();
592 if (localeRecipients.keySet().contains(recipientsLocales.get(internetAddress))) {
593 localeRecipients.get(recipientsLocales.get(internetAddress)).add(internetAddress);
594 } else {
595 Set<InternetAddress> addresses = new HashSet<InternetAddress>();
596 localeRecipients.put(recipientsLocales.get(internetAddress), addresses);
597 }
598 }
599
600 Iterator<Locale> localesIt = localeRecipients.keySet().iterator();
601 try {
602 while (localesIt.hasNext()) {
603 Locale currentLocale = (Locale) localesIt.next();
604 recipients = localeRecipients.get(currentLocale);
605
606
607 if (recipients.size() > 0) {
608 String subject = "";
609 if (type == Type.CREATED) {
610 subject = ITrackerResources.getString(
611 "itracker.email.issue.subject.created",
612 currentLocale,
613 new Object[] { issue.getId(),
614 issue.getProject().getName(),
615 notModifiedSince });
616 } else if (type == Type.ASSIGNED) {
617 subject = ITrackerResources.getString(
618 "itracker.email.issue.subject.assigned",
619 currentLocale,
620 new Object[] { issue.getId(),
621 issue.getProject().getName(),
622 notModifiedSince });
623 } else if (type == Type.CLOSED) {
624 subject = ITrackerResources.getString(
625 "itracker.email.issue.subject.closed",
626 currentLocale,
627 new Object[] { issue.getId(),
628 issue.getProject().getName(),
629 notModifiedSince });
630 } else if (type == Type.ISSUE_REMINDER) {
631 subject = ITrackerResources.getString(
632 "itracker.email.issue.subject.reminder",
633 currentLocale,
634 new Object[] { issue.getId(),
635 issue.getProject().getName(),
636 notModifiedSince });
637 } else {
638 subject = ITrackerResources.getString(
639 "itracker.email.issue.subject.updated",
640 currentLocale,
641 new Object[] { issue.getId(),
642 issue.getProject().getName(),
643 notModifiedSince });
644 }
645
646 String activityString;
647 String componentString = "";
648 String versionString = "";
649 StringBuffer sb = new StringBuffer();
650 for (int i = 0; i < activity.size(); i++) {
651 sb.append(
652 IssueUtilities.getActivityName(activity.get(i)
653 .getActivityType(), currentLocale)).append(": ").append(
654 activity.get(i).getDescription()).append("\n");
655
656 }
657
658 activityString = sb.toString();
659
660 for (int i = 0; i < components.size(); i++) {
661 componentString += (i != 0 ? ", " : "")
662 + components.get(i).getName();
663 }
664 for (int i = 0; i < versions.size(); i++) {
665 versionString += (i != 0 ? ", " : "")
666 + versions.get(i).getNumber();
667 }
668
669 String msgText = "";
670 if (type == Type.ISSUE_REMINDER) {
671 msgText = ITrackerResources
672 .getString(
673 "itracker.email.issue.body.reminder",
674 currentLocale,
675 new Object[] {
676 url
677 + "/module-projects/view_issue.do?id="
678 + issue.getId(),
679 issue.getProject().getName(),
680 issue.getDescription(),
681 IssueUtilities.getStatusName(issue
682 .getStatus()),
683 IssueUtilities
684 .getSeverityName(issue
685 .getSeverity()),
686 (issue.getOwner().getFirstName() != null ? issue
687 .getOwner().getFirstName()
688 : "")
689 + " "
690 + (issue.getOwner()
691 .getLastName() != null ? issue
692 .getOwner()
693 .getLastName()
694 : ""),
695 componentString,
696 (history == null ? "" : history
697 .getUser().getFirstName()
698 + " "
699 + history.getUser()
700 .getLastName()),
701 (history == null ? ""
702 : HTMLUtilities
703 .removeMarkup(history
704 .getDescription())),
705 notModifiedSince, activityString });
706 } else {
707 String resolution = (issue.getResolution() == null ? ""
708 : issue.getResolution());
709 if (!resolution.equals("")
710 && ProjectUtilities
711 .hasOption(
712 ProjectUtilities.OPTION_PREDEFINED_RESOLUTIONS,
713 issue.getProject().getOptions())) {
714 resolution = IssueUtilities.getResolutionName(
715 resolution, ITrackerResources.getLocale());
716 }
717
718 msgText = ITrackerResources
719 .getString(
720 "itracker.email.issue.body.standard",
721 currentLocale,
722 new Object[] {
723 new StringBuffer(url).append("/module-projects/view_issue.do?id=").append(issue.getId()).toString(),
724 issue.getProject().getName(),
725 issue.getDescription(),
726 IssueUtilities.getStatusName(issue
727 .getStatus()),
728 resolution,
729 IssueUtilities
730 .getSeverityName(issue
731 .getSeverity()),
732 (null != issue.getOwner() && null != issue.getOwner().getFirstName() ? issue
733 .getOwner().getFirstName()
734 : "")
735 + " "
736 + (null != issue.getOwner() && null != issue.getOwner()
737 .getLastName() ? issue
738 .getOwner()
739 .getLastName()
740 : ""),
741 componentString,
742 (history == null ? "" : history
743 .getUser().getFirstName()
744 + " "
745 + history.getUser()
746 .getLastName()),
747 (history == null ? ""
748 : HTMLUtilities
749 .removeMarkup(history
750 .getDescription())),
751 activityString });
752 }
753
754 if (logger.isInfoEnabled()) {
755 logger.info(new StringBuilder("handleNotification: sending notification for ").append(issue).append(" (").append(type).append(") to ").append(currentLocale).append("-users (").append(recipients + ")").toString());
756
757 }
758
759 emailService.sendEmail(recipients, subject, msgText);
760
761 if (logger.isDebugEnabled()) {
762 logger.debug("handleNotification: sent notification for " + issue);
763 }
764 }
765
766 updateIssueActivityNotification(issue, true);
767 if (logger.isDebugEnabled()) {
768 logger.debug("handleNotification: sent notification for locales " + localeRecipients.keySet() + " recipients: " + localeRecipients.values());
769 }
770 }
771 } catch (RuntimeException e) {
772 logger.error("handleNotification: failed to notify: " + issue + " (locales: " + localeRecipients.keySet() + ")", e);
773
774 }
775
776
777 }
778 private IssueService getIssueService() {
779 return ServletContextUtils.getItrackerServices().getIssueService();
780 }
781
782 public void updateIssueActivityNotification(Issue issue,
783 Boolean notificationSent) {
784 if (logger.isDebugEnabled()) {
785 logger.debug("updateIssueActivityNotification: called with "
786 + issue + ", notificationSent: " + notificationSent);
787 }
788
789 Collection<IssueActivity> activity = getIssueActivityDao()
790 .findByIssueId(issue.getId());
791
792 for (Iterator<IssueActivity> iter = activity.iterator(); iter.hasNext();) {
793
794 ((IssueActivity) iter.next()).setNotificationSent(notificationSent);
795
796 }
797 }
798
799
800
801 public boolean addIssueNotification(Notification notification) {
802 if (logger.isDebugEnabled()) {
803 logger.debug("addIssueNotification: called with notification: "
804 + notification);
805 }
806 Issue issue = notification.getIssue();
807 if (!issue.getNotifications().contains(notification)) {
808 if (notification.getCreateDate() == null) {
809 notification.setCreateDate(new Date());
810 }
811 if (notification.getLastModifiedDate() == null) {
812 notification.setLastModifiedDate(new Date());
813 }
814
815
816
817
818
819 getNotificationDao().save(notification);
820
821 issue.getNotifications().add(notification);
822 getIssueDao().merge(issue);
823
824 return true;
825 }
826 if (logger.isDebugEnabled()) {
827 logger.debug("addIssueNotification: attempted to add duplicate notification " + notification + " for issue: " + issue);
828 }
829 return false;
830 }
831
832
833
834
835 public List<Notification> getIssueNotifications(Issue issue,
836 boolean primaryOnly, boolean activeOnly) {
837 if (logger.isDebugEnabled()) {
838 logger.debug("getIssueNotifications: called with issue: " + issue
839 + ", primaryOnly: " + primaryOnly + ", activeOnly: "
840 + activeOnly);
841 }
842 List<Notification> issueNotifications = new ArrayList<Notification>();
843 if (issue == null) {
844 logger.warn("getIssueNotifications: no issue, throwing exception");
845 throw new IllegalArgumentException("issue must not be null");
846 }
847 if (!primaryOnly) {
848 List<Notification> notifications = getNotificationDao()
849 .findByIssueId(issue.getId());
850
851 for (Iterator<Notification> iterator = notifications.iterator(); iterator
852 .hasNext();) {
853 Notification notification = iterator.next();
854 User notificationUser = notification.getUser();
855
856 if (!activeOnly
857 || notificationUser.getStatus() == UserUtilities.STATUS_ACTIVE) {
858 issueNotifications.add(notification);
859 }
860 }
861 }
862
863
864
865
866 boolean hasOwner = false;
867
868 if (issue != null) {
869 if (issue.getOwner() != null) {
870 User ownerModel = issue.getOwner();
871
872 if (ownerModel != null
873 && (!activeOnly || ownerModel.getStatus() == UserUtilities.STATUS_ACTIVE)) {
874 issueNotifications.add(new Notification(ownerModel, issue,
875 Role.OWNER));
876 hasOwner = true;
877 }
878 }
879
880 if (!primaryOnly || !hasOwner) {
881 User creatorModel = issue.getCreator();
882
883 if (creatorModel != null
884 && (!activeOnly || creatorModel.getStatus() == UserUtilities.STATUS_ACTIVE)) {
885 issueNotifications.add(new Notification(creatorModel,
886 issue, Role.CREATOR));
887 }
888 }
889
890 Project project = getProjectService().getProject(
891 issue.getProject().getId());
892 Collection<User> projectOwners = project.getOwners();
893
894 for (Iterator<User> iterator = projectOwners.iterator(); iterator
895 .hasNext();) {
896 User projectOwner = (User) iterator.next();
897
898 if (projectOwner != null
899 && (!activeOnly || projectOwner.getStatus() == UserUtilities.STATUS_ACTIVE)) {
900 issueNotifications.add(new Notification(projectOwner,
901 issue, Role.PO));
902 }
903 }
904 }
905
906 if (logger.isDebugEnabled()) {
907 logger.debug("getIssueNotifications: returning "
908 + issueNotifications);
909 }
910 return issueNotifications;
911 }
912
913 public List<Notification> getIssueNotifications(Issue issue) {
914 if (logger.isDebugEnabled()) {
915 logger.debug("getIssueNotifications: called with: " + issue);
916 }
917 return this.getIssueNotifications(issue, false, true);
918 }
919
920 public List<Notification> getPrimaryIssueNotifications(Issue issue) {
921 if (logger.isDebugEnabled()) {
922 logger.debug("getPrimaryIssueNotifications: called with: " + issue);
923 }
924 return this.getIssueNotifications(issue, true, false);
925 }
926
927 public boolean hasIssueNotification(Issue issue, Integer userId) {
928 if (logger.isDebugEnabled()) {
929 logger.debug("hasIssueNotification: called with: " + issue
930 + ", userId: " + userId);
931 }
932 return hasIssueNotification(issue, userId, Role.ANY);
933 }
934
935
936
937
938
939
940
941 public boolean hasIssueNotification(Issue issue, Integer userId, Role role) {
942
943 if (issue != null && userId != null) {
944
945 List<Notification> notifications = getIssueNotifications(issue,
946 false, false);
947
948 for (int i = 0; i < notifications.size(); i++) {
949
950 if (role == Role.ANY || notifications.get(i).getRole() == role) {
951
952 if (notifications.get(i).getUser().getId().equals(userId)) {
953
954 return true;
955
956 }
957
958 }
959
960 }
961
962 }
963
964 return false;
965
966 }
967
968 public boolean removeIssueNotification(Integer notificationId) {
969 Notification notification = this.getNotificationDao().findById(
970 notificationId);
971 getNotificationDao().delete(notification);
972 return true;
973 }
974
975 public void sendNotification(Issue issue, Type type, String baseURL,
976 InternetAddress[] receipients, Integer lastModifiedDays) {
977 this.handleIssueNotification(issue, type, baseURL, receipients,
978 lastModifiedDays);
979
980 }
981
982
983
984
985
986
987 public EmailService getEmailService() {
988 return emailService;
989 }
990
991
992
993
994 private NotificationDAO getNotificationDao() {
995 return notificationDao;
996 }
997
998
999
1000
1001 public ProjectService getProjectService() {
1002 return projectService;
1003 }
1004
1005
1006
1007
1008
1009 public void setProjectService(ProjectService projectService) {
1010 this.projectService = projectService;
1011 }
1012
1013
1014
1015
1016
1017 public void setNotificationDao(NotificationDAO notificationDao) {
1018 if (null == notificationDao) {
1019 throw new IllegalArgumentException(
1020 "notification dao must not be null");
1021 }
1022 if (null != this.notificationDao) {
1023 throw new IllegalStateException("notification dao allready set");
1024 }
1025 this.notificationDao = notificationDao;
1026 }
1027
1028
1029
1030
1031
1032
1033
1034
1035 public void sendNotification(Integer notificationId, Type type, String url) {
1036
1037 Notification notification = notificationDao.findById(notificationId);
1038 this.sendNotification(notification, type, url);
1039
1040 }
1041
1042
1043
1044
1045 public IssueActivityDAO getIssueActivityDao() {
1046 return issueActivityDao;
1047 }
1048
1049
1050
1051
1052
1053 public void setIssueActivityDao(IssueActivityDAO issueActivityDao) {
1054 this.issueActivityDao = issueActivityDao;
1055 }
1056
1057
1058
1059
1060 public IssueDAO getIssueDao() {
1061 return issueDao;
1062 }
1063
1064
1065
1066
1067
1068 public void setIssueDao(IssueDAO issueDao) {
1069 this.issueDao = issueDao;
1070 }
1071
1072 }