View Javadoc

    1   package com.ozacc.mail.impl;
    2
    3   import java.io.File;
    4   import java.io.IOException;
    5   import java.io.StringReader;
    6   import java.io.StringWriter;
    7   import java.util.HashMap;
    8   import java.util.Map;
    9   import java.util.Properties;
    10
    11  import javax.xml.parsers.DocumentBuilder;
    12  import javax.xml.transform.OutputKeys;
    13  import javax.xml.transform.Transformer;
    14  import javax.xml.transform.TransformerConfigurationException;
    15  import javax.xml.transform.TransformerException;
    16  import javax.xml.transform.TransformerFactory;
    17  import javax.xml.transform.TransformerFactoryConfigurationError;
    18  import javax.xml.transform.dom.DOMSource;
    19  import javax.xml.transform.stream.StreamResult;
    20
    21  import org.apache.commons.logging.Log;
    22  import org.apache.commons.logging.LogFactory;
    23  import org.apache.velocity.VelocityContext;
    24  import org.apache.velocity.app.Velocity;
    25  import org.apache.velocity.exception.MethodInvocationException;
    26  import org.apache.velocity.exception.ParseErrorException;
    27  import org.apache.velocity.exception.ResourceNotFoundException;
    28  import org.apache.velocity.runtime.log.LogSystem;
    29  import org.w3c.dom.Document;
    30  import org.xml.sax.InputSource;
    31  import org.xml.sax.SAXException;
    32
    33  import com.ozacc.mail.Mail;
    34  import com.ozacc.mail.MailBuildException;
    35  import com.ozacc.mail.VelocityMailBuilder;
    36
    37  /***
    38   * XMLファイルを読み込み、Velocityと連携して動的にメールデータを生成し、そのデータからMailインスタンスを生成するクラス。
    39   *
    40   * @since 1.0.1
    41   * @author Tomohiro Otsuka
    42   * @version $Id: XMLVelocityMailBuilderImpl.java,v 1.4.2.2 2004/11/25 08:01:07 otsuka Exp $
    43   */
    44  public class XMLVelocityMailBuilderImpl extends XMLMailBuilderImpl implements VelocityMailBuilder {
    45
    46  	private static Log log = LogFactory.getLog(XMLVelocityMailBuilderImpl.class);
    47
    48  	protected String charset = "UTF-8";
    49
    50  	protected LogSystem velocityLogSystem = new VelocityLogSystem();
    51
    52  	protected Map templateCache = new HashMap();
    53
    54  	private boolean cacheEnabled = false;
    55
    56  	protected boolean hasTemplateCache(String key) {
    57  		if (cacheEnabled) {
    58  			return templateCache.containsKey(key);
    59  		}
    60  		return false;
    61  	}
    62
    63  	protected void putTemplateCache(String key, String templateXmlText) {
    64  		if (cacheEnabled) {
    65  			log.debug("テンプレートをキャッシュします。[key='" + key + "']");
    66  			templateCache.put(key, templateXmlText);
    67  		}
    68  	}
    69
    70  	protected String getTemplateCache(String key) {
    71  		if (hasTemplateCache(key)) {
    72  			log.debug("テンプレートキャッシュを返します。[key='" + key + "']");
    73  			return (String)templateCache.get(key);
    74  		}
    75  		return null;
    76  	}
    77
    78  	/***
    79  	 * @see com.ozacc.mail.VelocityMailBuilder#clearCache()
    80  	 */
    81  	public synchronized void clearCache() {
    82  		log.debug("テンプレートキャッシュをクリアします。");
    83  		templateCache.clear();
    84  	}
    85
    86  	/***
    87  	 * @see com.ozacc.mail.VelocityMailBuilder#isCacheEnabled()
    88  	 */
    89  	public boolean isCacheEnabled() {
    90  		return cacheEnabled;
    91  	}
    92
    93  	/***
    94  	 * @see com.ozacc.mail.VelocityMailBuilder#setCacheEnabled(boolean)
    95  	 */
    96  	public void setCacheEnabled(boolean cacheEnabled) {
    97  		if (!cacheEnabled) {
    98  			clearCache();
    99  		}
    100 		this.cacheEnabled = cacheEnabled;
    101 	}
    102
    103 	/***
    104 	 * @see com.ozacc.mail.VelocityMailBuilder#buildMail(java.lang.String, org.apache.velocity.VelocityContext)
    105 	 */
    106 	public Mail buildMail(String classPath, VelocityContext context) throws MailBuildException {
    107 		String templateXmlText;
    108 		if (!hasTemplateCache(classPath)) {
    109 			Document doc;
    110 			try {
    111 				// Velocityマージ前のXMLではコメントを許可する
    112 				doc = getDocumentFromClassPath(classPath, false);
    113 			} catch (SAXException e) {
    114 				throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
    115 			} catch (IOException e) {
    116 				throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
    117 			}
    118 			templateXmlText = convertDocumentIntoString(doc);
    119 			putTemplateCache(classPath, templateXmlText);
    120 		} else {
    121 			templateXmlText = getTemplateCache(classPath);
    122 		}
    123
    124 		try {
    125 			return build(templateXmlText, context);
    126 		} catch (Exception e) {
    127 			throw new MailBuildException("メールの生成に失敗しました。", e);
    128 		}
    129 	}
    130
    131 	/***
    132 	 * @see com.ozacc.mail.VelocityMailBuilder#buildMail(java.io.File, org.apache.velocity.VelocityContext)
    133 	 */
    134 	public Mail buildMail(File file, VelocityContext context) throws MailBuildException {
    135 		String templateXmlText;
    136 		if (!hasTemplateCache(file.getAbsolutePath())) {
    137 			Document doc;
    138 			try {
    139 				// Velocityマージ前のXMLではコメントを許可する
    140 				doc = getDocumentFromFile(file, false);
    141 			} catch (SAXException e) {
    142 				throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
    143 			} catch (IOException e) {
    144 				throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
    145 			}
    146 			templateXmlText = convertDocumentIntoString(doc);
    147 			putTemplateCache(file.getAbsolutePath(), templateXmlText);
    148 		} else {
    149 			templateXmlText = getTemplateCache(file.getAbsolutePath());
    150 		}
    151
    152 		try {
    153 			return build(templateXmlText, context);
    154 		} catch (Exception e) {
    155 			throw new MailBuildException("メールの生成に失敗しました。", e);
    156 		}
    157 	}
    158
    159 	/***
    160 	 * メールデータをVelocityContextとマージして生成されたXMLからMailインスタンスを生成します。
    161 	 *
    162 	 * @param templateXmlText メールデータのテンプレート
    163 	 * @param context テンプレートにマージする内容を格納したVelocityContext
    164 	 * @return VelocityContextをテンプレートにマージして生成されたXMLから生成されたMailインスタンス
    165 	 * @throws TransformerFactoryConfigurationError
    166 	 * @throws Exception
    167 	 * @throws ParseErrorException
    168 	 * @throws MethodInvocationException
    169 	 * @throws ResourceNotFoundException
    170 	 * @throws IOException
    171 	 */
    172 	protected Mail build(String templateXmlText, VelocityContext context)
    173 																			throws TransformerFactoryConfigurationError,
    174 																			Exception,
    175 																			ParseErrorException,
    176 																			MethodInvocationException,
    177 																			ResourceNotFoundException,
    178 																			IOException {
    179 		if (log.isDebugEnabled()) {
    180 			log.debug("Source XML Mail Data\n" + templateXmlText);
    181 		}
    182
    183 		Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, velocityLogSystem);
    184 		Velocity.init();
    185 		StringWriter w = new StringWriter();
    186 		Velocity.evaluate(context, w, "XML Mail Data", templateXmlText);
    187 		StringReader reader = new StringReader(w.toString());
    188
    189 		DocumentBuilder db = createDocumentBuilder();
    190 		InputSource source = new InputSource(reader);
    191 		Document newDoc = db.parse(source);
    192
    193 		if (log.isDebugEnabled()) {
    194 			String newXmlContent = convertDocumentIntoString(newDoc);
    195 			log.debug("VelocityContext-merged XML Mail Data\n" + newXmlContent);
    196 		}
    197
    198 		return buildMail(newDoc);
    199 	}
    200
    201 	/***
    202 	 * 指定されたDOM Documentを文字列に変換します。
    203 	 *
    204 	 * @param doc
    205 	 * @return XMLドキュメントの文字列
    206 	 * @throws TransformerFactoryConfigurationError
    207 	 */
    208 	protected String convertDocumentIntoString(Document doc)
    209 															throws TransformerFactoryConfigurationError {
    210 		TransformerFactory tf = TransformerFactory.newInstance();
    211 		Transformer t;
    212 		try {
    213 			t = tf.newTransformer();
    214 		} catch (TransformerConfigurationException e) {
    215 			throw new MailBuildException(e.getMessage(), e);
    216 		}
    217 		t.setOutputProperties(getOutputProperties());
    218
    219 		DOMSource source = new DOMSource(doc);
    220 		StringWriter w = new StringWriter();
    221 		StreamResult result = new StreamResult(w);
    222 		try {
    223 			t.transform(source, result);
    224 		} catch (TransformerException e) {
    225 			throw new MailBuildException(e.getMessage(), e);
    226 		}
    227
    228 		return w.toString();
    229 	}
    230
    231 	/***
    232 	 * 出力プロパティを生成。
    233 	 * @return 出力プロパティを設定したPropertiesインスタンス
    234 	 */
    235 	protected Properties getOutputProperties() {
    236 		Properties p = new Properties();
    237 		p.put(OutputKeys.ENCODING, charset);
    238 		p.put(OutputKeys.DOCTYPE_PUBLIC, Mail.DOCTYPE_PUBLIC);
    239 		p.put(OutputKeys.DOCTYPE_SYSTEM, Mail.DOCTYPE_SYSTEM);
    240 		return p;
    241 	}
    242
    243 }