-
Notifications
You must be signed in to change notification settings - Fork 0
/
EmailNotificationService.java
312 lines (292 loc) · 10.4 KB
/
EmailNotificationService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
* Copyright (C) 2013 UniCoPA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package unicopa.copa.server.notification;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import unicopa.copa.base.UserSettings;
import unicopa.copa.base.event.Event;
import unicopa.copa.base.event.SingleEventUpdate;
import unicopa.copa.base.event.SingleEvent;
import unicopa.copa.server.CopaSystemContext;
import unicopa.copa.server.database.ObjectNotFoundException;
import unicopa.copa.server.email.EmailContext;
import unicopa.copa.server.email.EmailService;
import unicopa.copa.server.email.UpdateInformation;
/**
* This NotificationService informs users about updates by sending E-Mails.
*
* @author Felix Wiemuth, Philip Wendland
*/
public class EmailNotificationService extends NotificationService {
private EmailService emailService;
private Map<InternetAddress, String> centralInstances;
public static final Logger LOG = Logger
.getLogger(GoogleCloudNotificationService.class.getName());
/**
* Create a new EmailNotificationService.
*
* Reads the configuration and text templates from /email and gets an
* EmailService object.
*
* @param context
* The system context
*/
public EmailNotificationService(CopaSystemContext context) {
super(context);
File settingsDirectory = new File(super.getContext()
.getSettingsDirectory(), "email");
settingsDirectory.mkdirs();
// obtain configuration for the SMTP server
Properties smtpProps = new Properties();
File smtpConfig = new File(settingsDirectory, "smtp.properties");
if (!smtpConfig.exists()) {
File src;
try {
src = new File(this.getClass()
.getResource("/email/smtp.properties").toURI());
unicopa.copa.server.util.IOutils.copyFile(src, smtpConfig);
} catch (URISyntaxException | IOException ex) {
LOG.log(Level.SEVERE,
"Error copying smtp.properties file to user settings directory",
ex);
}
}
try (BufferedInputStream stream = new BufferedInputStream(
new FileInputStream(smtpConfig))) {
smtpProps.load(stream);
} catch (FileNotFoundException ex) {
LOG.log(Level.SEVERE, "Did not find smtp.properties.", ex);
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
// obtain text templates
Map<String, InputStream> texts = new HashMap<>();
File templates = new File(settingsDirectory, "/templates");
templates.mkdirs();
File[] files = unicopa.copa.server.util.IOutils.FileFinder(templates);
for (File file : files) {
FileInputStream fis;
try {
fis = new FileInputStream(file);
texts.put(file.getName(), fis);
} catch (FileNotFoundException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
// gather external E-Mail addresses and language settigns from
// configuration
centralInstances = new HashMap<>();
File externalAddrs = new File(settingsDirectory,
"externalAddresses.txt");
try {
if (!externalAddrs.exists()) {
File src = new File(this.getClass()
.getResource("externalAddresses.txt").toURI());
unicopa.copa.server.util.IOutils.copyFile(src, smtpConfig);
}
FileInputStream extAddrs = new FileInputStream(externalAddrs);
Scanner scn = new Scanner(new BufferedInputStream(extAddrs));
if (scn.hasNextLine())
scn.nextLine();
if (scn.hasNextLine())
scn.nextLine();
if (scn.hasNextLine())
scn.nextLine(); // ignore first three lines
while (scn.hasNextLine()) {
String nextAddrStr = scn.useDelimiter(":").next();
String nextLanguage = scn.skip(":").nextLine();
InternetAddress nextAddr = new InternetAddress(nextAddrStr);
this.centralInstances.put(nextAddr, nextLanguage);
}
} catch (IOException | AddressException ex) {
LOG.log(Level.SEVERE,
"Possibly format errors in externalAddresses.txt.", ex);
} catch (URISyntaxException ex) {
LOG.log(Level.SEVERE, null, ex);
}
// get a EmailService object
FileHandler logFH;
try {
logFH = new FileHandler(context.getLogDirectory()
.getCanonicalPath() + "/email.log", 10000000, 1, true);
this.emailService = new EmailService(smtpProps, texts, logFH);
} catch (IOException | SecurityException ex) {
LOG.log(Level.SEVERE, "Error creating FileHandler for logging.", ex);
}
}
/**
* Notify all users that have subscribed to get the specified
* SingleEventUpdate by sending an E-Mail to their registered E-Mail
* address.
*
* The content of the E-Mail will be in the language the user specified in
* his settings (if available).
*
* @param update
* the SingleEventUpdate to inform about
*/
@Override
public void notifyClients(SingleEventUpdate update) {
try {
// determine kind of update
String kindOfUpd;
if (update.isSingleEventCreation()) {
kindOfUpd = "new_";
} else if (update.isCancellation()) {
kindOfUpd = "cncld_";
} else {
kindOfUpd = "upd_";
}
// === gather the update information ===
// obtain EventGroupName, EventName from db.
// Note: We have to get the Event-ID from the old single event,
// because the new single event might be null
int eventID;
if (!update.isSingleEventCreation()) {
int oldID = update.getOldSingleEventID();
SingleEvent oldSingleEvent = super.getContext().getDbservice()
.getSingleEvent(oldID);
eventID = oldSingleEvent.getEventID();
} else {
eventID = update.getUpdatedSingleEvent().getEventID();
}
Event event = super.getContext().getDbservice().getEvent(eventID);
int eventGroupID = event.getEventGroupID();
String eventGroupName = super.getContext().getDbservice()
.getEventGroup(eventGroupID).getEventGroupName();
String eventName = event.getEventName();
Date updateDate = update.getUpdateDate();
String creatorName = update.getCreatorName();
String comment = update.getComment();
String location;
Date date;
String supervisor;
// if the update is _no_ cancellation use data from new single event
// else use data from old single event
if (!update.isCancellation()) {
location = update.getUpdatedSingleEvent().getLocation();
date = update.getUpdatedSingleEvent().getDate();
supervisor = update.getUpdatedSingleEvent().getSupervisor();
} else {
int oldID = update.getOldSingleEventID();
SingleEvent oldSingleEvent = super.getContext().getDbservice()
.getSingleEvent(oldID);
location = oldSingleEvent.getLocation();
date = oldSingleEvent.getDate();
supervisor = oldSingleEvent.getSupervisor();
}
UpdateInformation info = new UpdateInformation(eventGroupName,
eventName, updateDate, creatorName, comment, location,
date, supervisor);
// search for clients who want to be notified about this update
List<Integer> subUsers = super.getContext().getDbservice()
.getSubscribedUserIDs(eventID);
// get the Email addresses and user settings for those users
Map<Integer, String> emailStrings = new HashMap<>();
Map<Integer, UserSettings> usrSettings = new HashMap<>();
for (int usrID : subUsers) {
try {
String addr = super.getContext().getDbservice()
.getEmailAddress(usrID);
emailStrings.put(usrID, addr);
UserSettings settings = super.getContext().getDbservice()
.getUserSettings(usrID);
usrSettings.put(usrID, settings);
} catch (ObjectNotFoundException ex) {
LOG.log(Level.SEVERE,
"Error obtaining information from database.", ex);
}
}
// === create the list of EmailContext ===
// begin with default users from db
List<EmailContext> emailContexts = new ArrayList<>();
for (int userID : subUsers) {
UserSettings usrSet = usrSettings.get(userID);
if (usrSet.isEmailNotificationEnabled()) {
// E-Mail address
String emailString = emailStrings.get(userID);
InternetAddress EmailAddr = null;
try {
EmailAddr = new InternetAddress(emailString);
} catch (AddressException ex) {
LOG.log(Level.WARNING, "E-Mail address of user"
+ userID + "propably malformated.", ex);
}
// Text-ID
StringBuilder textID = new StringBuilder();
textID.append("default_");
textID.append(kindOfUpd);
textID.append(usrSet.getLanguage());
textID.append(".txt");
// add EmailContext to list
if (EmailAddr != null) {
EmailContext ctx = new EmailContext(EmailAddr,
textID.toString());
emailContexts.add(ctx);
}
}
}
// next we have to add the contexts for external users.
// The E-Mail addresses of those users are located in a
// configuration file and have already been gathered by the
// constructor.
for (Map.Entry<InternetAddress, String> entry : centralInstances
.entrySet()) {
// Text-ID
String lang = entry.getValue();
StringBuilder textID = new StringBuilder();
textID.append("general_");
textID.append(kindOfUpd);
textID.append(lang);
textID.append(".txt");
EmailContext ctx = new EmailContext(entry.getKey(),
textID.toString());
emailContexts.add(ctx);
}
// use EmailService to send emails
this.emailService.notifySingleEventUpdate(emailContexts, info);
} catch (ObjectNotFoundException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
/**
* The E-Mail service ignores those notification events.
*
* @param event
* @param userID
*/
@Override
public void notifyClient(NotificationEvent event, int userID) {
}
}