com.ozacc.mail.impl.JDomXMLMailBuilder Maven / Gradle / Ivy
package com.ozacc.mail.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.log.LogSystem;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import com.ozacc.mail.Mail;
import com.ozacc.mail.MailBuildException;
import com.ozacc.mail.MultipleMailBuilder;
import com.ozacc.mail.VelocityMultipleMailBuilder;
/**
* JDOMを利用してXMLファイルからMailインスタンスを生成するクラス。
*
* ソースXMLを読み込む際に、DTDバリデーションが実行されますので妥当なXMLデータ(Valid XML Document)でなければいけません。
*
* @since 1.0
*
* @author Tomohiro Otsuka
* @version $Id: JDomXMLMailBuilder.java,v 1.10.2.5 2005/02/01 20:37:49 otsuka Exp $
*/
public class JDomXMLMailBuilder implements MultipleMailBuilder, VelocityMultipleMailBuilder {
private static Log log = LogFactory.getLog(JDomXMLMailBuilder.class);
private static String CACHE_KEY_SEPARATOR = "#";
private static String DEFAULT_MAIL_ID = "DEFAULT";
protected LogSystem velocityLogSystem = new VelocityLogSystem();
private boolean cacheEnabled = false;
protected Map templateCache = new HashMap();
/**
* コンストラクタ。
*/
public JDomXMLMailBuilder() {}
/**
* 指定されたクラスパス上のXMLファイルからMailインスタンスを生成します。
*
* @param classPath メール内容を記述したXMLファイルのパス
* @return 生成されたMailインスタンス
* @throws MailBuildException Mailインスタンスの生成に失敗した場合
*/
public Mail buildMail(String classPath) throws MailBuildException {
Document doc = getDocumentFromClassPath(classPath);
return build(doc.getRootElement());
}
/**
* 指定されたクラスパス上のXMLファイルからMailインスタンスを生成します。
* 指定されたVelocityContextを使って、XMLファイルの内容を動的に生成できます。
*
* @param classPath メール内容を記述したXMLファイルのパス
* @param context VelocityContext
* @return 生成されたMailインスタンス
* @throws MailBuildException Mailインスタンスの生成に失敗した場合
*/
public Mail buildMail(String classPath, VelocityContext context) throws MailBuildException {
String cacheKey = classPath + CACHE_KEY_SEPARATOR + DEFAULT_MAIL_ID;
String templateXmlText;
if (!hasTemplateCache(cacheKey)) {
Document doc = getDocumentFromClassPath(classPath);
templateXmlText = cacheTemplateText(doc, cacheKey);
} else {
templateXmlText = getTemplateCache(cacheKey);
}
try {
return build(templateXmlText, context);
} catch (Exception e) {
throw new MailBuildException("メールの生成に失敗しました。", e);
}
}
/**
* 指定されたXMLファイルからMailインスタンスを生成します。
*
* @param file メール内容を記述したXMLファイル
* @return 生成されたMailインスタンス
* @throws MailBuildException Mailインスタンスの生成に失敗した場合
*/
public Mail buildMail(File file) throws MailBuildException {
Document doc = getDocumentFromFile(file);
return build(doc.getRootElement());
}
/**
* 指定されたXMLファイルからMailインスタンスを生成します。
* 指定されたVelocityContextを使って、XMLファイルの内容を動的に生成できます。
*
* @param file メール内容を記述したXMLファイル
* @param context VelocityContext
* @return 生成されたMailインスタンス
* @throws MailBuildException Mailインスタンスの生成に失敗した場合
*/
public Mail buildMail(File file, VelocityContext context) throws MailBuildException {
String cacheKey = file.getAbsolutePath() + CACHE_KEY_SEPARATOR + DEFAULT_MAIL_ID;
String templateXmlText;
if (!hasTemplateCache(cacheKey)) {
Document doc = getDocumentFromFile(file);
templateXmlText = cacheTemplateText(doc, cacheKey);
} else {
templateXmlText = getTemplateCache(cacheKey);
}
try {
return build(templateXmlText, context);
} catch (Exception e) {
throw new MailBuildException("メールの生成に失敗しました。", e);
}
}
private String cacheTemplateText(Document doc, String cacheKey) {
XMLOutputter output = new XMLOutputter();
String templateXmlText = "\n" + output.outputString(doc.getRootElement());
log.debug("以下のXMLデータをキャッシュします。\n" + templateXmlText);
putTemplateCache(cacheKey, templateXmlText);
return templateXmlText;
}
/**
* 指定されたクラスパス上のファイルを読み込んで、XMLドキュメントを生成します。
*
* @param classPath
* @return JDOM Document
*/
protected Document getDocumentFromClassPath(String classPath) throws MailBuildException {
InputStream is = getClass().getResourceAsStream(classPath);
SAXBuilder builder = new SAXBuilder(true);
builder.setEntityResolver(new DTDEntityResolver());
Document doc;
try {
doc = builder.build(is);
} catch (JDOMException e) {
throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
} catch (IOException e) {
throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// ignore
}
}
}
return doc;
}
/**
* 指定されたファイルを読み込んで、XMLドキュメントを生成します。
*
* @param file
* @return JDOM Document
*/
protected Document getDocumentFromFile(File file) {
SAXBuilder builder = new SAXBuilder(true);
builder.setEntityResolver(new DTDEntityResolver());
Document doc;
try {
doc = builder.build(file);
} catch (JDOMException e) {
throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
} catch (IOException e) {
throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
}
return doc;
}
/**
* XMLのmailルートエレメントからMailインスタンスを生成します。
*
* @param mailElement mail要素を示すElementインスタンス
* @return Mail 生成されたMail
*/
protected Mail build(Element mailElement) {
Mail mail = new Mail();
setFrom(mailElement, mail);
setRecipients(mailElement, mail);
setSubject(mailElement, mail);
setBody(mailElement, mail);
setReplyTo(mailElement, mail);
setReturnPath(mailElement, mail);
setHtml(mailElement, mail);
return mail;
}
/**
* VelocityContextとXMLテンプレートをマージさせ、Mailインスタンスを生成します。
*
* @param templateText マージするXMLテンプレートの文字列
* @param context マージするVelocityContext
* @return Mail
*
* @throws Exception
* @throws ParseErrorException
* @throws MethodInvocationException
* @throws ResourceNotFoundException
* @throws IOException
* @throws JDOMException
*/
protected Mail build(String templateText, VelocityContext context) throws Exception,
ParseErrorException,
MethodInvocationException,
ResourceNotFoundException,
IOException, JDOMException {
if (log.isDebugEnabled()) {
log.debug("ソースXMLデータ\n" + templateText);
}
Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, velocityLogSystem);
Velocity.init();
StringWriter w = new StringWriter();
Velocity.evaluate(context, w, "XML Mail Data", templateText);
if (log.isDebugEnabled()) {
log.debug("VelocityContextとマージ後のXMLデータ\n" + w.toString());
}
StringReader reader = new StringReader(w.toString());
SAXBuilder builder = new SAXBuilder(true);
builder.setEntityResolver(new DTDEntityResolver());
Document mergedDoc = builder.build(reader);
return build(mergedDoc.getRootElement());
}
/**
* @param root
* @param mail
*/
protected void setReturnPath(Element root, Mail mail) {
Element returnPathElem = root.getChild("returnPath");
if (returnPathElem != null && returnPathElem.getAttributeValue("email") != null) {
mail.setReturnPath(returnPathElem.getAttributeValue("email"));
}
}
/**
* @param root
* @param mail
*/
protected void setReplyTo(Element root, Mail mail) {
Element replyToElem = root.getChild("replyTo");
if (replyToElem != null && replyToElem.getAttributeValue("email") != null) {
mail.setReplyTo(replyToElem.getAttributeValue("email"));
}
}
/**
* @param root
* @param mail
*/
protected void setBody(Element root, Mail mail) {
Element bodyElem = root.getChild("body");
if (bodyElem != null) {
mail.setText(bodyElem.getTextTrim());
}
}
/**
* @param root
* @param mail
*/
protected void setHtml(Element root, Mail mail) {
Element htmlElem = root.getChild("html");
if (htmlElem != null) {
mail.setHtmlText(htmlElem.getTextTrim());
}
}
/**
* @param root
* @param mail
*/
protected void setSubject(Element root, Mail mail) {
Element subjectElem = root.getChild("subject");
if (subjectElem != null) {
mail.setSubject(subjectElem.getTextTrim());
}
}
/**
* @param root
* @param mail
*/
protected void setRecipients(Element root, Mail mail) {
Element recipientsElem = root.getChild("recipients");
if (recipientsElem == null) {
return;
}
List recipientElemList = recipientsElem.getChildren();
for (int i = 0, max = recipientElemList.size(); i < max; i++) {
Element e = (Element)recipientElemList.get(i);
if ("to".equals(e.getName())) { // to
if (e.getAttributeValue("email") != null) {
if (e.getAttributeValue("name") != null) {
mail.addTo(e.getAttributeValue("email"), e.getAttributeValue("name"));
} else {
mail.addTo(e.getAttributeValue("email"));
}
}
} else if ("cc".equals(e.getName())) { // cc
if (e.getAttributeValue("email") != null) {
if (e.getAttributeValue("name") != null) {
mail.addCc(e.getAttributeValue("email"), e.getAttributeValue("name"));
} else {
mail.addCc(e.getAttributeValue("email"));
}
}
} else {
if (e.getAttributeValue("email") != null) { // bcc
mail.addBcc(e.getAttributeValue("email"));
}
}
}
}
/**
* @param root
* @param mail
*/
protected void setFrom(Element root, Mail mail) {
Element fromElem = root.getChild("from");
if (fromElem != null && fromElem.getAttributeValue("email") != null) {
if (fromElem.getAttributeValue("name") != null) {
mail.setFrom(fromElem.getAttributeValue("email"), fromElem
.getAttributeValue("name"));
} else {
mail.setFrom(fromElem.getAttributeValue("email"));
}
}
}
/**
* @see com.ozacc.mail.VelocityMailBuilder#clearCache()
*/
public synchronized void clearCache() {
log.debug("テンプレートキャッシュをクリアします。");
templateCache.clear();
}
/**
* @see com.ozacc.mail.VelocityMailBuilder#isCacheEnabled()
*/
public boolean isCacheEnabled() {
return cacheEnabled;
}
/**
* @see com.ozacc.mail.VelocityMailBuilder#setCacheEnabled(boolean)
*/
public void setCacheEnabled(boolean cacheEnabled) {
if (!cacheEnabled) {
clearCache();
}
this.cacheEnabled = cacheEnabled;
}
protected boolean hasTemplateCache(String key) {
if (cacheEnabled) {
return templateCache.containsKey(key);
}
return false;
}
protected void putTemplateCache(String key, String templateXmlText) {
if (cacheEnabled) {
log.debug("テンプレートをキャッシュします。[key='" + key + "']");
templateCache.put(key, templateXmlText);
}
}
protected String getTemplateCache(String key) {
if (hasTemplateCache(key)) {
log.debug("テンプレートキャッシュを返します。[key='" + key + "']");
return (String)templateCache.get(key);
}
return null;
}
/**
* @see com.ozacc.mail.VelocityMultipleMailBuilder#buildMail(java.lang.String, org.apache.velocity.VelocityContext, java.lang.String)
*/
public Mail buildMail(String classPath, VelocityContext context, String mailId)
throws MailBuildException {
if (mailId == null || "".equals(mailId)) {
throw new IllegalArgumentException("メールIDが指定されていません。");
}
String cacheKey = classPath + CACHE_KEY_SEPARATOR + mailId;
String templateXmlText;
if (!hasTemplateCache(cacheKey)) {
Document doc = getDocumentFromClassPath(classPath);
templateXmlText = getAndCacheTemplateText(doc, mailId, cacheKey);
} else {
templateXmlText = getTemplateCache(cacheKey);
}
try {
return build(templateXmlText, context);
} catch (Exception e) {
throw new MailBuildException("メールの生成に失敗しました。", e);
}
}
private String getAndCacheTemplateText(Document doc, String mailId, String cacheKey)
throws MailBuildException {
Element mailElem = getElementById(doc, mailId);
XMLOutputter output = new XMLOutputter();
String templateXmlText = output.outputString(mailElem);
putTemplateCache(cacheKey, templateXmlText);
return templateXmlText;
}
/**
* @see com.ozacc.mail.VelocityMultipleMailBuilder#buildMail(java.io.File, org.apache.velocity.VelocityContext, java.lang.String)
*/
public Mail buildMail(File file, VelocityContext context, String mailId)
throws MailBuildException {
if (mailId == null || "".equals(mailId)) {
throw new IllegalArgumentException("メールIDが指定されていません。");
}
String cacheKey = file.getAbsolutePath() + CACHE_KEY_SEPARATOR + mailId;
String templateXmlText;
if (!hasTemplateCache(cacheKey)) {
Document doc = getDocumentFromFile(file);
templateXmlText = getAndCacheTemplateText(doc, mailId, cacheKey);
} else {
templateXmlText = getTemplateCache(cacheKey);
}
try {
return build(templateXmlText, context);
} catch (Exception e) {
throw new MailBuildException("メールの生成に失敗しました。", e);
}
}
/**
* @see com.ozacc.mail.MultipleMailBuilder#buildMail(java.lang.String, java.lang.String)
*/
public Mail buildMail(String classPath, String mailId) throws MailBuildException {
Document doc = getDocumentFromClassPath(classPath);
Element mailElem = getElementById(doc, mailId);
return build(mailElem);
}
/**
* @see com.ozacc.mail.MultipleMailBuilder#buildMail(java.io.File, java.lang.String)
*/
public Mail buildMail(File file, String mailId) throws MailBuildException {
Document doc = getDocumentFromFile(file);
Element mailElem = getElementById(doc, mailId);
return build(mailElem);
}
/**
* 指定されたXMLドキュメントの中から、指定されたid属性がセットされている要素を取得します。
*
* @param doc XMLドキュメント
* @param id 抽出する要素のid属性値
* @return XMLドキュメントで見つかったid属性を持つ要素
*/
private Element getElementById(Document doc, String id) {
Element mailsElem = doc.getRootElement(); //
List mailElemList = mailsElem.getChildren("mail");
for (Iterator itr = mailElemList.iterator(); itr.hasNext();) {
Element mailElem = (Element)itr.next();
String mailId = mailElem.getAttributeValue("id");
if (mailId.equals(id)) {
return mailElem;
}
}
throw new MailBuildException("指定されたID[" + id + "]のメールデータは見つかりませんでした。");
}
}