1 package org.apache.maven.continuum.notification.mail;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.continuum.model.project.ProjectScmRoot;
23 import org.apache.maven.continuum.Continuum;
24 import org.apache.maven.continuum.configuration.ConfigurationService;
25 import org.apache.maven.continuum.execution.ExecutorConfigurator;
26 import org.apache.maven.continuum.execution.ant.AntBuildExecutor;
27 import org.apache.maven.continuum.execution.maven.m1.MavenOneBuildExecutor;
28 import org.apache.maven.continuum.execution.maven.m2.MavenTwoBuildExecutor;
29 import org.apache.maven.continuum.installation.InstallationException;
30 import org.apache.maven.continuum.installation.InstallationService;
31 import org.apache.maven.continuum.model.project.BuildDefinition;
32 import org.apache.maven.continuum.model.project.BuildResult;
33 import org.apache.maven.continuum.model.project.Project;
34 import org.apache.maven.continuum.model.project.ProjectDeveloper;
35 import org.apache.maven.continuum.model.project.ProjectGroup;
36 import org.apache.maven.continuum.model.project.ProjectNotifier;
37 import org.apache.maven.continuum.model.scm.ChangeSet;
38 import org.apache.maven.continuum.model.scm.ScmResult;
39 import org.apache.maven.continuum.model.system.Installation;
40 import org.apache.maven.continuum.model.system.Profile;
41 import org.apache.maven.continuum.notification.AbstractContinuumNotifier;
42 import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
43 import org.apache.maven.continuum.notification.MessageContext;
44 import org.apache.maven.continuum.notification.NotificationException;
45 import org.apache.maven.continuum.project.ContinuumProjectState;
46 import org.apache.maven.continuum.reports.surefire.ReportTestResult;
47 import org.apache.maven.continuum.reports.surefire.ReportTestSuiteGenerator;
48 import org.apache.velocity.VelocityContext;
49 import org.apache.velocity.exception.ResourceNotFoundException;
50 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
51 import org.codehaus.plexus.util.StringUtils;
52 import org.codehaus.plexus.velocity.VelocityComponent;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.mail.javamail.JavaMailSender;
56
57 import java.io.StringWriter;
58 import java.io.UnsupportedEncodingException;
59 import java.net.InetAddress;
60 import java.net.UnknownHostException;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.Date;
64 import java.util.HashMap;
65 import java.util.HashSet;
66 import java.util.List;
67 import java.util.Map;
68 import java.util.Set;
69 import javax.mail.Message;
70 import javax.mail.MessagingException;
71 import javax.mail.internet.AddressException;
72 import javax.mail.internet.InternetAddress;
73 import javax.mail.internet.MimeMessage;
74
75
76
77
78
79 public class MailContinuumNotifier
80 extends AbstractContinuumNotifier
81 implements Initializable
82 {
83 private static final Logger log = LoggerFactory.getLogger( MailContinuumNotifier.class );
84
85
86
87
88
89
90
91
92 private VelocityComponent velocity;
93
94
95
96
97 private ConfigurationService configurationService;
98
99
100
101
102 private Continuum continuum;
103
104
105
106
107 private JavaMailSender javaMailSender;
108
109
110
111
112 private ReportTestSuiteGenerator reportTestSuiteGenerator;
113
114
115
116
117
118
119
120
121 private String fromMailbox;
122
123
124
125
126 private String fromName;
127
128
129
130
131 private String toOverride;
132
133
134
135
136 private String timestampFormat;
137
138
139
140
141 private boolean includeBuildSummary = true;
142
143
144
145
146 private boolean includeTestSummary = true;
147
148
149
150
151 private boolean includeBuildOutput = false;
152
153
154
155
156
157
158
159
160
161
162
163 private String buildSubjectFormat = "[continuum] BUILD ${state}: ${project.groupId} ${project.name}";
164
165
166
167
168
169
170 private String prepareBuildSubjectFormat =
171 "[continuum] PREPARE BUILD ${state]: ${projectScmRoot.projectGroup.name}";
172
173
174
175
176
177 private String buildHost;
178
179 private FormatterTool formatterTool;
180
181
182
183
184
185 private static final String FALLBACK_FROM_MAILBOX = "continuum@localhost";
186
187
188
189
190
191 public void initialize()
192 {
193 try
194 {
195 InetAddress address = InetAddress.getLocalHost();
196
197 buildHost = StringUtils.clean( address.getHostName() );
198
199 if ( buildHost == null )
200 {
201 buildHost = "localhost";
202 }
203 }
204 catch ( UnknownHostException ex )
205 {
206 fromName = "Continuum";
207 }
208
209
210
211
212
213 if ( StringUtils.isEmpty( fromMailbox ) )
214 {
215 log.info( "The from mailbox is not configured, will use the nag email address from the project." );
216
217 fromMailbox = null;
218 }
219 else
220 {
221 log.info( "Using '" + fromMailbox + "' as the from mailbox for all emails." );
222 }
223
224 if ( StringUtils.isEmpty( fromName ) )
225 {
226 fromName = "Continuum@" + buildHost;
227 }
228
229 log.info( "From name: " + fromName );
230
231 log.info( "Build host name: " + buildHost );
232
233
234
235
236
237 formatterTool = new FormatterTool( timestampFormat );
238 }
239
240
241
242
243
244 public String getType()
245 {
246 return "mail";
247 }
248
249 public void sendMessage( String messageId, MessageContext context )
250 throws NotificationException
251 {
252 Project project = context.getProject();
253 List<ProjectNotifier> notifiers = context.getNotifiers();
254 BuildResult build = context.getBuildResult();
255
256 if ( build != null )
257 {
258 log.error( "br state=" + build.getState() );
259 }
260
261 if ( project != null )
262 {
263 log.error( "project state=" + project.getState() );
264 }
265
266 BuildDefinition buildDefinition = context.getBuildDefinition();
267 ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
268
269 boolean isPrepareBuildComplete = messageId.equals(
270 ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE );
271
272 if ( projectScmRoot == null && isPrepareBuildComplete )
273 {
274 return;
275 }
276
277
278
279
280
281 if ( build == null && !isPrepareBuildComplete )
282 {
283 return;
284 }
285
286
287
288
289
290 if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_COMPLETE ) )
291 {
292 buildComplete( project, notifiers, build, messageId, context, buildDefinition );
293 }
294 else if ( isPrepareBuildComplete )
295 {
296 prepareBuildComplete( projectScmRoot, notifiers, messageId, context );
297 }
298 }
299
300 private void buildComplete( Project project, List<ProjectNotifier> notifiers, BuildResult build, String messageId,
301 MessageContext context, BuildDefinition buildDefinition )
302 throws NotificationException
303 {
304 BuildResult previousBuild = getPreviousBuild( project, buildDefinition, build );
305
306 List<ProjectNotifier> notifiersList = new ArrayList<ProjectNotifier>();
307 for ( ProjectNotifier notifier : notifiers )
308 {
309
310
311
312
313 if ( shouldNotify( build, previousBuild, notifier ) )
314 {
315 notifiersList.add( notifier );
316 }
317 }
318 buildComplete( project, notifiersList, build, previousBuild, messageId, context, buildDefinition );
319 }
320
321 private void buildComplete( Project project, List<ProjectNotifier> notifiers, BuildResult build,
322 BuildResult previousBuild, String messageId, MessageContext messageContext,
323 BuildDefinition buildDefinition )
324 throws NotificationException
325 {
326
327
328
329
330 String packageName = getClass().getPackage().getName().replace( '.', '/' );
331
332 String templateName = packageName + "/templates/" + project.getExecutorId() + "/" + messageId + ".vm";
333
334 StringWriter writer = new StringWriter();
335
336 String content;
337
338 try
339 {
340 VelocityContext context = new VelocityContext();
341
342 context.put( "includeTestSummary", includeTestSummary );
343
344 context.put( "includeOutput", includeBuildOutput );
345
346 if ( includeBuildOutput )
347 {
348 context.put( "buildOutput", getBuildOutput( project, build ) );
349 }
350
351 if ( includeBuildSummary )
352 {
353 context.put( "build", build );
354
355 ReportTestResult reportTestResult = reportTestSuiteGenerator.generateReportTestResult( build.getId(),
356 project.getId() );
357
358 context.put( "testResult", reportTestResult );
359
360 context.put( "project", project );
361
362 context.put( "changesSinceLastSuccess", continuum.getChangesSinceLastSuccess( project.getId(),
363 build.getId() ) );
364
365 context.put( "previousBuild", previousBuild );
366
367
368
369
370
371 context.put( "formatter", formatterTool );
372
373
374
375 context.put( "buildHost", buildHost );
376
377 String osName = System.getProperty( "os.name" );
378
379 String osPatchLevel = System.getProperty( "sun.os.patch.level" );
380
381 if ( osPatchLevel != null )
382 {
383 osName = osName + "(" + osPatchLevel + ")";
384 }
385
386 context.put( "osName", osName );
387
388 context.put( "javaVersion", System.getProperty( "java.version" ) + "(" + System.getProperty(
389 "java.vendor" ) + ")" );
390
391
392 context.put( "javaHomeInformations", getJavaHomeInformations( buildDefinition ) );
393
394 context.put( "builderVersions", getBuilderVersion( buildDefinition, project ) );
395 }
396
397
398
399
400
401 context.put( "reportUrl", getReportUrl( project, build, configurationService ) );
402
403
404
405
406
407
408
409 velocity.getEngine().mergeTemplate( templateName, context, writer );
410
411 content = writer.getBuffer().toString();
412 }
413 catch ( ResourceNotFoundException e )
414 {
415 log.info( "No such template: '" + templateName + "'." );
416
417 return;
418 }
419 catch ( Exception e )
420 {
421 throw new NotificationException( "Error while generating mail contents.", e );
422 }
423
424
425
426
427
428 String subject;
429 try
430 {
431 subject = generateSubject( project, build );
432 }
433 catch ( Exception e )
434 {
435 throw new NotificationException( "Error while generating mail subject.", e );
436 }
437
438 sendMessage( project, notifiers, subject, content, messageContext );
439 }
440
441 private void prepareBuildComplete( ProjectScmRoot projectScmRoot, List<ProjectNotifier> notifiers, String messageId,
442 MessageContext messageContext )
443 throws NotificationException
444 {
445
446
447
448
449 String packageName = getClass().getPackage().getName().replace( '.', '/' );
450
451 String templateName = packageName + "/templates/" + messageId + ".vm";
452
453 StringWriter writer = new StringWriter();
454
455 String content;
456
457 try
458 {
459 VelocityContext context = new VelocityContext();
460
461
462
463
464
465 context.put( "reportUrl", getReportUrl( projectScmRoot.getProjectGroup(), projectScmRoot,
466 configurationService ) );
467
468 context.put( "projectScmRoot", projectScmRoot );
469
470
471
472
473
474
475
476 velocity.getEngine().mergeTemplate( templateName, context, writer );
477
478 content = writer.getBuffer().toString();
479 }
480 catch ( ResourceNotFoundException e )
481 {
482 log.info( "No such template: '" + templateName + "'." );
483
484 return;
485 }
486 catch ( Exception e )
487 {
488 throw new NotificationException( "Error while generating mail contents.", e );
489 }
490
491
492
493
494
495 String subject;
496 try
497 {
498 subject = generateSubject( projectScmRoot );
499 }
500 catch ( Exception e )
501 {
502 throw new NotificationException( "Error while generating mail subject.", e );
503 }
504
505 sendMessage( projectScmRoot, notifiers, subject, content, messageContext );
506 }
507
508
509
510
511
512 private List<String> getJavaHomeInformations( BuildDefinition buildDefinition )
513 throws InstallationException
514 {
515 if ( buildDefinition == null )
516 {
517 return continuum.getInstallationService().getDefaultJdkInformations();
518 }
519 Profile profile = buildDefinition.getProfile();
520 if ( profile == null )
521 {
522 return continuum.getInstallationService().getDefaultJdkInformations();
523 }
524 return continuum.getInstallationService().getJdkInformations( profile.getJdk() );
525 }
526
527 private List<String> getBuilderVersion( BuildDefinition buildDefinition, Project project )
528 throws InstallationException
529 {
530 ExecutorConfigurator executorConfigurator;
531 Installation builder = null;
532 Profile profile = null;
533 if ( buildDefinition != null )
534 {
535 profile = buildDefinition.getProfile();
536 if ( profile != null )
537 {
538 builder = profile.getBuilder();
539 }
540 }
541 if ( builder != null )
542 {
543 executorConfigurator = continuum.getInstallationService().getExecutorConfigurator( builder.getType() );
544 }
545 else
546 {
547
548 if ( MavenTwoBuildExecutor.ID.equals( project.getExecutorId() ) )
549 {
550 executorConfigurator = continuum.getInstallationService().getExecutorConfigurator(
551 InstallationService.MAVEN2_TYPE );
552 }
553 else if ( MavenOneBuildExecutor.ID.equals( project.getExecutorId() ) )
554 {
555 executorConfigurator = continuum.getInstallationService().getExecutorConfigurator(
556 InstallationService.MAVEN1_TYPE );
557 }
558 else if ( AntBuildExecutor.ID.equals( project.getExecutorId() ) )
559 {
560 executorConfigurator = continuum.getInstallationService().getExecutorConfigurator(
561 InstallationService.ANT_TYPE );
562 }
563 else
564 {
565 return Arrays.asList( "No builder defined" );
566 }
567 }
568
569 return continuum.getInstallationService().getExecutorConfiguratorVersion(
570 builder == null ? null : builder.getVarValue(), executorConfigurator, profile );
571 }
572
573 private String generateSubject( Project project, BuildResult build )
574 throws Exception
575 {
576 String state = getState( project, build );
577
578 VelocityContext context = new VelocityContext();
579 context.put( "project", project );
580 context.put( "build", build );
581 context.put( "state", state );
582
583 StringWriter writer = new StringWriter();
584
585 boolean velocityRes = velocity.getEngine().evaluate( context, writer, "subjectPattern", buildSubjectFormat );
586
587 return writer.toString();
588 }
589
590 private String generateSubject( ProjectScmRoot projectScmRoot )
591 throws Exception
592 {
593 String state = getState( projectScmRoot );
594
595 VelocityContext context = new VelocityContext();
596 context.put( "projectScmRoot", projectScmRoot );
597 context.put( "state", state );
598
599 StringWriter writer = new StringWriter();
600
601 boolean velocityResults = velocity.getEngine().evaluate( context, writer, "subjectPattern",
602 prepareBuildSubjectFormat );
603
604 return writer.toString();
605 }
606
607 private String getState( Project project, BuildResult build )
608 {
609 int state = project.getState();
610
611 if ( build != null )
612 {
613 state = build.getState();
614 }
615
616 if ( state == ContinuumProjectState.OK )
617 {
618 return "SUCCESSFUL";
619 }
620 else if ( state == ContinuumProjectState.FAILED )
621 {
622 return "FAILURE";
623 }
624 else if ( state == ContinuumProjectState.ERROR )
625 {
626 return "ERROR";
627 }
628 else
629 {
630 log.warn( "Unknown build state " + state + " for project " + project.getId() );
631
632 return "ERROR: Unknown build state " + state;
633 }
634 }
635
636 private String getState( ProjectScmRoot projectScmRoot )
637 {
638 int state = projectScmRoot.getState();
639
640 if ( state == ContinuumProjectState.UPDATED )
641 {
642 return "SUCCESSFUL";
643 }
644 else if ( state == ContinuumProjectState.ERROR )
645 {
646 return "ERROR";
647 }
648 else
649 {
650 log.warn(
651 "Unknown prepare build state " + state + " for SCM Root URL " + projectScmRoot.getScmRootAddress() +
652 " in projectGroup " + projectScmRoot.getProjectGroup().getId() );
653
654 return "ERROR: Unknown build state " + state;
655 }
656 }
657
658 private void sendMessage( Project project, List<ProjectNotifier> notifiers, String subject, String content,
659 MessageContext context )
660 throws NotificationException
661 {
662 if ( notifiers.size() == 0 )
663 {
664
665
666
667 log.info( "No mail notifier for '" + project.getName() + "'." );
668
669 return;
670 }
671
672 String fromMailbox = getFromMailbox( notifiers );
673
674 if ( fromMailbox == null )
675 {
676 log.warn( project.getName() +
677 ": Project is missing nag email and global from mailbox is missing, not sending mail." );
678
679 return;
680 }
681
682 try
683 {
684
685 MimeMessage message = javaMailSender.createMimeMessage();
686
687 message.addHeader( "X-Continuum-Build-Host", buildHost );
688
689 message.addHeader( "X-Continuum-Project-Id", Integer.toString( project.getId() ) );
690
691 message.addHeader( "X-Continuum-Project-Name", project.getName() );
692
693 message.setSubject( subject );
694
695 log.info( "Message Subject: '" + subject + "'." );
696
697 message.setText( content );
698
699 InternetAddress from = new InternetAddress( fromMailbox, fromName );
700
701 message.setFrom( from );
702
703 log.info( "Sending message: From '" + from + "'." );
704
705 if ( StringUtils.isEmpty( toOverride ) )
706 {
707 Set<String> listRecipents = new HashSet<String>();
708 for ( ProjectNotifier notifier : notifiers )
709 {
710 Map<String, String> conf = notifier.getConfiguration();
711 if ( conf != null )
712 {
713 String addressField = conf.get( ADDRESS_FIELD );
714
715 if ( StringUtils.isNotEmpty( addressField ) )
716 {
717 String[] addresses = StringUtils.split( addressField, "," );
718 for ( String address : addresses )
719 {
720 if ( !listRecipents.contains( address.trim() ) )
721 {
722
723
724 InternetAddress to = new InternetAddress( address.trim() );
725
726 log.info( "Recipient: To '" + to + "'." );
727 message.addRecipient( Message.RecipientType.TO, to );
728 listRecipents.add( address.trim() );
729 }
730 }
731
732 }
733
734 if ( context.getBuildResult() != null )
735 {
736 String committerField = (String) notifier.getConfiguration().get( COMMITTER_FIELD );
737 String developerField = (String) notifier.getConfiguration().get( DEVELOPER_FIELD );
738
739 if ( StringUtils.isNotEmpty( developerField ) && Boolean.parseBoolean( developerField ) )
740 {
741 List<ProjectDeveloper> developers = project.getDevelopers();
742 if ( developers == null || developers.isEmpty() )
743 {
744 log.warn(
745 "No developers have been configured...notifcation email will not be sent" );
746 return;
747 }
748 Map<String, String> developerToEmailMap = mapDevelopersToRecipients( developers );
749 for ( String email : developerToEmailMap.values() )
750 {
751 if ( !listRecipents.contains( email.trim() ) )
752 {
753 InternetAddress to = new InternetAddress( email.trim() );
754 log.info( "Recipient: To '" + to + "'." );
755 message.addRecipient( Message.RecipientType.TO, to );
756 listRecipents.add( email.trim() );
757 }
758 }
759 }
760 else if ( StringUtils.isNotEmpty( committerField ) && Boolean.parseBoolean(
761 committerField ) )
762 {
763 ScmResult scmResult = context.getBuildResult().getScmResult();
764 if ( scmResult != null && scmResult.getChanges() != null &&
765 !scmResult.getChanges().isEmpty() )
766 {
767 List<ProjectDeveloper> developers = project.getDevelopers();
768 if ( developers == null || developers.isEmpty() )
769 {
770 log.warn( "No developers have been configured...notifcation email " +
771 "will not be sent" );
772 return;
773 }
774
775 Map<String, String> developerToEmailMap = mapDevelopersToRecipients( developers );
776
777 List<ChangeSet> changes = scmResult.getChanges();
778
779 for ( ChangeSet changeSet : changes )
780 {
781 String scmId = changeSet.getAuthor();
782 if ( StringUtils.isNotEmpty( scmId ) )
783 {
784 String email = developerToEmailMap.get( scmId );
785 if ( StringUtils.isEmpty( email ) )
786 {
787
788 log.warn(
789 "no email address is defined in developers list for '" + scmId +
790 "' scm id." );
791 }
792 else if ( !listRecipents.contains( email.trim() ) )
793 {
794
795
796 InternetAddress to = new InternetAddress( email.trim() );
797 log.info( "Recipient: To '" + to + "'." );
798
799 message.addRecipient( Message.RecipientType.TO, to );
800 listRecipents.add( email.trim() );
801 }
802 }
803 }
804 }
805 }
806 }
807 }
808 }
809 }
810 else
811 {
812
813
814 InternetAddress to = new InternetAddress( toOverride.trim() );
815 log.info( "Recipient: To '" + to + "'." );
816
817 message.addRecipient( Message.RecipientType.TO, to );
818 }
819
820 message.setSentDate( new Date() );
821
822 if ( message.getAllRecipients() != null && ( message.getAllRecipients() ).length > 0 )
823 {
824 javaMailSender.send( message );
825 }
826 }
827 catch ( AddressException ex )
828 {
829 throw new NotificationException( "Exception while sending message.", ex );
830 }
831 catch ( MessagingException ex )
832 {
833 throw new NotificationException( "Exception while sending message.", ex );
834 }
835 catch ( UnsupportedEncodingException ex )
836 {
837 throw new NotificationException( "Exception while sending message.", ex );
838 }
839 }
840
841 private void sendMessage( ProjectScmRoot projectScmRoot, List<ProjectNotifier> notifiers, String subject,
842 String content, MessageContext context )
843 throws NotificationException
844 {
845 ProjectGroup projectGroup = projectScmRoot.getProjectGroup();
846
847 if ( notifiers.size() == 0 )
848 {
849
850
851
852 log.info( "No mail notifier for '" + projectGroup.getName() + "'." );
853
854 return;
855 }
856
857 String fromMailbox = getFromMailbox( notifiers );
858
859 if ( fromMailbox == null )
860 {
861 log.warn( projectGroup.getName() +
862 ": ProjectGroup is missing nag email and global from mailbox is missing, not sending mail." );
863
864 return;
865 }
866
867 MimeMessage message = javaMailSender.createMimeMessage();
868
869 try
870 {
871 message.setSubject( subject );
872
873 log.info( "Message Subject: '" + subject + "'." );
874
875 message.setText( content );
876
877 InternetAddress from = new InternetAddress( fromMailbox, fromName );
878
879 message.setFrom( from );
880
881 log.info( "Sending message: From '" + from + "'." );
882
883 if ( StringUtils.isEmpty( toOverride ) )
884 {
885 for ( ProjectNotifier notifier : notifiers )
886 {
887 if ( !shouldNotify( projectScmRoot, notifier ) )
888 {
889 continue;
890 }
891
892 Map<String, String> conf = notifier.getConfiguration();
893 if ( conf != null )
894 {
895 String addressField = conf.get( ADDRESS_FIELD );
896
897 if ( StringUtils.isNotEmpty( addressField ) )
898 {
899 String[] addresses = StringUtils.split( addressField, "," );
900
901 for ( String address : addresses )
902 {
903
904 InternetAddress to = new InternetAddress( address.trim() );
905
906 log.info( "Recipient: To '" + to + "'." );
907 message.addRecipient( Message.RecipientType.TO, to );
908 }
909 }
910 }
911 }
912 }
913 else
914 {
915
916
917 InternetAddress to = new InternetAddress( toOverride.trim() );
918 log.info( "Recipient: To '" + to + "'." );
919
920 message.addRecipient( Message.RecipientType.TO, to );
921 }
922
923 message.setSentDate( new Date() );
924
925 if ( message.getAllRecipients() != null && ( message.getAllRecipients() ).length > 0 )
926 {
927 javaMailSender.send( message );
928 }
929 }
930 catch ( AddressException ex )
931 {
932 throw new NotificationException( "Exception while sending message.", ex );
933 }
934 catch ( MessagingException ex )
935 {
936 throw new NotificationException( "Exception while sending message.", ex );
937 }
938 catch ( UnsupportedEncodingException ex )
939 {
940 throw new NotificationException( "Exception while sending message.", ex );
941 }
942 }
943
944 private Map<String, String> mapDevelopersToRecipients( List<ProjectDeveloper> developers )
945 {
946 Map<String, String> developersMap = new HashMap<String, String>();
947
948 for ( ProjectDeveloper developer : developers )
949 {
950 if ( StringUtils.isNotEmpty( developer.getScmId() ) && StringUtils.isNotEmpty( developer.getEmail() ) )
951 {
952 developersMap.put( developer.getScmId(), developer.getEmail() );
953 }
954 }
955
956 return developersMap;
957 }
958
959 private String getFromMailbox( List<ProjectNotifier> notifiers )
960 {
961 if ( fromMailbox != null )
962 {
963 return fromMailbox;
964 }
965
966 String address = null;
967
968 for ( ProjectNotifier notifier : notifiers )
969 {
970 Map<String, String> configuration = notifier.getConfiguration();
971 if ( configuration != null && StringUtils.isNotEmpty( configuration.get( ADDRESS_FIELD ) ) )
972 {
973 address = configuration.get( ADDRESS_FIELD );
974 break;
975 }
976 }
977
978 if ( StringUtils.isEmpty( address ) )
979 {
980 return FALLBACK_FROM_MAILBOX;
981 }
982
983 if ( address != null && address.contains( "," ) )
984 {
985 String[] addresses = StringUtils.split( address, "," );
986 return addresses[0];
987 }
988 return address;
989 }
990
991 public String getBuildHost()
992 {
993 return buildHost;
994 }
995
996 public void setBuildHost( String buildHost )
997 {
998 this.buildHost = buildHost;
999 }
1000
1001 public String getToOverride()
1002 {
1003 return toOverride;
1004 }
1005
1006 public void setToOverride( String toOverride )
1007 {
1008 this.toOverride = toOverride;
1009 }
1010 }