OSDN Git Service

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