View Javadoc

    1   package com.ozacc.mail.impl;
    2
    3   import java.io.File;
    4   import java.io.IOException;
    5   import java.io.InputStream;
    6   import java.io.StringReader;
    7   import java.io.StringWriter;
    8   import java.util.HashMap;
    9   import java.util.List;
    10  import java.util.Map;
    11
    12  import org.apache.commons.logging.Log;
    13  import org.apache.commons.logging.LogFactory;
    14  import org.apache.velocity.VelocityContext;
    15  import org.apache.velocity.app.Velocity;
    16  import org.apache.velocity.exception.MethodInvocationException;
    17  import org.apache.velocity.exception.ParseErrorException;
    18  import org.apache.velocity.exception.ResourceNotFoundException;
    19  import org.apache.velocity.runtime.log.LogSystem;
    20  import org.jdom.Document;
    21  import org.jdom.Element;
    22  import org.jdom.JDOMException;
    23  import org.jdom.input.SAXBuilder;
    24  import org.jdom.output.XMLOutputter;
    25
    26  import com.ozacc.mail.Mail;
    27  import com.ozacc.mail.MailBuildException;
    28  import com.ozacc.mail.VelocityMailBuilder;
    29
    30  /***
    31   * <a href="http://www.jdom.org/">JDOM</a>を利用してXMLファイルからMailインスタンスを生成するクラス。
    32   * <p>
    33   * ソースXMLを読み込む際に、DTDバリデーションが実行されますので妥当なXMLデータ(Valid XML Document)でなければいけません。
    34   *
    35   * @since 1.0
    36   *
    37   * @author Tomohiro Otsuka
    38   * @version $Id: JDomXMLMailBuilder.java,v 1.10.2.3 2005/01/17 15:44:21 otsuka Exp $
    39   */
    40  public class JDomXMLMailBuilder implements VelocityMailBuilder {
    41
    42  	private static Log log = LogFactory.getLog(JDomXMLMailBuilder.class);
    43
    44  	protected LogSystem velocityLogSystem = new VelocityLogSystem();
    45
    46  	private boolean cacheEnabled = false;
    47
    48  	protected Map templateCache = new HashMap();
    49
    50  	/***
    51  	 * コンストラクタ。
    52  	 */
    53  	public JDomXMLMailBuilder() {}
    54
    55  	/***
    56  	 * 指定されたクラスパス上のXMLファイルからMailインスタンスを生成します。
    57  	 *
    58  	 * @param classPath メール内容を記述したXMLファイルのパス
    59  	 * @return 生成されたMailインスタンス
    60  	 * @throws MailBuildException Mailインスタンスの生成に失敗した場合
    61  	 */
    62  	public Mail buildMail(String classPath) throws MailBuildException {
    63  		Document doc = getDocumentFromClassPath(classPath);
    64  		return build(doc);
    65  	}
    66
    67  	/***
    68  	 * 指定されたクラスパス上のXMLファイルからMailインスタンスを生成します。
    69  	 * 指定されたVelocityContextを使って、XMLファイルの内容を動的に生成できます。
    70  	 *
    71  	 * @param classPath メール内容を記述したXMLファイルのパス
    72  	 * @param context VelocityContext
    73  	 * @return 生成されたMailインスタンス
    74  	 * @throws MailBuildException Mailインスタンスの生成に失敗した場合
    75  	 */
    76  	public Mail buildMail(String classPath, VelocityContext context) throws MailBuildException {
    77  		String templateXmlText;
    78  		if (!hasTemplateCache(classPath)) {
    79  			Document doc = getDocumentFromClassPath(classPath);
    80  			XMLOutputter output = new XMLOutputter();
    81  			templateXmlText = output.outputString(doc);
    82  			putTemplateCache(classPath, templateXmlText);
    83  		} else {
    84  			templateXmlText = getTemplateCache(classPath);
    85  		}
    86
    87  		try {
    88  			return build(templateXmlText, context);
    89  		} catch (Exception e) {
    90  			throw new MailBuildException("メールの生成に失敗しました。", e);
    91  		}
    92  	}
    93
    94  	/***
    95  	 * 指定されたXMLファイルからMailインスタンスを生成します。
    96  	 *
    97  	 * @param file メール内容を記述したXMLファイル
    98  	 * @return 生成されたMailインスタンス
    99  	 * @throws MailBuildException Mailインスタンスの生成に失敗した場合
    100 	 */
    101 	public Mail buildMail(File file) throws MailBuildException {
    102 		Document doc = getDocumentFromFile(file);
    103 		return build(doc);
    104 	}
    105
    106 	/***
    107 	 * 指定されたXMLファイルからMailインスタンスを生成します。
    108 	 * 指定されたVelocityContextを使って、XMLファイルの内容を動的に生成できます。
    109 	 *
    110 	 * @param file メール内容を記述したXMLファイル
    111 	 * @param context VelocityContext
    112 	 * @return 生成されたMailインスタンス
    113 	 * @throws MailBuildException Mailインスタンスの生成に失敗した場合
    114 	 */
    115 	public Mail buildMail(File file, VelocityContext context) throws MailBuildException {
    116 		String templateXmlText;
    117 		if (!hasTemplateCache(file.getAbsolutePath())) {
    118 			Document doc = getDocumentFromFile(file);
    119 			XMLOutputter output = new XMLOutputter();
    120 			templateXmlText = output.outputString(doc);
    121 			putTemplateCache(file.getAbsolutePath(), templateXmlText);
    122 		} else {
    123 			templateXmlText = getTemplateCache(file.getAbsolutePath());
    124 		}
    125
    126 		try {
    127 			return build(templateXmlText, context);
    128 		} catch (Exception e) {
    129 			throw new MailBuildException("メールの生成に失敗しました。", e);
    130 		}
    131 	}
    132
    133 	/***
    134 	 * 指定されたクラスパス上のファイルを読み込んで、XMLドキュメントを生成します。
    135 	 *
    136 	 * @param classPath
    137 	 * @return JDOM Document
    138 	 */
    139 	protected Document getDocumentFromClassPath(String classPath) throws MailBuildException {
    140 		InputStream is = getClass().getResourceAsStream(classPath);
    141 		SAXBuilder builder = new SAXBuilder(true);
    142 		builder.setEntityResolver(new DTDEntityResolver());
    143 		Document doc;
    144 		try {
    145 			doc = builder.build(is);
    146 			is.close();
    147 		} catch (JDOMException e) {
    148 			throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
    149 		} catch (IOException e) {
    150 			throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
    151 		}
    152 		return doc;
    153 	}
    154
    155 	/***
    156 	 * 指定されたファイルを読み込んで、XMLドキュメントを生成します。
    157 	 *
    158 	 * @param file
    159 	 * @return JDOM Document
    160 	 */
    161 	protected Document getDocumentFromFile(File file) {
    162 		SAXBuilder builder = new SAXBuilder(true);
    163 		builder.setEntityResolver(new DTDEntityResolver());
    164 		Document doc;
    165 		try {
    166 			doc = builder.build(file);
    167 		} catch (JDOMException e) {
    168 			throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
    169 		} catch (IOException e) {
    170 			throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
    171 		}
    172 		return doc;
    173 	}
    174
    175 	/***
    176 	 * XMLドキュメントからMailインスタンスを生成します。
    177 	 *
    178 	 * @param doc
    179 	 * @return Mail
    180 	 */
    181 	protected Mail build(Document doc) {
    182 		Element root = doc.getRootElement();
    183
    184 		Mail mail = new Mail();
    185 		setFrom(root, mail);
    186 		setRecipients(root, mail);
    187 		setSubject(root, mail);
    188 		setBody(root, mail);
    189 		setReplyTo(root, mail);
    190 		setReturnPath(root, mail);
    191
    192 		setHtml(root, mail);
    193
    194 		return mail;
    195 	}
    196
    197 	/***
    198 	 * VelocityContextとXMLテンプレートをマージさせ、Mailインスタンスを生成します。
    199 	 *
    200 	 * @param templateText マージするXMLテンプレートの文字列
    201 	 * @param context マージするVelocityContext
    202 	 * @return Mail
    203 	 *
    204 	 * @throws Exception
    205 	 * @throws ParseErrorException
    206 	 * @throws MethodInvocationException
    207 	 * @throws ResourceNotFoundException
    208 	 * @throws IOException
    209 	 * @throws JDOMException
    210 	 */
    211 	protected Mail build(String templateText, VelocityContext context) throws Exception,
    212 																		ParseErrorException,
    213 																		MethodInvocationException,
    214 																		ResourceNotFoundException,
    215 																		IOException, JDOMException {
    216 		if (log.isDebugEnabled()) {
    217 			log.debug("Source XML Mail Data\n" + templateText);
    218 		}
    219
    220 		Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, velocityLogSystem);
    221 		Velocity.init();
    222 		StringWriter w = new StringWriter();
    223 		Velocity.evaluate(context, w, "XML Mail Data", templateText);
    224
    225 		if (log.isDebugEnabled()) {
    226 			String newXmlContent = w.toString();
    227 			log.debug("VelocityContext-merged XML Mail Data\n" + newXmlContent);
    228 		}
    229
    230 		StringReader reader = new StringReader(w.toString());
    231 		SAXBuilder builder = new SAXBuilder(true);
    232 		builder.setEntityResolver(new DTDEntityResolver());
    233 		Document doc2 = builder.build(reader);
    234
    235 		return build(doc2);
    236 	}
    237
    238 	/***
    239 	 * @param root
    240 	 * @param mail
    241 	 */
    242 	protected void setReturnPath(Element root, Mail mail) {
    243 		Element returnPathElem = root.getChild("returnPath");
    244 		if (returnPathElem != null && returnPathElem.getAttributeValue("email") != null) {
    245 			mail.setReturnPath(returnPathElem.getAttributeValue("email"));
    246 		}
    247 	}
    248
    249 	/***
    250 	 * @param root
    251 	 * @param mail
    252 	 */
    253 	protected void setReplyTo(Element root, Mail mail) {
    254 		Element replyToElem = root.getChild("replyTo");
    255 		if (replyToElem != null && replyToElem.getAttributeValue("email") != null) {
    256 			mail.setReplyTo(replyToElem.getAttributeValue("email"));
    257 		}
    258 	}
    259
    260 	/***
    261 	 * @param root
    262 	 * @param mail
    263 	 */
    264 	protected void setBody(Element root, Mail mail) {
    265 		Element bodyElem = root.getChild("body");
    266 		if (bodyElem != null) {
    267 			mail.setText(bodyElem.getTextTrim());
    268 		}
    269 	}
    270
    271 	/***
    272 	 * @param root
    273 	 * @param mail
    274 	 */
    275 	protected void setHtml(Element root, Mail mail) {
    276 		Element htmlElem = root.getChild("html");
    277 		if (htmlElem != null) {
    278 			mail.setHtmlText(htmlElem.getTextTrim());
    279 		}
    280 	}
    281
    282 	/***
    283 	 * @param root
    284 	 * @param mail
    285 	 */
    286 	protected void setSubject(Element root, Mail mail) {
    287 		Element subjectElem = root.getChild("subject");
    288 		if (subjectElem != null) {
    289 			mail.setSubject(subjectElem.getTextTrim());
    290 		}
    291 	}
    292
    293 	/***
    294 	 * @param root
    295 	 * @param mail
    296 	 */
    297 	protected void setRecipients(Element root, Mail mail) {
    298 		Element recipientsElem = root.getChild("recipients");
    299 		if (recipientsElem == null) {
    300 			return;
    301 		}
    302
    303 		List recipientElemList = recipientsElem.getChildren();
    304 		for (int i = 0, max = recipientElemList.size(); i < max; i++) {
    305 			Element e = (Element)recipientElemList.get(i);
    306 			if ("to".equals(e.getName())) { // to
    307 				if (e.getAttributeValue("email") != null) {
    308 					if (e.getAttributeValue("name") != null) {
    309 						mail.addTo(e.getAttributeValue("email"), e.getAttributeValue("name"));
    310 					} else {
    311 						mail.addTo(e.getAttributeValue("email"));
    312 					}
    313 				}
    314 			} else if ("cc".equals(e.getName())) { // cc
    315 				if (e.getAttributeValue("email") != null) {
    316 					if (e.getAttributeValue("name") != null) {
    317 						mail.addCc(e.getAttributeValue("email"), e.getAttributeValue("name"));
    318 					} else {
    319 						mail.addCc(e.getAttributeValue("email"));
    320 					}
    321 				}
    322 			} else {
    323 				if (e.getAttributeValue("email") != null) { // bcc
    324 					mail.addBcc(e.getAttributeValue("email"));
    325 				}
    326 			}
    327 		}
    328 	}
    329
    330 	/***
    331 	 * @param root
    332 	 * @param mail
    333 	 */
    334 	protected void setFrom(Element root, Mail mail) {
    335 		Element fromElem = root.getChild("from");
    336 		if (fromElem != null && fromElem.getAttributeValue("email") != null) {
    337 			if (fromElem.getAttributeValue("name") != null) {
    338 				mail.setFrom(fromElem.getAttributeValue("email"), fromElem
    339 						.getAttributeValue("name"));
    340 			} else {
    341 				mail.setFrom(fromElem.getAttributeValue("email"));
    342 			}
    343 		}
    344 	}
    345
    346 	/***
    347 	 * @see com.ozacc.mail.VelocityMailBuilder#clearCache()
    348 	 */
    349 	public synchronized void clearCache() {
    350 		log.debug("テンプレートキャッシュをクリアします。");
    351 		templateCache.clear();
    352 	}
    353
    354 	/***
    355 	 * @see com.ozacc.mail.VelocityMailBuilder#isCacheEnabled()
    356 	 */
    357 	public boolean isCacheEnabled() {
    358 		return cacheEnabled;
    359 	}
    360
    361 	/***
    362 	 * @see com.ozacc.mail.VelocityMailBuilder#setCacheEnabled(boolean)
    363 	 */
    364 	public void setCacheEnabled(boolean cacheEnabled) {
    365 		if (!cacheEnabled) {
    366 			clearCache();
    367 		}
    368 		this.cacheEnabled = cacheEnabled;
    369 	}
    370
    371 	protected boolean hasTemplateCache(String key) {
    372 		if (cacheEnabled) {
    373 			return templateCache.containsKey(key);
    374 		}
    375 		return false;
    376 	}
    377
    378 	protected void putTemplateCache(String key, String templateXmlText) {
    379 		if (cacheEnabled) {
    380 			log.debug("テンプレートをキャッシュします。[key='" + key + "']");
    381 			templateCache.put(key, templateXmlText);
    382 		}
    383 	}
    384
    385 	protected String getTemplateCache(String key) {
    386 		if (hasTemplateCache(key)) {
    387 			log.debug("テンプレートキャッシュを返します。[key='" + key + "']");
    388 			return (String)templateCache.get(key);
    389 		}
    390 		return null;
    391 	}
    392
    393 }