001: package com.mycompany.listeners;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.FileInputStream;
005: import java.io.IOException;
006: import java.io.InputStream;
007: import java.util.Enumeration;
008: import java.util.Properties;
009: import java.util.StringTokenizer;
010:
011: import javax.mail.Session;
012: import javax.mail.Transport;
013: import javax.mail.internet.InternetAddress;
014: import javax.mail.internet.MimeMessage;
015:
016: import com.puppycrawl.tools.checkstyle.DefaultLogger;
017: import com.puppycrawl.tools.checkstyle.api.AuditEvent;
018: import com.puppycrawl.tools.checkstyle.api.AuditListener;
019: import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
020: import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
021:
022: /**
023: * Buffers log messages from DefaultLogger, and sends an e-mail with the
024: * results. The following Project properties are used to send the mail.
025: * <ul>
026: * <li> MailLogger.mailhost [default: localhost] - Mail server to use</li>
027: *
028: * <li> MailLogger.from [required] - Mail "from" address</li>
029: * <li> MailLlistener.failure.notify [default: true] - Send build failure
030: * e-mails?</li>
031: * <li> MailLogger.success.notify [default: true] - Send build success
032: * e-mails?</li>
033: * <li> MailLogger.failure.to [required if failure mail to be sent] - Address
034: * to send failure messages to</li>
035: * <li> MailLogger.success.to [required if success mail to be sent] - Address
036: * to send success messages to</li>
037: * <li> MailLogger.failure.subject [default: "Build Failure"] - Subject of
038: * failed build</li>
039: * <li> MailLlistener.success.subject [default: "Build Success"] - Subject of
040: * successful build</li>
041: * </ul>
042: * These properties are set using standard property setting mechanisms
043: * (command-line -D, ant <property>, etc).Properties can be overridden
044: * by specifying the filename of a properties file in the <i>
045: * MailLogger.properties.file property</i> . Any properties defined in that
046: * file will override properties.
047: * Based on
048: * <a href="http://ant.apache.org/index.html">org.apache.tools.ant.listener.MailLogger>org.apache.tools.ant.listener.MailLogger</a>
049: * @author Erik Hatcher
050: * <a href="mailto:ehatcher@apache.org">ehatcher@apache.org</a>
051: * @author Rick Giles
052: */
053: public class MailLogger implements AuditListener {
054: /** output stream for logger */
055: private ByteArrayOutputStream mOutputStream;
056:
057: /** adapted listener */
058: private DefaultLogger mLogger;
059:
060: /** count of the number of errors and exceptions */
061: private int mErrors;
062:
063: /**
064: * Constructs a <code>MailLogger</code>
065: */
066: public MailLogger() {
067: mOutputStream = new ByteArrayOutputStream();
068: mLogger = new DefaultLogger(mOutputStream, false);
069: mErrors = 0;
070: }
071:
072: /** @see com.puppycrawl.tools.checkstyle.api.AuditListener */
073: public void auditStarted(AuditEvent aEvt) {
074: mLogger.auditStarted(aEvt);
075: }
076:
077: /**
078: * Sends an e-mail with the log results.
079: * @see com.puppycrawl.tools.checkstyle.api.AuditListener
080: */
081: public void auditFinished(AuditEvent aEvt) {
082: mLogger.auditFinished(aEvt);
083:
084: final Properties properties = System.getProperties();
085:
086: // overlay specified properties file (if any), which overrides project
087: // settings
088: final Properties fileProperties = new Properties();
089: final String filename = (String) properties
090: .get("MailLogger.properties.file");
091: if (filename != null) {
092: InputStream is = null;
093: try {
094: is = new FileInputStream(filename);
095: fileProperties.load(is);
096: } catch (IOException ioe) {
097: // ignore because properties file is not required
098: ;
099: } finally {
100: if (is != null) {
101: try {
102: is.close();
103: } catch (IOException e) {
104: ;
105: }
106: }
107: }
108: }
109:
110: for (Enumeration e = fileProperties.keys(); e.hasMoreElements();) {
111: final String key = (String) e.nextElement();
112: final String value = fileProperties.getProperty(key);
113: properties.put(key, value);
114: }
115:
116: final boolean success = (mErrors == 0);
117: final String prefix = success ? "success" : "failure";
118:
119: try {
120: final String mailhost = getValue(properties, "mailhost",
121: "localhost");
122: final String from = getValue(properties, "from", null);
123:
124: final String toList = getValue(properties, prefix + ".to",
125: null);
126: final String subject = getValue(properties, prefix
127: + ".subject",
128: (success) ? "Checkstyle Audit Success"
129: : "Checkstyle Audit Failure");
130:
131: sendMail(mailhost, from, toList, subject, mOutputStream
132: .toString());
133: } catch (Exception e) {
134: System.out.println("MailLogger failed to send e-mail!");
135: e.printStackTrace(System.err);
136: }
137: }
138:
139: /** @see com.puppycrawl.tools.checkstyle.api.AuditListener */
140: public void fileStarted(AuditEvent aEvt) {
141: mLogger.fileStarted(aEvt);
142: }
143:
144: /** @see com.puppycrawl.tools.checkstyle.api.AuditListener */
145: public void fileFinished(AuditEvent aEvt) {
146: mLogger.fileFinished(aEvt);
147: }
148:
149: /** @see com.puppycrawl.tools.checkstyle.api.AuditListener */
150: public void addError(AuditEvent aEvt) {
151: if (SeverityLevel.ERROR.equals(aEvt.getSeverityLevel())) {
152: mLogger.addError(aEvt);
153: mErrors++;
154: }
155: }
156:
157: /** @see com.puppycrawl.tools.checkstyle.api.AuditListener */
158: public void addException(AuditEvent aEvt, Throwable aThrowable) {
159: mLogger.addException(aEvt, aThrowable);
160: mErrors++;
161: }
162:
163: /**
164: * Gets the value of a property.
165: *
166: * @param aProperties Properties to obtain value from.
167: * @param aName suffix of property name. "MailLogger." will be
168: * prepended internally.
169: * @param aDefaultValue value returned if not present in the properties.
170: * Set to null to make required.
171: * @return The value of the property, or default value.
172: * @throws CheckstyleException if no default value is specified and the
173: * property is not present in properties.
174: */
175: private String getValue(Properties aProperties, String aName,
176: String aDefaultValue) throws CheckstyleException {
177: final String propertyName = "MailLogger." + aName;
178: String value = (String) aProperties.get(propertyName);
179:
180: if (value == null) {
181: value = aDefaultValue;
182: }
183:
184: if (value == null) {
185: throw new CheckstyleException(
186: "Missing required parameter: " + propertyName);
187: }
188:
189: return value;
190: }
191:
192: /**
193: * Send the mail
194: *
195: * @param aMailhost mail server
196: * @param aFrom from address
197: * @param aToList comma-separated recipient list
198: * @param aSubject mail subject
199: * @param aText mail body
200: * @throws Exception if sending message fails
201: */
202: private void sendMail(String aMailhost, String aFrom,
203: String aToList, String aSubject, String aText)
204: throws Exception {
205: // Get system properties
206: final Properties props = System.getProperties();
207:
208: // Setup mail server
209: props.put("mail.smtp.host", aMailhost);
210:
211: // Get session
212: final Session session = Session.getDefaultInstance(props, null);
213:
214: // Define message
215: final MimeMessage message = new MimeMessage(session);
216:
217: message.setFrom(new InternetAddress(aFrom));
218: final StringTokenizer t = new StringTokenizer(aToList, ", ",
219: false);
220: while (t.hasMoreTokens()) {
221: message.addRecipient(MimeMessage.RecipientType.TO,
222: new InternetAddress(t.nextToken()));
223: }
224: message.setSubject(aSubject);
225: message.setText(aText);
226:
227: Transport.send(message);
228: }
229: }
|