/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.services.task.deadlines.notifications.impl.email;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.activation.DataHandler;
import javax.activation.MimetypesFileTypeMap;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import org.jbpm.services.task.deadlines.NotificationListener;
import org.kie.api.task.model.Group;
import org.kie.api.task.model.OrganizationalEntity;
import org.kie.api.task.model.Task;
import org.kie.api.task.model.User;
import org.kie.internal.task.api.TaskModelProvider;
import org.kie.internal.task.api.UserInfo;
import org.kie.internal.task.api.model.EmailNotification;
import org.kie.internal.task.api.model.EmailNotificationHeader;
import org.kie.internal.task.api.model.InternalOrganizationalEntity;
import org.kie.internal.task.api.model.Language;
import org.kie.internal.task.api.model.NotificationEvent;
import org.mvel2.templates.TemplateRuntime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EmailNotificationListener implements NotificationListener {
private static final Logger logger = LoggerFactory.getLogger(EmailNotificationListener.class);
private Session mailSession = EmailSessionProducer.produceSession();
@Override
public void onNotification(NotificationEvent event, UserInfo userInfo) {
if (userInfo == null || mailSession == null) {
logger.info("Missing mail session or userinfo - skipping email notification listener processing");
return;
}
if (event.getNotification() instanceof EmailNotification) {
EmailNotification notification = (EmailNotification) event.getNotification();
Task task = event.getTask();
// group users into languages
Map<String, List<User>> users = new HashMap<String, List<User>>();
for (OrganizationalEntity entity : notification.getBusinessAdministrators()) {
if (entity instanceof Group) {
buildMapByLanguage(users, (Group) entity, userInfo);
} else {
buildMapByLanguage(users, (User) entity, userInfo);
}
}
for (OrganizationalEntity entity : notification.getRecipients()) {
if (entity instanceof Group) {
buildMapByLanguage(users, (Group) entity, userInfo);
} else {
buildMapByLanguage(users, (User) entity, userInfo);
}
}
Map<String, Object> variables = event.getContent();
Map<? extends Language, ? extends EmailNotificationHeader> headers = notification.getEmailHeaders();
for (Iterator<Map.Entry<String, List<User>>> it = users.entrySet()
.iterator(); it.hasNext();) {
try {
Map.Entry<String, List<User>> entry = it.next();
Language lang = TaskModelProvider.getFactory().newLanguage();
lang.setMapkey(entry.getKey());
EmailNotificationHeader header = headers.get(lang);
Message msg = new MimeMessage(mailSession);
Set<String> toAddresses = new HashSet<String>();
for (User user : entry.getValue()) {
String emailAddress = userInfo.getEmailForEntity(user);
if (emailAddress != null && !toAddresses.contains(emailAddress)) {
msg.addRecipients( Message.RecipientType.TO, InternetAddress.parse( emailAddress, false));
toAddresses.add(emailAddress);
} else {
logger.warn("Email address not found for user {}", user.getId());
}
}
if (header.getFrom() != null && header.getFrom().trim().length() > 0) {
User user = TaskModelProvider.getFactory().newUser();
((InternalOrganizationalEntity) user).setId(header.getFrom());
msg.setFrom( new InternetAddress(userInfo.getEmailForEntity(user)));
} else {
msg.setFrom( new InternetAddress(mailSession.getProperty("mail.from")));
}
if (header.getReplyTo() != null && header.getReplyTo().trim().length() > 0) {
User user = TaskModelProvider.getFactory().newUser();
((InternalOrganizationalEntity) user).setId(header.getReplyTo());
msg.setReplyTo( new InternetAddress[] {
new InternetAddress(userInfo.getEmailForEntity(user))});
} else if (mailSession.getProperty("mail.replyto") != null) {
msg.setReplyTo( new InternetAddress[] { new InternetAddress(mailSession.getProperty("mail.replyto"))});
}
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("doc", variables);
// add internal items to be able to reference them in templates
vars.put("processInstanceId", task.getTaskData().getProcessInstanceId());
vars.put("processSessionId", task.getTaskData().getProcessSessionId());
vars.put("workItemId", task.getTaskData().getWorkItemId());
vars.put("expirationTime", task.getTaskData().getExpirationTime());
vars.put("taskId", task.getId());
if (task.getPeopleAssignments() != null) {
vars.put("owners", task.getPeopleAssignments().getPotentialOwners());
}
String subject = (String) TemplateRuntime.eval(header.getSubject(), vars);
String body = (String) TemplateRuntime.eval(header.getBody(), vars);
if (variables.containsKey("attachments")) {
Multipart multipart = new MimeMultipart();
// prepare body as first mime body part
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler( new DataHandler( new ByteArrayDataSource( body, "text/html" ) ) );
multipart.addBodyPart(messageBodyPart);
List<String> attachments = getAttachements(variables.get("attachments"));
for (String attachment : attachments) {
MimeBodyPart attachementBodyPart = new MimeBodyPart();
URL attachmentUrl = getAttachemntURL(attachment);
String contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(attachmentUrl.getFile());
attachementBodyPart.setDataHandler(new DataHandler(new ByteArrayDataSource( attachmentUrl.openStream(), contentType ) ));
String fileName = new File(attachmentUrl.getFile()).getName();
attachementBodyPart.setFileName(fileName);
attachementBodyPart.setContentID("<"+fileName+">");
multipart.addBodyPart(attachementBodyPart);
}
// Put parts in message
msg.setContent(multipart);
} else {
msg.setDataHandler( new DataHandler( new ByteArrayDataSource( body, "text/html" ) ) );
}
msg.setSubject( subject );
msg.setHeader( "X-Mailer", "jbpm huamn task service" );
msg.setSentDate( new Date() );
Transport.send(msg);
} catch (Exception e) {
logger.error("Unable to send email notification due to {}", e.getMessage());
logger.debug("Stacktrace:", e);
}
}
}
}
protected URL getAttachemntURL(String attachment) throws MalformedURLException {
if (attachment.startsWith("classpath:")) {
String location = attachment.replaceFirst("classpath:", "");
return this.getClass().getResource(location);
} else {
URL attachmentUrl = new URL(attachment);
return attachmentUrl;
}
}
@SuppressWarnings("unchecked")
protected List<String> getAttachements(Object attachementsFromVariables) {
if (attachementsFromVariables instanceof List) {
return (List<String>) attachementsFromVariables;
} else {
String attachementsAsString = attachementsFromVariables.toString();
return Arrays.asList(attachementsAsString.split(","));
}
}
protected void buildMapByLanguage(Map<String, List<User>> map, Group group, UserInfo userInfo) {
Iterator<OrganizationalEntity> it = userInfo.getMembersForGroup(group);
if (it != null) {
while (it.hasNext()) {
OrganizationalEntity entity = it.next();
if (entity instanceof Group) {
buildMapByLanguage(map, (Group) entity, userInfo);
} else {
buildMapByLanguage(map, (User) entity, userInfo);
}
}
}
}
protected void buildMapByLanguage(Map<String, List<User>> map, User user, UserInfo userInfo) {
String language = userInfo.getLanguageForEntity(user);
List<User> list = map.get(language);
if (list == null) {
list = new ArrayList<User>();
map.put(language, list);
}
list.add(user);
}
}