KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > publishers > EmailPublisher


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001-2003, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37 package net.sourceforge.cruisecontrol.publishers;
38
39 import java.io.File JavaDoc;
40 import java.io.UnsupportedEncodingException JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.Arrays JavaDoc;
43 import java.util.Collections JavaDoc;
44 import java.util.Date JavaDoc;
45 import java.util.HashSet JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.util.List JavaDoc;
48 import java.util.Properties JavaDoc;
49 import java.util.Set JavaDoc;
50 import java.util.TreeSet JavaDoc;
51
52 import javax.mail.Message JavaDoc;
53 import javax.mail.MessagingException JavaDoc;
54 import javax.mail.SendFailedException JavaDoc;
55 import javax.mail.Session JavaDoc;
56 import javax.mail.Transport JavaDoc;
57 import javax.mail.internet.AddressException JavaDoc;
58 import javax.mail.internet.InternetAddress JavaDoc;
59 import javax.mail.internet.MimeMessage JavaDoc;
60
61 import net.sourceforge.cruisecontrol.CruiseControlException;
62 import net.sourceforge.cruisecontrol.Modification;
63 import net.sourceforge.cruisecontrol.Publisher;
64 import net.sourceforge.cruisecontrol.publishers.email.EmailMapper;
65 import net.sourceforge.cruisecontrol.publishers.email.EmailMapperHelper;
66 import net.sourceforge.cruisecontrol.publishers.email.EmailMapping;
67 import net.sourceforge.cruisecontrol.util.ValidationHelper;
68 import net.sourceforge.cruisecontrol.util.XMLLogHelper;
69
70 import org.apache.log4j.Logger;
71 import org.apache.oro.io.GlobFilenameFilter;
72 import org.apache.oro.text.MalformedCachePatternException;
73 import org.jdom.Element;
74
75 /**
76  * Abstract implementation of the <code>Publisher</code> interface, specifically
77  * tailored for sending email. The only abstract method is createMessage, which
78  * allows different implementations to send different messages as the body of
79  * the email. As it currently stands, there is one concrete implementation--
80  * <code>LinkEmailPublisher</code>, but the ability to create
81  * <code>EmailPublisher</code>s that handle sending a text summary or an html
82  * summary is there.
83  *
84  * @author alden almagro, ThoughtWorks, Inc. 2002
85  */

86 public abstract class EmailPublisher implements Publisher {
87     private static final Logger LOG = Logger.getLogger(EmailPublisher.class);
88
89     private String JavaDoc mailHost;
90     private String JavaDoc userName;
91     private String JavaDoc password;
92     private String JavaDoc mailPort;
93     private boolean useSSL;
94     private String JavaDoc buildResultsURL;
95     private Always[] alwaysAddresses = new Always[0];
96     private Failure[] failureAddresses = new Failure[0];
97     private Success[] successAddresses = new Success[0];
98     private Alert[] alertAddresses = new Alert[0];
99     private EmailMapper[] emailMapper = new EmailMapper[0];
100     private EmailMapperHelper mapperHelper = new EmailMapperHelper();
101     private String JavaDoc returnAddress;
102     private String JavaDoc returnName;
103     private String JavaDoc defaultSuffix = "";
104     private String JavaDoc reportSuccess = "always";
105     private boolean spamWhileBroken = true;
106     private boolean skipUsers = false;
107     private String JavaDoc subjectPrefix;
108     private boolean failAsImportant = true;
109
110     /**
111      * Implementations of this method will create the email message body.
112      *
113      * @param logHelper <code>XMLLogHelper</code> wrapper for the build log.
114      * @return <code>String</code> containing the message
115      */

116     protected abstract String JavaDoc createMessage(XMLLogHelper logHelper);
117
118     /*
119      * Called after the configuration is read to make sure that all the mandatory parameters
120      * were specified..
121      *
122      * @throws CruiseControlException if there was a configuration error.
123      */

124     public void validate() throws CruiseControlException {
125         ValidationHelper.assertIsSet(getMailHost(), "mailhost", this.getClass());
126         ValidationHelper.assertIsSet(getReturnAddress(), "returnaddress", this.getClass());
127         ValidationHelper.assertFalse(getUsername() != null && getPassword() == null,
128             "'password' is required if 'username' is set for email.");
129         ValidationHelper.assertFalse(getPassword() != null && getUsername() == null,
130             "'username' is required if 'password' is set for email.");
131
132         for (int i = 0; i < alertAddresses.length; i++) {
133             try {
134                 alertAddresses[i].fileFilter = new GlobFilenameFilter(alertAddresses[i].fileRegExpr);
135             } catch (MalformedCachePatternException mcpe) {
136                 ValidationHelper.fail("invalid regexp '" + alertAddresses[i].fileRegExpr + "'", mcpe);
137             }
138         }
139     }
140
141     /**
142      * Creates the subject line for the email message.
143      *
144      * @param logHelper <code>XMLLogHelper</code> wrapper for the build log.
145      * @return <code>String</code> containing the subject line.
146      */

147     protected String JavaDoc createSubject(XMLLogHelper logHelper) throws CruiseControlException {
148         StringBuffer JavaDoc subjectLine = new StringBuffer JavaDoc();
149         if (subjectPrefix != null) {
150             subjectLine.append(subjectPrefix).append(" ");
151         }
152         subjectLine.append(logHelper.getProjectName());
153         if (logHelper.isBuildSuccessful()) {
154             String JavaDoc label = logHelper.getLabel();
155             if (label.trim().length() > 0) {
156                 subjectLine.append(" ").append(logHelper.getLabel());
157             }
158
159             //Anytime the build is "fixed" the subjest line
160
// should read "fixed". It might confuse recipients...but
161
// it shouldn't
162
if (logHelper.isBuildFix()) {
163                 subjectLine.append(" Build Fixed");
164             } else {
165                 subjectLine.append(" Build Successful");
166             }
167         } else {
168             subjectLine.append(" Build Failed");
169         }
170         return subjectLine.toString();
171     }
172
173     /**
174      * Determines if the conditions are right for the email to be sent.
175      *
176      * @param logHelper <code>XMLLogHelper</code> wrapper for the build log.
177      * @return whether or not the mail message should be sent.
178      */

179     protected boolean shouldSend(XMLLogHelper logHelper) throws CruiseControlException {
180         if (logHelper.isBuildSuccessful()) {
181             if (reportSuccess.equalsIgnoreCase("always")) {
182                 return true;
183             }
184             if (reportSuccess.equalsIgnoreCase("fixes")) {
185                 if (logHelper.wasPreviousBuildSuccessful()) {
186                     LOG.debug(
187                         "reportSuccess is set to 'fixes', not sending emails for repeated successful builds.");
188                     return false;
189                 } else {
190                     return true;
191                 }
192             }
193             if (reportSuccess.equalsIgnoreCase("never")) {
194                 LOG.debug(
195                     "reportSuccess is set to 'never', not sending emails for successful builds.");
196                 return false;
197             }
198         } else { //build wasn't successful
199
if (!logHelper.wasPreviousBuildSuccessful()
200                 && logHelper.isBuildNecessary()
201                 && !spamWhileBroken) {
202
203                 LOG.debug("spamWhileBroken is set to false, not sending email");
204                 return false;
205             }
206         }
207         return true;
208     }
209
210     /**
211      * Creates the list of email addresses to receive the email message.
212      * Uses configured emailmappers to map user names to email addresses.
213      * After all mappings are done, mapped users are checked for existance of
214      * the domain part (i.e @mydomain.com) in the mapped email address. If it
215      * doesn't exist, default (if configured) is appended
216      *
217      * Any addresses set in the <code>addAlwaysAddress</code> method will
218      * always receive the email if it is sent. Any address set in the
219      * <code>addFailureAddress</code> method will receive the message if the
220      * build has failed.
221      *
222      * @param logHelper <code>XMLLogHelper</code> wrapper for the build log.
223      * @return comma delimited <code>String</code> of email addresses to
224      * receive the email message.
225      */

226     protected String JavaDoc createUserList(XMLLogHelper logHelper) throws CruiseControlException {
227         
228         Set JavaDoc emails = createUserSet(logHelper);
229         return createEmailString(emails);
230     }
231
232     
233     
234     /**
235      * Creates the <code>Set</code> of email addresses to receive
236      * the email message.
237      * <p>
238      * Uses configured emailmappers to map user names to email addresses.
239      * After all mappings are done, mapped users are checked for existance of
240      * the domain part (i.e @mydomain.com) in the mapped email address. If it
241      * doesn't exist, default (if configured) is appended
242      *
243      * Any addresses set in the <code>addAlwaysAddress</code> method will
244      * always receive the email if it is sent. Any address set in the
245      * <code>addFailureAddress</code> method will receive the message if the
246      * build has failed.
247      *
248      * @param logHelper <code>XMLLogHelper</code> wrapper for the build log.
249      * @return A <code>Set</code> of email addresses to
250      * receive the email message.
251      */

252     protected Set JavaDoc createUserSet(XMLLogHelper logHelper) throws CruiseControlException {
253         
254         Set JavaDoc users = skipUsers ? new HashSet JavaDoc() : logHelper.getBuildParticipants();
255         
256         //add always addresses
257
for (int i = 0; i < alwaysAddresses.length; i++) {
258             users.add(alwaysAddresses[i].getAddress());
259         }
260
261         //if build failed, add failure addresses
262
if (!logHelper.isBuildSuccessful()) {
263             for (int i = 0; i < failureAddresses.length; i++) {
264                 users.add(failureAddresses[i].getAddress());
265             }
266         }
267
268         //If build fixed, add failure addresses that want to know about the fix
269
if (logHelper.isBuildFix()) {
270             for (int i = 0; i < failureAddresses.length; i++) {
271                 if (failureAddresses[i].shouldReportWhenFixed()) {
272                     users.add(failureAddresses[i].getAddress());
273                 }
274             }
275         }
276
277         //if build succeeded, add success addresses
278
if (logHelper.isBuildSuccessful()) {
279             for (int i = 0; i < successAddresses.length; i++) {
280                 users.add(successAddresses[i].getAddress());
281             }
282         }
283         
284         Set JavaDoc emails = new TreeSet JavaDoc();
285         mapperHelper.mapUsers(this, users, emails);
286         return emails;
287     }
288     
289     
290     /**
291      * Implementing the <code>Publisher</code> interface.
292      *
293      * Sends modification alert and regular build emails. If a user is
294      * supposed to recieve a modification alert and a regular build email,
295      * they will only recieve the modiciation alert. This prevents
296      * duplicate emails (currently only the subject is different).
297      */

298     public void publish(Element cruisecontrolLog) throws CruiseControlException {
299         XMLLogHelper helper = new XMLLogHelper(cruisecontrolLog);
300         boolean important = failAsImportant && !helper.isBuildSuccessful();
301
302         Set JavaDoc userSet = new HashSet JavaDoc();
303         Set JavaDoc alertSet = createAlertUserSet(helper);
304         String JavaDoc subject = createSubject(helper);
305         
306         if (!alertSet.isEmpty()) {
307             String JavaDoc alertSubject = "[MOD ALERT] " + subject;
308             sendMail(createEmailString(alertSet), alertSubject, createMessage(helper), important);
309         }
310
311         if (shouldSend(helper)) {
312             userSet.addAll(createUserSet(helper));
313             // Do not send duplicates to users who received an alert email
314
userSet.removeAll(alertSet);
315             
316             if (!userSet.isEmpty()) {
317                 sendMail(createEmailString(userSet), subject, createMessage(helper), important);
318             } else {
319                 if (alertSet.isEmpty()) {
320                     LOG.info("No recipients, so not sending email");
321                 }
322             }
323         }
324     }
325
326     /**
327      * builds the properties object for the mail session
328      * @return a properties object containing configured properties.
329      */

330     protected Properties JavaDoc getMailProperties() {
331         Properties JavaDoc props = System.getProperties();
332         props.put("mail.smtp.host", mailHost);
333         props.put("mail.smtp.sendpartial", "true");
334         if (mailPort != null) {
335             props.put("mail.smtp.port", mailPort);
336         }
337         LOG.debug(
338             "mailHost is " + mailHost + ", mailPort is " + mailPort == null ? "default" : mailPort);
339         if (userName != null && password != null) {
340             props.put("mail.smtp.auth", "true");
341             if (useSSL) {
342                 props.put("mail.smtp.socketFactory.port", mailPort);
343                 props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
344                 props.put("mail.smtp.socketFactory.fallback", "false");
345             }
346         }
347         return props;
348     }
349
350     /**
351      * Sends an email message.
352      *
353      * @param toList comma delimited <code>String</code> of email addresses
354      * @param subject subject line for the message
355      * @param message body of the message
356      * @return Boolean value indicating if an email was sent.
357      */

358     protected boolean sendMail(String JavaDoc toList, String JavaDoc subject, String JavaDoc message, boolean important)
359         throws CruiseControlException {
360         
361         boolean emailSent = false;
362         
363         if (toList != null && toList.trim().length() != 0) {
364
365             LOG.debug("Sending email to: " + toList);
366             
367             Session JavaDoc session = Session.getDefaultInstance(getMailProperties(), null);
368             session.setDebug(LOG.isDebugEnabled());
369     
370             try {
371                 Message JavaDoc msg = new MimeMessage JavaDoc(session);
372                 msg.setFrom(getFromAddress());
373                 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toList, false));
374                 msg.setSubject(subject);
375                 msg.setSentDate(new Date JavaDoc());
376                 String JavaDoc importance = (important) ? "High" : "Normal";
377                 msg.addHeader("Importance", importance);
378     
379                 addContentToMessage(message, msg);
380     
381                 if (userName != null && password != null) {
382                     msg.saveChanges(); // implicit with send()
383
Transport JavaDoc transport = session.getTransport("smtp");
384                     transport.connect(mailHost, userName, password);
385                     transport.sendMessage(msg, msg.getAllRecipients());
386                     transport.close();
387                 } else {
388                     Transport.send(msg);
389                 }
390                 
391                 emailSent = true;
392                 
393             } catch (SendFailedException JavaDoc e) {
394                 LOG.warn(e.getMessage(), e);
395             } catch (MessagingException JavaDoc e) {
396                 throw new CruiseControlException(e.getClass().getName() + ": " + e.getMessage(), e);
397             }
398         }
399         
400         return emailSent;
401     }
402
403     /**
404      * Subclasses can override this method to control how the content
405      * is added to the Message.
406      *
407      * @param content content returned by createMessage
408      * @param msg mail Message with headers and addresses added elsewhere
409      * @throws MessagingException
410      */

411     protected void addContentToMessage(String JavaDoc content, Message JavaDoc msg) throws MessagingException JavaDoc {
412         msg.setText(content);
413     }
414
415     protected InternetAddress JavaDoc getFromAddress() throws AddressException JavaDoc {
416         InternetAddress JavaDoc fromAddress = new InternetAddress JavaDoc(returnAddress);
417         if (returnName != null) {
418             try {
419                 fromAddress = new InternetAddress JavaDoc(returnAddress, returnName);
420             } catch (UnsupportedEncodingException JavaDoc e) {
421                 LOG.error("error setting returnName [" + returnName + "]: " + e.getMessage());
422             }
423         }
424         return fromAddress;
425     }
426
427     public void setMailHost(String JavaDoc hostname) {
428         mailHost = hostname;
429     }
430
431     public String JavaDoc getMailHost() {
432         return mailHost;
433     }
434
435     public void setUsername(String JavaDoc name) {
436         userName = name;
437     }
438
439     public String JavaDoc getUsername() {
440         return userName;
441     }
442
443     public void setPassword(String JavaDoc passwd) {
444         password = passwd;
445     }
446
447     public String JavaDoc getPassword() {
448         return password;
449     }
450
451     public void setMailPort(String JavaDoc port) {
452         mailPort = port;
453     }
454
455     public String JavaDoc getMailPort() {
456         return mailPort;
457     }
458
459     public void setUseSSL(boolean useSSL) {
460         this.useSSL = useSSL;
461     }
462
463     public void setSubjectPrefix(String JavaDoc prefix) {
464         subjectPrefix = prefix;
465     }
466
467     public String JavaDoc getSubjectPrefix() {
468         return subjectPrefix;
469     }
470
471     public String JavaDoc getBuildResultsURL() {
472         return buildResultsURL;
473     }
474
475     public void setBuildResultsURL(String JavaDoc url) {
476         buildResultsURL = url;
477     }
478
479     public EmailMapper[] getEmailMapper() {
480         return emailMapper;
481     }
482
483     public String JavaDoc getReturnAddress() {
484         return returnAddress;
485     }
486
487     public void setReturnAddress(String JavaDoc emailAddress) {
488         returnAddress = emailAddress;
489     }
490
491     public String JavaDoc getReturnName() {
492         return returnName;
493     }
494
495     public void setReturnName(String JavaDoc emailReturnName) {
496         returnName = emailReturnName;
497     }
498
499     public String JavaDoc getDefaultSuffix() {
500         return defaultSuffix;
501     }
502
503     public void setDefaultSuffix(String JavaDoc defaultEmailSuffix) {
504         defaultSuffix = defaultEmailSuffix;
505     }
506
507     public void setReportSuccess(String JavaDoc report) {
508         reportSuccess = report;
509     }
510
511     public void setSkipUsers(boolean skip) {
512         skipUsers = skip;
513     }
514
515     public void setSpamWhileBroken(boolean spam) {
516         spamWhileBroken = spam;
517     }
518
519     public void setFailAsImportant(boolean important) {
520         failAsImportant = important;
521     }
522
523     public Always createAlways() {
524         List JavaDoc alwaysList = new ArrayList JavaDoc();
525         alwaysList.addAll(Arrays.asList(alwaysAddresses));
526
527         Always always = new Always();
528         alwaysList.add(always);
529
530         alwaysAddresses = (Always[]) alwaysList.toArray(new Always[0]);
531
532         return always;
533     }
534
535     public Failure createFailure() {
536         List JavaDoc failureList = new ArrayList JavaDoc();
537         failureList.addAll(Arrays.asList(failureAddresses));
538
539         Failure failure = new Failure();
540         failureList.add(failure);
541
542         failureAddresses = (Failure[]) failureList.toArray(new Failure[0]);
543
544         return failure;
545     }
546
547     public Success createSuccess() {
548         List JavaDoc successList = new ArrayList JavaDoc();
549         successList.addAll(Arrays.asList(successAddresses));
550
551         Success success = new Success();
552         successList.add(success);
553
554         successAddresses = (Success[]) successList.toArray(new Success[0]);
555
556         return success;
557     }
558
559     public Alert createAlert() {
560         List JavaDoc alertsList = new ArrayList JavaDoc();
561         alertsList.addAll(Arrays.asList(alertAddresses));
562
563         Alert alert = new Alert();
564         alertsList.add(alert);
565
566         alertAddresses = (Alert[]) alertsList.toArray(new Alert[0]);
567
568         return alert;
569     }
570     
571     /*
572      * for the <map ... /> entries, just stuff them into the cache in EmailMapperHelper
573      */

574     public void add(EmailMapping mapping) {
575         EmailMapperHelper.addCacheEntry(this, mapping.getAlias(), mapping.getAddress());
576     }
577
578     public void add(EmailMapper mapper) {
579         List JavaDoc mapperList = new ArrayList JavaDoc();
580         mapperList.addAll(Arrays.asList(emailMapper));
581
582         mapper.setPublisher(this);
583         mapperList.add(mapper);
584
585         emailMapper = (EmailMapper[]) mapperList.toArray(new EmailMapper[0]);
586     }
587
588     public static class Address {
589         private String JavaDoc address;
590
591         public String JavaDoc getAddress() {
592             return address;
593         }
594
595         public void setAddress(String JavaDoc theAddress) {
596             address = theAddress;
597         }
598     }
599
600     public static class Always extends Address JavaDoc {
601     }
602
603     public static class Failure extends Address JavaDoc {
604         /**
605          * Set to true to send an email to this "address" when the build gets
606          * fixed.
607          */

608         private boolean reportWhenFixed = false;
609
610         public boolean shouldReportWhenFixed() {
611             return reportWhenFixed;
612         }
613
614         public void setReportWhenFixed(boolean reportWhenFixed) {
615             this.reportWhenFixed = reportWhenFixed;
616         }
617     }
618
619     public static class Success extends Address JavaDoc {
620     }
621
622
623     public static class Alert extends Address JavaDoc {
624         /**
625          * A regExpr for the file you are interested in watching
626          *
627          */

628         private String JavaDoc fileRegExpr = null;
629         
630         /**
631          * The compiled regExp, set on validation of the Publisher
632          */

633         private GlobFilenameFilter fileFilter = null;
634
635         /**
636          * A <code>String</code> representing the regexp to match against modified files
637          * @param f A <code>String</code> representing the file that was modified
638          */

639         public void setFileRegExpr(String JavaDoc f) {
640             this.fileRegExpr = f;
641         }
642     }
643     
644     public static void main(String JavaDoc[] args) {
645         EmailPublisher pub = new EmailPublisher() {
646             protected String JavaDoc createMessage(XMLLogHelper logHelper) {
647                 return "This is a test message.";
648             }
649         };
650         pub.setMailHost(args[0]);
651         pub.setUsername(args[1]);
652         pub.setPassword(args[2]);
653         pub.setReturnAddress(args[3]);
654         try {
655             pub.sendMail(args[4], "test subject", "test message", false);
656         } catch (CruiseControlException e) {
657             LOG.error("test failed", e);
658         }
659     }
660
661     /**
662      * Creates the list of email addresses to receive an alert email message.
663      * <p>
664      * The full path of each modified file is compared against
665      * the regular expressions specified in the configuration. If
666      * a modified file's path matches a regular expression, the user's
667      * email address is included in the returned <code>String</code>.
668      * <p>
669      * Uses configured emailmappers to map user names to email addresses. After
670      * all mappings are done, mapped users are checked for existance of the
671      * domain part (i.e @mydomain.com) in the mapped email address. If it
672      * doesn't exist, default (if configured) is appended.
673      *
674      * @param logHelper
675      * <code>XMLLogHelper</code> wrapper for the build log.
676      * @return comma delimited <code>String</code> of email addresses to
677      * receive the email message.
678      */

679     protected String JavaDoc createAlertUserList(XMLLogHelper logHelper) throws CruiseControlException {
680         return createEmailString(createAlertUserSet(logHelper));
681     }
682
683
684     /**
685      * Creates a <code>Set</code> of email addresses to recieve an alert email
686      * message based on the logHelper.
687      *
688      * @param logHelper <code>XMLLogHelper</code> wrapper for the build log.
689      * @throws CruiseControlException
690      * @return A <code>Set</code> of email addresses to receive the email message.
691      */

692     protected Set JavaDoc createAlertUserSet(XMLLogHelper logHelper) throws CruiseControlException {
693         if (alertAddresses.length == 0) {
694             return Collections.EMPTY_SET;
695         }
696
697         Set JavaDoc users = new HashSet JavaDoc();
698         Set JavaDoc modificationSet = logHelper.getModifications();
699
700         for (Iterator JavaDoc modificationIter = modificationSet.iterator(); modificationIter.hasNext(); ) {
701             Modification mod = (Modification) modificationIter.next();
702             String JavaDoc modifiedFile = mod.getFullPath();
703             
704             LOG.debug("Modified file: " + modifiedFile);
705             
706             // Compare the modified file to the regExpr's
707
for (int i = 0; i < alertAddresses.length; i++) {
708                 String JavaDoc emailAddress = alertAddresses[i].getAddress();
709
710                 if (emailAddress != null && !"".equals(emailAddress.trim())
711                     && !users.contains(emailAddress)
712                     && matchRegExpr(modifiedFile, alertAddresses[i].fileFilter)) {
713
714                     // We have a new match, send an alert email
715
users.add(emailAddress);
716                     
717                     LOG.info("Alert '" + emailAddress
718                             + "' because their fileRegExpr '" + alertAddresses[i].fileRegExpr
719                             + "' matched " + modifiedFile);
720                 }
721             }
722         }
723
724         Set JavaDoc emails = new TreeSet JavaDoc();
725         mapperHelper.mapUsers(this, users, emails);
726         return emails;
727     }
728     
729
730     /**
731      * Creates a comma delimited <code>String</code> from a <code>Set</code> of
732      * <code>String</code>s.
733      *
734      * @param emails A <code>Set</code> containing <code>String</code>s of emails addresses
735      * @return A comma delmited <code>String</code> of email addresses
736      */

737     protected String JavaDoc createEmailString(Set JavaDoc emails) {
738         StringBuffer JavaDoc commaDelimitedString = new StringBuffer JavaDoc();
739         Iterator JavaDoc emailIterator = appendDefaultSuffix(emails).iterator();
740
741         while (emailIterator.hasNext()) {
742             String JavaDoc mappedUser = (String JavaDoc) emailIterator.next();
743             commaDelimitedString.append(mappedUser);
744             if (emailIterator.hasNext()) {
745                 commaDelimitedString.append(",");
746             }
747         }
748         
749         LOG.debug("List of emails: " + commaDelimitedString);
750         
751         return commaDelimitedString.toString();
752     }
753
754     private Set JavaDoc appendDefaultSuffix(Set JavaDoc emails) {
755         Set JavaDoc result = new TreeSet JavaDoc();
756         Iterator JavaDoc emailIterator = emails.iterator();
757
758         while (emailIterator.hasNext()) {
759             String JavaDoc mappedUser = (String JavaDoc) emailIterator.next();
760             // append default suffix if need to
761
if (mappedUser.indexOf("@") < 0) {
762                 mappedUser += defaultSuffix;
763             }
764             result.add(mappedUser);
765         }
766         return result;
767     }
768     
769     
770     /**
771      * Compare the input <code>String</code> against a regular expression pattern.
772      *
773      * @param input A <code>String</code> to compare against the regExpr pattern
774      * @param pattern A <code>GlobFilenameFilter</code> pattern
775      * @return True if the file matches the regular expression pattern. Otherwise false.
776      */

777     protected boolean matchRegExpr(String JavaDoc input, GlobFilenameFilter pattern) {
778         File JavaDoc file = new File JavaDoc(input);
779         String JavaDoc path = file.toString();
780         
781         // On systems with a '\' as pathseparator convert it to a forward slash '/'
782
// That makes patterns platform independent
783
if (File.separatorChar == '\\') {
784             path = path.replace('\\', '/');
785         }
786         
787         return pattern.accept(file, path);
788     }
789 }
790
Popular Tags