View Javadoc

1   /***
2    * Copyright 2009 Martin Vysny.
3    *
4    * This file is part of WebVM.
5    *
6    * WebVM is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * WebVM is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with WebVM.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package sk.baka.webvm.misc;
20  
21  import java.util.List;
22  import java.util.StringTokenizer;
23  import java.util.concurrent.BlockingQueue;
24  import java.util.concurrent.LinkedBlockingQueue;
25  import java.util.concurrent.ScheduledExecutorService;
26  import java.util.logging.Level;
27  import java.util.logging.Logger;
28  import org.apache.commons.mail.Email;
29  import org.apache.commons.mail.EmailException;
30  import org.apache.commons.mail.HtmlEmail;
31  import org.jivesoftware.smack.Chat;
32  import org.jivesoftware.smack.MessageListener;
33  import org.jivesoftware.smack.XMPPConnection;
34  import org.jivesoftware.smack.XMPPException;
35  import org.jivesoftware.smack.packet.Message;
36  import sk.baka.webvm.analyzer.ProblemReport;
37  import sk.baka.webvm.config.Config;
38  
39  /***
40   * Delivers miscellaneous notifications (mail, jabber).
41   * @author Martin Vysny
42   */
43  public final class NotificationDelivery extends BackgroundService {
44  
45      /***
46       * Creates new deliverer.
47       */
48      public NotificationDelivery() {
49          super("Notificator", 1);
50      }
51  
52      /***
53       * Checks if sending mail is enabled in given config object.
54       * @param config the configuration object
55       * @return true if {@link Config#mailSmtpHost} is non-empty, false otherwise.
56       */
57      public static boolean isEmailEnabled(final Config config) {
58          return !isBlank(config.mailSmtpHost);
59      }
60  
61      private static boolean isBlank(final String str) {
62          return str == null || str.trim().length() == 0;
63      }
64  
65      /***
66       * Checks if sending mail is enabled in given config object.
67       * @param config the configuration object
68       * @return true if {@link Config#mailSmtpHost} is non-empty, false otherwise.
69       */
70      public static boolean isJabberEnabled(final Config config) {
71          return !isBlank(config.jabberServer);
72      }
73  
74      /***
75       * Sends a mail with given report.
76       * @param config the mail server configuration.
77       * @param testing if true then a testing mail is sent
78       * @param reports the current reports
79       * @throws org.apache.commons.mail.EmailException if sending mail fails.
80       */
81      public static void sendEmail(final Config config, final boolean testing, final List<ProblemReport> reports) throws EmailException {
82          if (!isEmailEnabled(config)) {
83              return;
84          }
85          final HtmlEmail mail = new HtmlEmail();
86          configure(mail, config);
87          mail.setSubject("WebVM: Problems notification" + (testing ? " (testing mail)" : ""));
88          mail.setMsg(ProblemReport.toString(reports, "\n"));
89          mail.setHtmlMsg("<html><body>\n" + ProblemReport.toHtml(reports) + "\n</body></html>");
90          mail.send();
91      }
92  
93      private static void configure(final Email mail, final Config config) throws EmailException {
94          mail.setHostName(config.mailSmtpHost);
95          config.mailSmtpEncryption.activate(mail);
96          if (config.mailSmtpPort > 0) {
97              if (mail.isSSL()) {
98                  mail.setSslSmtpPort(Integer.toString(config.mailSmtpPort));
99              } else {
100                 mail.setSmtpPort(config.mailSmtpPort);
101             }
102         }
103         if (config.mailSmtpUsername != null) {
104             mail.setAuthentication(config.mailSmtpUsername, config.mailSmtpPassword);
105         }
106         mail.setFrom(config.mailFrom);
107         if (config.mailTo == null) {
108             config.mailTo = "";
109         }
110         // add recipients
111         final StringTokenizer t = new StringTokenizer(config.mailTo, ",");
112         for (; t.hasMoreTokens();) {
113             mail.addTo(t.nextToken().trim());
114         }
115     }
116 
117     /***
118      * Sends a Jabber message with the Problems analysis.
119      * @param config use this config.
120      * @param testing if true then a (testing) string is appended to the message
121      * @param reports use these reports
122      * @throws org.jivesoftware.smack.XMPPException when send fails
123      */
124     public static void sendJabber(final Config config, final boolean testing, final List<ProblemReport> reports) throws XMPPException {
125         if (!isJabberEnabled(config)) {
126             return;
127         }
128         XMPPConnection connection = new XMPPConnection(config.jabberServer);
129         connection.connect();
130         try {
131             connection.login(config.jabberUsername, config.jabberPassword);
132             final StringTokenizer t = new StringTokenizer(config.jabberRecipients, ",");
133             for (; t.hasMoreTokens();) {
134                 final String recipient = t.nextToken().trim();
135                 final Chat chat = connection.getChatManager().createChat(recipient, "WebVM", new MessageListener() {
136 
137                     public void processMessage(Chat chat, Message message) {
138                         // do nothing
139                     }
140                 });
141                 chat.sendMessage("WebVM Problems report: " + (testing ? "(testing)" : "") + "\n" + ProblemReport.toString(reports, "\n"));
142             }
143         } finally {
144             connection.disconnect();
145         }
146     }
147 
148     /***
149      * Delivers given report asynchronously.
150      * @param reports the reports to deliver.
151      */
152     public void deliverAsync(final List<ProblemReport> reports) {
153         try {
154             asyncQueue.put(reports);
155         } catch (InterruptedException ex) {
156             // we do not have a space-bound queue
157             throw new AssertionError(ex);
158         }
159     }
160     private final BlockingQueue<List<ProblemReport>> asyncQueue = new LinkedBlockingQueue<List<ProblemReport>>();
161 
162     @Override
163     protected void started(ScheduledExecutorService executor) {
164         executor.execute(new Notificator());
165     }
166     private volatile Config config;
167 
168     /***
169      * Sets the new configuration file.
170      * @param config the new config file.
171      */
172     public void configure(final Config config) {
173         this.config = new Config(config);
174     }
175 
176     @Override
177     protected void stopped() {
178         // do nothing
179     }
180 
181     private class Notificator implements Runnable {
182 
183         public void run() {
184             while (true) {
185                 final List<ProblemReport> reports;
186                 try {
187                     reports = asyncQueue.take();
188                 } catch (InterruptedException ex) {
189                     // we are terminating.
190                     return;
191                 }
192                 try {
193                     NotificationDelivery.sendEmail(config, false, reports);
194                 } catch (Exception ex) {
195                     LOG.log(Level.SEVERE, "Failed to send email", ex);
196                 }
197                 try {
198                     NotificationDelivery.sendJabber(config, false, reports);
199                 } catch (Exception ex) {
200                     LOG.log(Level.SEVERE, "Failed to send jabber message", ex);
201                 }
202             }
203         }
204     }
205     private static final Logger LOG = Logger.getLogger(NotificationDelivery.class.getName());
206 }