Notification Service: Notifier implementation
22 November 2008Since we first introduced the Notifier interface, we have shown off the unit tests and explained the Spring configuration, but we haven’t actually revealed the code that we have been testing and configuring, so I guess it’s time we do that:
package org.restafarian.notify.service.impl;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.restafarian.core.utils.SimpleVelocityService;
import org.restafarian.notify.beans.MessageAddress;
import org.restafarian.notify.beans.NoticeTemplate;
import org.restafarian.notify.manager.NoticeTemplateManager;
import org.restafarian.notify.service.DeliveryService;
import org.restafarian.notify.service.Notifier;
/**
* <p>This class is a service module that delivers notifications.</p>
*/
public class NotifierImpl implements Notifier {
private final Log log = LogFactory.getLog(NotifierImpl.class);
private NoticeTemplateManager noticeTemplateManager;
private DeliveryService deliveryService;
private String defaultTemplateContext;
/**
* <p>Delivers the specified notification.</p>
*
* @param sendToAddress the "to" address of the message
* @param templateId the id of the notice template in the form of context/name
* @param noticeData optional data used to resolve variables in the notice
*/
public void sendNotification(String sendToAddress, String templateId, Object noticeData) {
List sendTo = new ArrayList();
sendTo.add(sendToAddress);
this.sendNotification(null, sendTo, null, getNoticeTemplate(templateId), noticeData);
}
/**
* <p>Delivers the specified notification.</p>
*
* @param sendTo the list of objects representing the notice recipients
* @param templateId the id of the notice template in the form of context/name
* @param noticeData optional data used to resolve variables in the notice
*/
public void sendNotification(List sendTo, String templateId, Object noticeData) {
this.sendNotification(null, sendTo, null, getNoticeTemplate(templateId), noticeData);
}
/**
* <p>Delivers the specified notification.</p>
*
* @param sendTo the list of objects representing the notice recipients
* @param sendToProperty the name of the property in the recipient object
* that specifies the "to" address. If this parameter is null or blank, it
* is assumed that the sendTo list contains simple "to" address strings
* @param templateId the id of the notice template in the form of context/name
* @param noticeData optional data used to resolve variables in the notice
*/
public void sendNotification(List sendTo, String sendToProperty, String templateId, Object
noticeData) {
this.sendNotification(null, sendTo, sendToProperty, getNoticeTemplate(templateId), noticeData);
}
/**
* <p>Delivers the specified notification.</p>
*
* @param sendFrom the "from" address
* @param sendTo the list of objects representing the notice recipients
* @param sendToProperty the name of the property in the recipient object
* that specifies the "to" address. If this parameter is null or blank, it
* is assumed that the sendTo list contains simple "to" address strings
* @param templateId the id of the notice template in the form of context/name
* @param noticeData optional data used to resolve variables in the notice
*/
public void sendNotification(String sendFrom, List sendTo, String sendToProperty, String
templateId, Object noticeData) {
this.sendNotification(sendFrom, sendTo, sendToProperty, getNoticeTemplate(templateId),
noticeData);
}
/**
* <p>Delivers the specified notification.</p>
*
* @param sendFrom the "from" address
* @param sendTo the list of objects representing the notice recipients
* @param sendToProperty the name of the property in the recipient object
* that specifies the "to" address. If this parameter is null or blank, it
* is assumed that the sendTo list contains simple "to" address strings
* @param noticeTemplate the notice template
* @param noticeData optional data used to resolve variables in the notice
*/
public void sendNotification(String sendFrom, List sendTo, String sendToProperty,
NoticeTemplate noticeTemplate, Object noticeData) {
if (log.isDebugEnabled()) {
log.debug("Processing notification request; sendFrom: " + sendFrom);
}
if (noticeTemplate != null) {
if (sendTo != null && sendTo.size() > 0) {
Iterator i = sendTo.iterator();
while (i.hasNext()) {
Object recipient = i.next();
// extract the "to" address string
String toAddress = "";
if (StringUtils.isNotEmpty(sendToProperty)) {
try {
toAddress = BeanUtils.getProperty(recipient, sendToProperty);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Exception encountered processing
sendToProperty.", e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Exception encountered processing
sendToProperty.", e);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Exception encountered processing
sendToProperty.", e);
}
} else {
toAddress = recipient.toString();
}
// resolve the variable data
Map sourceData = new HashMap();
sourceData.put("recipient", recipient);
sourceData.put("data", noticeData);
String titleSubject = SimpleVelocityService.evaluate(noticeTemplate.getTitleSubject(),
sourceData);
String body = SimpleVelocityService.evaluate(noticeTemplate.getBody(), sourceData);
// set up the from and to addresses
MessageAddress[] addresses = new MessageAddress[1];
MessageAddress toAddr = new MessageAddress();
toAddr.setAddressType("mailTo");
toAddr.addAddressValue(toAddress);
if (StringUtils.isNotEmpty(sendFrom)) {
MessageAddress fromAddress = new MessageAddress();
fromAddress.setAddressType("mailFrom");
fromAddress.addAddressValue(sendFrom);
addresses = new MessageAddress[2];
addresses[0] = fromAddress;
addresses[1] = toAddr;
} else {
addresses[0] = toAddr;
}
// log, if enabled
if (log.isDebugEnabled()) {
log.debug("Sending notification; toAddress: " + toAddress + "; titleSubject: " +
titleSubject);
}
// deliver message
deliveryService.deliverMessage(noticeTemplate.getDefaultDeliveryMethod(), addresses,
titleSubject, noticeTemplate.getContentType(), body);
}
} else {
if (log.isDebugEnabled()) {
log.debug("Invalid request -- recipient list is null or empty");
}
throw new IllegalArgumentException("Recipient list cannot be null or empty.");
}
} else {
if (log.isDebugEnabled()) {
log.debug("Invalid request -- notice template is null");
}
throw new IllegalArgumentException("Notice template cannot be null.");
}
}
/**
* <p>Fetches the specified template.</p>
*
* @param templateId the id of the notice template in the form of context/name
* @return the requested NoticeTemplate
*/
public NoticeTemplate getNoticeTemplate(String templateId) {
String context = defaultTemplateContext;
String name = templateId;
if (templateId.indexOf("/") != -1) {
String[] parts = templateId.split("/");
context = parts[0];
name = parts[1];
}
if (log.isDebugEnabled()) {
log.debug("Fetching notice template; context: " + context + "; name: " + name);
}
return noticeTemplateManager.findByContextAndName(context, name);
}
/**
* @return the noticeTemplateManager
*/
public NoticeTemplateManager getNoticeTemplateManager() {
return noticeTemplateManager;
}
/**
* @param noticeTemplateManager the noticeTemplateManager to set
*/
public void setNoticeTemplateManager(NoticeTemplateManager noticeTemplateManager) {
this.noticeTemplateManager = noticeTemplateManager;
}
/**
* @return the deliveryService
*/
public DeliveryService getDeliveryService() {
return deliveryService;
}
/**
* @param deliveryService the deliveryService to set
*/
public void setDeliveryService(DeliveryService deliveryService) {
this.deliveryService = deliveryService;
}
/**
* @return the defaultTemplateContext
*/
public String getDefaultTemplateContext() {
return defaultTemplateContext;
}
/**
* @param defaultTemplateContext the defaultTemplateContext to set
*/
public void setDefaultTemplateContext(String defaultTemplateContext) {
this.defaultTemplateContext = defaultTemplateContext;
}
}
The first four public methods are just short-cuts to get to the fifth, where all of the work is done, so those just fill in the missing pieces and call on the full service to do the work. The fifth is where all of the work is done, which starts by ensuring that we have a valid request that includes a template and at least one recipient, and then it loops through the list of intended recipients, resolves the variable data in both the subject and the body of the message, and then calls on the delivery service to deliver the message.
Even though there are still a number of things that I would like to do to improve on what we have so far, this essentially completes the service, We now have the capability to call one of the five public variations of the Notifier interface and have one or more messages delivered based on a message template. We could put this version into production use today and start using it while we continued on to enhance the service and add new features and performance improvements.
Technically, we are now done with version 1.0 of Notification Service.
Leave a reply
You must be logged in to post a comment.






