EMMA Coverage Report (generated Sun Sep 18 11:34:27 PHT 2011)
[all classes][org.apache.maven.continuum.notification.mail]

COVERAGE SUMMARY FOR SOURCE FILE [MailContinuumNotifier.java]

nameclass, %method, %block, %line, %
MailContinuumNotifier.java100% (1/1)68%  (15/22)49%  (734/1493)49%  (147.1/301)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class MailContinuumNotifier100% (1/1)68%  (15/22)49%  (734/1493)49%  (147.1/301)
generateSubject (ProjectScmRoot): String 0%   (0/1)0%   (0/35)0%   (0/7)
getBuildHost (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getState (ProjectScmRoot): String 0%   (0/1)0%   (0/43)0%   (0/7)
getToOverride (): String 0%   (0/1)0%   (0/3)0%   (0/1)
mapDevelopersToRecipients (List): Map 0%   (0/1)0%   (0/32)0%   (0/5)
prepareBuildComplete (ProjectScmRoot, List, String, MessageContext): void 0%   (0/1)0%   (0/99)0%   (0/20)
sendMessage (ProjectScmRoot, List, String, String, MessageContext): void 0%   (0/1)0%   (0/221)0%   (0/43)
getFromMailbox (List): String 100% (1/1)11%  (6/57)13%  (2/15)
getBuilderVersion (BuildDefinition, Project): List 100% (1/1)44%  (36/81)55%  (8.8/16)
sendMessage (Project, List, String, String, MessageContext): void 100% (1/1)57%  (204/359)55%  (38.8/70)
getJavaHomeInformations (BuildDefinition): List 100% (1/1)71%  (17/24)83%  (5/6)
initialize (): void 100% (1/1)71%  (62/87)65%  (11/17)
sendMessage (String, MessageContext): void 100% (1/1)76%  (39/51)70%  (10.5/15)
buildComplete (Project, List, BuildResult, BuildResult, String, MessageContex... 100% (1/1)88%  (209/237)82%  (33/40)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
MailContinuumNotifier (): void 100% (1/1)100% (18/18)100% (6/6)
buildComplete (Project, List, BuildResult, String, MessageContext, BuildDefin... 100% (1/1)100% (41/41)100% (7/7)
generateSubject (Project, BuildResult): String 100% (1/1)100% (41/41)100% (8/8)
getState (Project, BuildResult): String 100% (1/1)100% (47/47)100% (11/11)
getType (): String 100% (1/1)100% (2/2)100% (1/1)
setBuildHost (String): void 100% (1/1)100% (4/4)100% (2/2)
setToOverride (String): void 100% (1/1)100% (4/4)100% (2/2)

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

[all classes][org.apache.maven.continuum.notification.mail]
EMMA 2.0.5312 (C) Vladimir Roubtsov