1 package com.ozacc.mail.impl;
\r
4 import java.io.IOException;
\r
5 import java.io.StringReader;
\r
6 import java.io.StringWriter;
\r
7 import java.util.HashMap;
\r
8 import java.util.Map;
\r
9 import java.util.Properties;
\r
11 import javax.xml.parsers.DocumentBuilder;
\r
12 import javax.xml.transform.OutputKeys;
\r
13 import javax.xml.transform.Transformer;
\r
14 import javax.xml.transform.TransformerConfigurationException;
\r
15 import javax.xml.transform.TransformerException;
\r
16 import javax.xml.transform.TransformerFactory;
\r
17 import javax.xml.transform.TransformerFactoryConfigurationError;
\r
18 import javax.xml.transform.dom.DOMSource;
\r
19 import javax.xml.transform.stream.StreamResult;
\r
21 import org.apache.commons.logging.Log;
\r
22 import org.apache.commons.logging.LogFactory;
\r
23 import org.apache.velocity.VelocityContext;
\r
24 import org.apache.velocity.app.Velocity;
\r
25 import org.apache.velocity.exception.MethodInvocationException;
\r
26 import org.apache.velocity.exception.ParseErrorException;
\r
27 import org.apache.velocity.exception.ResourceNotFoundException;
\r
28 import org.apache.velocity.runtime.log.LogSystem;
\r
29 import org.w3c.dom.Document;
\r
30 import org.w3c.dom.Element;
\r
31 import org.xml.sax.InputSource;
\r
32 import org.xml.sax.SAXException;
\r
34 import com.ozacc.mail.Mail;
\r
35 import com.ozacc.mail.MailBuildException;
\r
36 import com.ozacc.mail.VelocityMultipleMailBuilder;
\r
39 * XMLファイルを読み込み、Velocityと連携して動的にメールデータを生成し、そのデータからMailインスタンスを生成するクラス。
\r
42 * @author Tomohiro Otsuka
\r
43 * @version $Id: XMLVelocityMailBuilderImpl.java,v 1.4.2.4 2005/01/23 06:13:10 otsuka Exp $
\r
45 public class XMLVelocityMailBuilderImpl extends XMLMailBuilderImpl implements
\r
46 VelocityMultipleMailBuilder {
\r
48 private static Log log = LogFactory.getLog(XMLVelocityMailBuilderImpl.class);
\r
50 private static String CACHE_KEY_SEPARATOR = "#";
\r
52 private static String DEFAULT_MAIL_ID = "DEFAULT";
\r
54 protected String charset = "UTF-8";
\r
56 protected LogSystem velocityLogSystem = new VelocityLogSystem();
\r
58 protected Map templateCache = new HashMap();
\r
60 private boolean cacheEnabled = false;
\r
62 protected boolean hasTemplateCache(String key) {
\r
64 return templateCache.containsKey(key);
\r
69 protected void putTemplateCache(String key, String templateXmlText) {
\r
71 log.debug("テンプレートをキャッシュします。[key='" + key + "']");
\r
72 templateCache.put(key, templateXmlText);
\r
76 protected String getTemplateCache(String key) {
\r
77 if (hasTemplateCache(key)) {
\r
78 log.debug("テンプレートキャッシュを返します。[key='" + key + "']");
\r
79 return (String)templateCache.get(key);
\r
85 * @see com.ozacc.mail.VelocityMailBuilder#clearCache()
\r
87 public synchronized void clearCache() {
\r
88 log.debug("テンプレートキャッシュをクリアします。");
\r
89 templateCache.clear();
\r
93 * @see com.ozacc.mail.VelocityMailBuilder#isCacheEnabled()
\r
95 public boolean isCacheEnabled() {
\r
96 return cacheEnabled;
\r
100 * @see com.ozacc.mail.VelocityMailBuilder#setCacheEnabled(boolean)
\r
102 public void setCacheEnabled(boolean cacheEnabled) {
\r
103 if (!cacheEnabled) {
\r
106 this.cacheEnabled = cacheEnabled;
\r
110 * @see com.ozacc.mail.VelocityMailBuilder#buildMail(java.lang.String, org.apache.velocity.VelocityContext)
\r
112 public Mail buildMail(String classPath, VelocityContext context) throws MailBuildException {
\r
113 String cacheKey = classPath + CACHE_KEY_SEPARATOR + DEFAULT_MAIL_ID;
\r
115 String templateXmlText;
\r
116 if (!hasTemplateCache(cacheKey)) {
\r
119 // Velocityマージ前のXMLではコメントを許可する
\r
120 doc = getDocumentFromClassPath(classPath, false);
\r
121 } catch (SAXException e) {
\r
122 throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
\r
123 } catch (IOException e) {
\r
124 throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
\r
126 templateXmlText = convertDocumentIntoString(doc.getDocumentElement());
\r
127 putTemplateCache(cacheKey, templateXmlText);
\r
129 templateXmlText = getTemplateCache(cacheKey);
\r
133 return build(templateXmlText, context);
\r
134 } catch (Exception e) {
\r
135 throw new MailBuildException("メールの生成に失敗しました。", e);
\r
140 * @see com.ozacc.mail.VelocityMailBuilder#buildMail(java.io.File, org.apache.velocity.VelocityContext)
\r
142 public Mail buildMail(File file, VelocityContext context) throws MailBuildException {
\r
143 String cacheKey = file.getAbsolutePath() + CACHE_KEY_SEPARATOR + DEFAULT_MAIL_ID;
\r
145 String templateXmlText;
\r
146 if (!hasTemplateCache(cacheKey)) {
\r
149 // Velocityマージ前のXMLではコメントを許可する
\r
150 doc = getDocumentFromFile(file, false);
\r
151 } catch (SAXException e) {
\r
152 throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
\r
153 } catch (IOException e) {
\r
154 throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
\r
156 templateXmlText = convertDocumentIntoString(doc.getDocumentElement());
\r
157 putTemplateCache(cacheKey, templateXmlText);
\r
159 templateXmlText = getTemplateCache(cacheKey);
\r
163 return build(templateXmlText, context);
\r
164 } catch (Exception e) {
\r
165 throw new MailBuildException("メールの生成に失敗しました。", e);
\r
170 * メールデータをVelocityContextとマージして生成されたXMLからMailインスタンスを生成します。
\r
172 * @param templateXmlText メールデータのテンプレート
\r
173 * @param context テンプレートにマージする内容を格納したVelocityContext
\r
174 * @return VelocityContextをテンプレートにマージして生成されたXMLから生成されたMailインスタンス
\r
175 * @throws TransformerFactoryConfigurationError
\r
176 * @throws Exception
\r
177 * @throws ParseErrorException
\r
178 * @throws MethodInvocationException
\r
179 * @throws ResourceNotFoundException
\r
180 * @throws IOException
\r
182 protected synchronized Mail build(String templateXmlText, VelocityContext context)
\r
183 throws TransformerFactoryConfigurationError,
\r
185 ParseErrorException,
\r
186 MethodInvocationException,
\r
187 ResourceNotFoundException,
\r
189 if (log.isDebugEnabled()) {
\r
190 log.debug("Source XML Mail Data\n" + templateXmlText);
\r
193 Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, velocityLogSystem);
\r
195 StringWriter w = new StringWriter();
\r
196 Velocity.evaluate(context, w, "XML Mail Data", templateXmlText);
\r
197 StringReader reader = new StringReader(w.toString());
\r
199 DocumentBuilder db = createDocumentBuilder();
\r
200 InputSource source = new InputSource(reader);
\r
201 Document newDoc = db.parse(source);
\r
203 if (log.isDebugEnabled()) {
\r
204 String newXmlContent = convertDocumentIntoString(newDoc.getDocumentElement());
\r
205 log.debug("VelocityContext-merged XML Mail Data\n" + newXmlContent);
\r
208 return buildMail(newDoc.getDocumentElement());
\r
212 * 指定されたDOM Documentを文字列に変換します。
\r
214 * @param mailElement
\r
215 * @return XMLドキュメントの文字列
\r
216 * @throws TransformerFactoryConfigurationError
\r
218 protected String convertDocumentIntoString(Element mailElement)
\r
219 throws TransformerFactoryConfigurationError {
\r
220 TransformerFactory tf = TransformerFactory.newInstance();
\r
223 t = tf.newTransformer();
\r
224 } catch (TransformerConfigurationException e) {
\r
225 throw new MailBuildException(e.getMessage(), e);
\r
227 t.setOutputProperties(getOutputProperties());
\r
229 DOMSource source = new DOMSource(mailElement);
\r
230 StringWriter w = new StringWriter();
\r
231 StreamResult result = new StreamResult(w);
\r
233 t.transform(source, result);
\r
234 } catch (TransformerException e) {
\r
235 throw new MailBuildException(e.getMessage(), e);
\r
238 return w.toString();
\r
243 * @return 出力プロパティを設定したPropertiesインスタンス
\r
245 protected Properties getOutputProperties() {
\r
246 Properties p = new Properties();
\r
247 p.put(OutputKeys.ENCODING, charset);
\r
248 p.put(OutputKeys.DOCTYPE_PUBLIC, Mail.DOCTYPE_PUBLIC);
\r
249 p.put(OutputKeys.DOCTYPE_SYSTEM, Mail.DOCTYPE_SYSTEM);
\r
254 * @see com.ozacc.mail.VelocityMultipleMailBuilder#buildMail(java.lang.String, org.apache.velocity.VelocityContext, java.lang.String)
\r
256 public Mail buildMail(String classPath, VelocityContext context, String mailId)
\r
257 throws MailBuildException {
\r
258 if (mailId == null || "".equals(mailId)) {
\r
259 throw new IllegalArgumentException("メールIDが指定されていません。");
\r
262 String cacheKey = classPath + CACHE_KEY_SEPARATOR + mailId;
\r
264 String templateXmlText;
\r
265 if (!hasTemplateCache(cacheKey)) {
\r
268 // Velocityマージ前のXMLではコメントを許可する
\r
269 doc = getDocumentFromClassPath(classPath, false);
\r
270 } catch (SAXException e) {
\r
271 throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
\r
272 } catch (IOException e) {
\r
273 throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
\r
275 if (Mail.DOCTYPE_PUBLIC.equals(doc.getDoctype().getPublicId())) {
\r
276 throw new MailBuildException("指定されたクラスパスのXMLはシングルメールテンプレートです。[classPath='"
\r
277 + classPath + "']");
\r
279 templateXmlText = getAndCacheTemplateText(doc, mailId, cacheKey);
\r
281 templateXmlText = getTemplateCache(cacheKey);
\r
285 return build(templateXmlText, context);
\r
286 } catch (Exception e) {
\r
287 throw new MailBuildException("メールの生成に失敗しました。", e);
\r
291 private String getAndCacheTemplateText(Document doc, String mailId, String cacheKey)
\r
292 throws TransformerFactoryConfigurationError {
\r
293 Element mailElem = doc.getElementById(mailId);
\r
294 if (mailElem == null) {
\r
295 throw new MailBuildException("指定されたID[" + mailId + "]のメールデータは見つかりませんでした。");
\r
297 String templateXmlText = convertDocumentIntoString(mailElem);
\r
298 putTemplateCache(cacheKey, templateXmlText);
\r
299 return templateXmlText;
\r
303 * @see com.ozacc.mail.VelocityMultipleMailBuilder#buildMail(java.io.File, org.apache.velocity.VelocityContext, java.lang.String)
\r
305 public Mail buildMail(File file, VelocityContext context, String mailId)
\r
306 throws MailBuildException {
\r
307 if (mailId == null || "".equals(mailId)) {
\r
308 throw new IllegalArgumentException("メールIDが指定されていません。");
\r
311 String cacheKey = file.getAbsolutePath() + CACHE_KEY_SEPARATOR + mailId;
\r
313 String templateXmlText;
\r
314 if (!hasTemplateCache(cacheKey)) {
\r
317 // Velocityマージ前のXMLではコメントを許可する
\r
318 doc = getDocumentFromFile(file, false);
\r
319 } catch (SAXException e) {
\r
320 throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);
\r
321 } catch (IOException e) {
\r
322 throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);
\r
324 if (Mail.DOCTYPE_PUBLIC.equals(doc.getDoctype().getPublicId())) {
\r
325 throw new MailBuildException("指定されたファイルのXMLはシングルメールテンプレートです。[filePath='"
\r
326 + file.getAbsolutePath() + "']");
\r
328 templateXmlText = getAndCacheTemplateText(doc, mailId, cacheKey);
\r
330 templateXmlText = getTemplateCache(cacheKey);
\r
334 return build(templateXmlText, context);
\r
335 } catch (Exception e) {
\r
336 throw new MailBuildException("メールの生成に失敗しました。", e);
\r