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
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
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
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
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
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 }