OSDN Git Service

CVS最新版の全ファイルを追加
[spring-ext/ozacc-mail.git] / src / java / com / ozacc / mail / impl / JDomXMLMailBuilder.java
1 package com.ozacc.mail.impl;\r
2 \r
3 import java.io.File;\r
4 import java.io.IOException;\r
5 import java.io.InputStream;\r
6 import java.io.StringReader;\r
7 import java.io.StringWriter;\r
8 import java.util.HashMap;\r
9 import java.util.Iterator;\r
10 import java.util.List;\r
11 import java.util.Map;\r
12 \r
13 import org.apache.commons.logging.Log;\r
14 import org.apache.commons.logging.LogFactory;\r
15 import org.apache.velocity.VelocityContext;\r
16 import org.apache.velocity.app.Velocity;\r
17 import org.apache.velocity.exception.MethodInvocationException;\r
18 import org.apache.velocity.exception.ParseErrorException;\r
19 import org.apache.velocity.exception.ResourceNotFoundException;\r
20 import org.apache.velocity.runtime.log.LogSystem;\r
21 import org.jdom.Document;\r
22 import org.jdom.Element;\r
23 import org.jdom.JDOMException;\r
24 import org.jdom.input.SAXBuilder;\r
25 import org.jdom.output.XMLOutputter;\r
26 \r
27 import com.ozacc.mail.Mail;\r
28 import com.ozacc.mail.MailBuildException;\r
29 import com.ozacc.mail.MultipleMailBuilder;\r
30 import com.ozacc.mail.VelocityMultipleMailBuilder;\r
31 \r
32 /**\r
33  * <a href="http://www.jdom.org/">JDOM</a>を利用してXMLファイルからMailインスタンスを生成するクラス。\r
34  * <p>\r
35  * ソースXMLを読み込む際に、DTDバリデーションが実行されますので妥当なXMLデータ(Valid XML Document)でなければいけません。\r
36  * \r
37  * @since 1.0\r
38  * \r
39  * @author Tomohiro Otsuka\r
40  * @version $Id: JDomXMLMailBuilder.java,v 1.10.2.5 2005/02/01 20:37:49 otsuka Exp $\r
41  */\r
42 public class JDomXMLMailBuilder implements MultipleMailBuilder, VelocityMultipleMailBuilder {\r
43 \r
44         private static Log log = LogFactory.getLog(JDomXMLMailBuilder.class);\r
45 \r
46         private static String CACHE_KEY_SEPARATOR = "#";\r
47 \r
48         private static String DEFAULT_MAIL_ID = "DEFAULT";\r
49 \r
50         protected LogSystem velocityLogSystem = new VelocityLogSystem();\r
51 \r
52         private boolean cacheEnabled = false;\r
53 \r
54         protected Map templateCache = new HashMap();\r
55 \r
56         /**\r
57          * コンストラクタ。\r
58          */\r
59         public JDomXMLMailBuilder() {}\r
60 \r
61         /**\r
62          * 指定されたクラスパス上のXMLファイルからMailインスタンスを生成します。\r
63          * \r
64          * @param classPath メール内容を記述したXMLファイルのパス\r
65          * @return 生成されたMailインスタンス\r
66          * @throws MailBuildException Mailインスタンスの生成に失敗した場合\r
67          */\r
68         public Mail buildMail(String classPath) throws MailBuildException {\r
69                 Document doc = getDocumentFromClassPath(classPath);\r
70                 return build(doc.getRootElement());\r
71         }\r
72 \r
73         /**\r
74          * 指定されたクラスパス上のXMLファイルからMailインスタンスを生成します。\r
75          * 指定されたVelocityContextを使って、XMLファイルの内容を動的に生成できます。\r
76          * \r
77          * @param classPath メール内容を記述したXMLファイルのパス\r
78          * @param context VelocityContext\r
79          * @return 生成されたMailインスタンス\r
80          * @throws MailBuildException Mailインスタンスの生成に失敗した場合\r
81          */\r
82         public Mail buildMail(String classPath, VelocityContext context) throws MailBuildException {\r
83                 String cacheKey = classPath + CACHE_KEY_SEPARATOR + DEFAULT_MAIL_ID;\r
84                 String templateXmlText;\r
85                 if (!hasTemplateCache(cacheKey)) {\r
86                         Document doc = getDocumentFromClassPath(classPath);\r
87                         templateXmlText = cacheTemplateText(doc, cacheKey);\r
88                 } else {\r
89                         templateXmlText = getTemplateCache(cacheKey);\r
90                 }\r
91                 try {\r
92                         return build(templateXmlText, context);\r
93                 } catch (Exception e) {\r
94                         throw new MailBuildException("メールの生成に失敗しました。", e);\r
95                 }\r
96         }\r
97 \r
98         /**\r
99          * 指定されたXMLファイルからMailインスタンスを生成します。\r
100          * \r
101          * @param file メール内容を記述したXMLファイル\r
102          * @return 生成されたMailインスタンス\r
103          * @throws MailBuildException Mailインスタンスの生成に失敗した場合\r
104          */\r
105         public Mail buildMail(File file) throws MailBuildException {\r
106                 Document doc = getDocumentFromFile(file);\r
107                 return build(doc.getRootElement());\r
108         }\r
109 \r
110         /**\r
111          * 指定されたXMLファイルからMailインスタンスを生成します。\r
112          * 指定されたVelocityContextを使って、XMLファイルの内容を動的に生成できます。\r
113          * \r
114          * @param file メール内容を記述したXMLファイル\r
115          * @param context VelocityContext\r
116          * @return 生成されたMailインスタンス\r
117          * @throws MailBuildException Mailインスタンスの生成に失敗した場合\r
118          */\r
119         public Mail buildMail(File file, VelocityContext context) throws MailBuildException {\r
120                 String cacheKey = file.getAbsolutePath() + CACHE_KEY_SEPARATOR + DEFAULT_MAIL_ID;\r
121                 String templateXmlText;\r
122                 if (!hasTemplateCache(cacheKey)) {\r
123                         Document doc = getDocumentFromFile(file);\r
124                         templateXmlText = cacheTemplateText(doc, cacheKey);\r
125                 } else {\r
126                         templateXmlText = getTemplateCache(cacheKey);\r
127                 }\r
128                 try {\r
129                         return build(templateXmlText, context);\r
130                 } catch (Exception e) {\r
131                         throw new MailBuildException("メールの生成に失敗しました。", e);\r
132                 }\r
133         }\r
134 \r
135         private String cacheTemplateText(Document doc, String cacheKey) {\r
136                 XMLOutputter output = new XMLOutputter();\r
137                 String templateXmlText = "<!DOCTYPE mail PUBLIC \"" + Mail.DOCTYPE_PUBLIC + "\" \""\r
138                                 + Mail.DOCTYPE_SYSTEM + "\">\n" + output.outputString(doc.getRootElement());\r
139                 log.debug("以下のXMLデータをキャッシュします。\n" + templateXmlText);\r
140                 putTemplateCache(cacheKey, templateXmlText);\r
141                 return templateXmlText;\r
142         }\r
143 \r
144         /**\r
145          * 指定されたクラスパス上のファイルを読み込んで、XMLドキュメントを生成します。\r
146          * \r
147          * @param classPath\r
148          * @return JDOM Document\r
149          */\r
150         protected Document getDocumentFromClassPath(String classPath) throws MailBuildException {\r
151                 InputStream is = getClass().getResourceAsStream(classPath);\r
152                 SAXBuilder builder = new SAXBuilder(true);\r
153                 builder.setEntityResolver(new DTDEntityResolver());\r
154                 Document doc;\r
155                 try {\r
156                         doc = builder.build(is);\r
157                 } catch (JDOMException e) {\r
158                         throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);\r
159                 } catch (IOException e) {\r
160                         throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);\r
161                 } finally {\r
162                         if (is != null) {\r
163                                 try {\r
164                                         is.close();\r
165                                 } catch (IOException e) {\r
166                                         // ignore\r
167                                 }\r
168                         }\r
169                 }\r
170                 return doc;\r
171         }\r
172 \r
173         /**\r
174          * 指定されたファイルを読み込んで、XMLドキュメントを生成します。\r
175          * \r
176          * @param file\r
177          * @return JDOM Document\r
178          */\r
179         protected Document getDocumentFromFile(File file) {\r
180                 SAXBuilder builder = new SAXBuilder(true);\r
181                 builder.setEntityResolver(new DTDEntityResolver());\r
182                 Document doc;\r
183                 try {\r
184                         doc = builder.build(file);\r
185                 } catch (JDOMException e) {\r
186                         throw new MailBuildException("XMLのパースに失敗しました。" + e.getMessage(), e);\r
187                 } catch (IOException e) {\r
188                         throw new MailBuildException("XMLファイルの読み込みに失敗しました。", e);\r
189                 }\r
190                 return doc;\r
191         }\r
192 \r
193         /**\r
194          * XMLのmailルートエレメントからMailインスタンスを生成します。\r
195          * \r
196          * @param mailElement mail要素を示すElementインスタンス\r
197          * @return Mail 生成されたMail\r
198          */\r
199         protected Mail build(Element mailElement) {\r
200                 Mail mail = new Mail();\r
201                 setFrom(mailElement, mail);\r
202                 setRecipients(mailElement, mail);\r
203                 setSubject(mailElement, mail);\r
204                 setBody(mailElement, mail);\r
205                 setReplyTo(mailElement, mail);\r
206                 setReturnPath(mailElement, mail);\r
207 \r
208                 setHtml(mailElement, mail);\r
209 \r
210                 return mail;\r
211         }\r
212 \r
213         /**\r
214          * VelocityContextとXMLテンプレートをマージさせ、Mailインスタンスを生成します。\r
215          * \r
216          * @param templateText マージするXMLテンプレートの文字列\r
217          * @param context マージするVelocityContext\r
218          * @return Mail\r
219          * \r
220          * @throws Exception\r
221          * @throws ParseErrorException\r
222          * @throws MethodInvocationException\r
223          * @throws ResourceNotFoundException\r
224          * @throws IOException\r
225          * @throws JDOMException \r
226          */\r
227         protected Mail build(String templateText, VelocityContext context) throws Exception,\r
228                                                                                                                                                 ParseErrorException,\r
229                                                                                                                                                 MethodInvocationException,\r
230                                                                                                                                                 ResourceNotFoundException,\r
231                                                                                                                                                 IOException, JDOMException {\r
232                 if (log.isDebugEnabled()) {\r
233                         log.debug("ソースXMLデータ\n" + templateText);\r
234                 }\r
235 \r
236                 Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, velocityLogSystem);\r
237                 Velocity.init();\r
238                 StringWriter w = new StringWriter();\r
239                 Velocity.evaluate(context, w, "XML Mail Data", templateText);\r
240 \r
241                 if (log.isDebugEnabled()) {\r
242                         log.debug("VelocityContextとマージ後のXMLデータ\n" + w.toString());\r
243                 }\r
244 \r
245                 StringReader reader = new StringReader(w.toString());\r
246                 SAXBuilder builder = new SAXBuilder(true);\r
247                 builder.setEntityResolver(new DTDEntityResolver());\r
248                 Document mergedDoc = builder.build(reader);\r
249 \r
250                 return build(mergedDoc.getRootElement());\r
251         }\r
252 \r
253         /**\r
254          * @param root\r
255          * @param mail \r
256          */\r
257         protected void setReturnPath(Element root, Mail mail) {\r
258                 Element returnPathElem = root.getChild("returnPath");\r
259                 if (returnPathElem != null && returnPathElem.getAttributeValue("email") != null) {\r
260                         mail.setReturnPath(returnPathElem.getAttributeValue("email"));\r
261                 }\r
262         }\r
263 \r
264         /**\r
265          * @param root\r
266          * @param mail \r
267          */\r
268         protected void setReplyTo(Element root, Mail mail) {\r
269                 Element replyToElem = root.getChild("replyTo");\r
270                 if (replyToElem != null && replyToElem.getAttributeValue("email") != null) {\r
271                         mail.setReplyTo(replyToElem.getAttributeValue("email"));\r
272                 }\r
273         }\r
274 \r
275         /**\r
276          * @param root\r
277          * @param mail \r
278          */\r
279         protected void setBody(Element root, Mail mail) {\r
280                 Element bodyElem = root.getChild("body");\r
281                 if (bodyElem != null) {\r
282                         mail.setText(bodyElem.getTextTrim());\r
283                 }\r
284         }\r
285 \r
286         /**\r
287          * @param root\r
288          * @param mail\r
289          */\r
290         protected void setHtml(Element root, Mail mail) {\r
291                 Element htmlElem = root.getChild("html");\r
292                 if (htmlElem != null) {\r
293                         mail.setHtmlText(htmlElem.getTextTrim());\r
294                 }\r
295         }\r
296 \r
297         /**\r
298          * @param root\r
299          * @param mail \r
300          */\r
301         protected void setSubject(Element root, Mail mail) {\r
302                 Element subjectElem = root.getChild("subject");\r
303                 if (subjectElem != null) {\r
304                         mail.setSubject(subjectElem.getTextTrim());\r
305                 }\r
306         }\r
307 \r
308         /**\r
309          * @param root\r
310          * @param mail \r
311          */\r
312         protected void setRecipients(Element root, Mail mail) {\r
313                 Element recipientsElem = root.getChild("recipients");\r
314                 if (recipientsElem == null) {\r
315                         return;\r
316                 }\r
317 \r
318                 List recipientElemList = recipientsElem.getChildren();\r
319                 for (int i = 0, max = recipientElemList.size(); i < max; i++) {\r
320                         Element e = (Element)recipientElemList.get(i);\r
321                         if ("to".equals(e.getName())) { // to\r
322                                 if (e.getAttributeValue("email") != null) {\r
323                                         if (e.getAttributeValue("name") != null) {\r
324                                                 mail.addTo(e.getAttributeValue("email"), e.getAttributeValue("name"));\r
325                                         } else {\r
326                                                 mail.addTo(e.getAttributeValue("email"));\r
327                                         }\r
328                                 }\r
329                         } else if ("cc".equals(e.getName())) { // cc\r
330                                 if (e.getAttributeValue("email") != null) {\r
331                                         if (e.getAttributeValue("name") != null) {\r
332                                                 mail.addCc(e.getAttributeValue("email"), e.getAttributeValue("name"));\r
333                                         } else {\r
334                                                 mail.addCc(e.getAttributeValue("email"));\r
335                                         }\r
336                                 }\r
337                         } else {\r
338                                 if (e.getAttributeValue("email") != null) { // bcc\r
339                                         mail.addBcc(e.getAttributeValue("email"));\r
340                                 }\r
341                         }\r
342                 }\r
343         }\r
344 \r
345         /**\r
346          * @param root\r
347          * @param mail \r
348          */\r
349         protected void setFrom(Element root, Mail mail) {\r
350                 Element fromElem = root.getChild("from");\r
351                 if (fromElem != null && fromElem.getAttributeValue("email") != null) {\r
352                         if (fromElem.getAttributeValue("name") != null) {\r
353                                 mail.setFrom(fromElem.getAttributeValue("email"), fromElem\r
354                                                 .getAttributeValue("name"));\r
355                         } else {\r
356                                 mail.setFrom(fromElem.getAttributeValue("email"));\r
357                         }\r
358                 }\r
359         }\r
360 \r
361         /**\r
362          * @see com.ozacc.mail.VelocityMailBuilder#clearCache()\r
363          */\r
364         public synchronized void clearCache() {\r
365                 log.debug("テンプレートキャッシュをクリアします。");\r
366                 templateCache.clear();\r
367         }\r
368 \r
369         /**\r
370          * @see com.ozacc.mail.VelocityMailBuilder#isCacheEnabled()\r
371          */\r
372         public boolean isCacheEnabled() {\r
373                 return cacheEnabled;\r
374         }\r
375 \r
376         /**\r
377          * @see com.ozacc.mail.VelocityMailBuilder#setCacheEnabled(boolean)\r
378          */\r
379         public void setCacheEnabled(boolean cacheEnabled) {\r
380                 if (!cacheEnabled) {\r
381                         clearCache();\r
382                 }\r
383                 this.cacheEnabled = cacheEnabled;\r
384         }\r
385 \r
386         protected boolean hasTemplateCache(String key) {\r
387                 if (cacheEnabled) {\r
388                         return templateCache.containsKey(key);\r
389                 }\r
390                 return false;\r
391         }\r
392 \r
393         protected void putTemplateCache(String key, String templateXmlText) {\r
394                 if (cacheEnabled) {\r
395                         log.debug("テンプレートをキャッシュします。[key='" + key + "']");\r
396                         templateCache.put(key, templateXmlText);\r
397                 }\r
398         }\r
399 \r
400         protected String getTemplateCache(String key) {\r
401                 if (hasTemplateCache(key)) {\r
402                         log.debug("テンプレートキャッシュを返します。[key='" + key + "']");\r
403                         return (String)templateCache.get(key);\r
404                 }\r
405                 return null;\r
406         }\r
407 \r
408         /**\r
409          * @see com.ozacc.mail.VelocityMultipleMailBuilder#buildMail(java.lang.String, org.apache.velocity.VelocityContext, java.lang.String)\r
410          */\r
411         public Mail buildMail(String classPath, VelocityContext context, String mailId)\r
412                                                                                                                                                                         throws MailBuildException {\r
413                 if (mailId == null || "".equals(mailId)) {\r
414                         throw new IllegalArgumentException("メールIDが指定されていません。");\r
415                 }\r
416 \r
417                 String cacheKey = classPath + CACHE_KEY_SEPARATOR + mailId;\r
418                 String templateXmlText;\r
419                 if (!hasTemplateCache(cacheKey)) {\r
420                         Document doc = getDocumentFromClassPath(classPath);\r
421                         templateXmlText = getAndCacheTemplateText(doc, mailId, cacheKey);\r
422                 } else {\r
423                         templateXmlText = getTemplateCache(cacheKey);\r
424                 }\r
425                 try {\r
426                         return build(templateXmlText, context);\r
427                 } catch (Exception e) {\r
428                         throw new MailBuildException("メールの生成に失敗しました。", e);\r
429                 }\r
430         }\r
431 \r
432         private String getAndCacheTemplateText(Document doc, String mailId, String cacheKey)\r
433                                                                                                                                                                                 throws MailBuildException {\r
434                 Element mailElem = getElementById(doc, mailId);\r
435                 XMLOutputter output = new XMLOutputter();\r
436                 String templateXmlText = output.outputString(mailElem);\r
437 \r
438                 putTemplateCache(cacheKey, templateXmlText);\r
439                 return templateXmlText;\r
440         }\r
441 \r
442         /**\r
443          * @see com.ozacc.mail.VelocityMultipleMailBuilder#buildMail(java.io.File, org.apache.velocity.VelocityContext, java.lang.String)\r
444          */\r
445         public Mail buildMail(File file, VelocityContext context, String mailId)\r
446                                                                                                                                                         throws MailBuildException {\r
447                 if (mailId == null || "".equals(mailId)) {\r
448                         throw new IllegalArgumentException("メールIDが指定されていません。");\r
449                 }\r
450 \r
451                 String cacheKey = file.getAbsolutePath() + CACHE_KEY_SEPARATOR + mailId;\r
452                 String templateXmlText;\r
453                 if (!hasTemplateCache(cacheKey)) {\r
454                         Document doc = getDocumentFromFile(file);\r
455                         templateXmlText = getAndCacheTemplateText(doc, mailId, cacheKey);\r
456                 } else {\r
457                         templateXmlText = getTemplateCache(cacheKey);\r
458                 }\r
459                 try {\r
460                         return build(templateXmlText, context);\r
461                 } catch (Exception e) {\r
462                         throw new MailBuildException("メールの生成に失敗しました。", e);\r
463                 }\r
464         }\r
465 \r
466         /**\r
467          * @see com.ozacc.mail.MultipleMailBuilder#buildMail(java.lang.String, java.lang.String)\r
468          */\r
469         public Mail buildMail(String classPath, String mailId) throws MailBuildException {\r
470                 Document doc = getDocumentFromClassPath(classPath);\r
471                 Element mailElem = getElementById(doc, mailId);\r
472                 return build(mailElem);\r
473         }\r
474 \r
475         /**\r
476          * @see com.ozacc.mail.MultipleMailBuilder#buildMail(java.io.File, java.lang.String)\r
477          */\r
478         public Mail buildMail(File file, String mailId) throws MailBuildException {\r
479                 Document doc = getDocumentFromFile(file);\r
480                 Element mailElem = getElementById(doc, mailId);\r
481                 return build(mailElem);\r
482         }\r
483 \r
484         /**\r
485          * 指定されたXMLドキュメントの中から、指定されたid属性がセットされている要素を取得します。\r
486          * \r
487          * @param doc XMLドキュメント\r
488          * @param id 抽出する要素のid属性値\r
489          * @return XMLドキュメントで見つかったid属性を持つ要素\r
490          */\r
491         private Element getElementById(Document doc, String id) {\r
492                 Element mailsElem = doc.getRootElement(); // <mails>\r
493                 List mailElemList = mailsElem.getChildren("mail");\r
494                 for (Iterator itr = mailElemList.iterator(); itr.hasNext();) {\r
495                         Element mailElem = (Element)itr.next();\r
496                         String mailId = mailElem.getAttributeValue("id");\r
497                         if (mailId.equals(id)) {\r
498                                 return mailElem;\r
499                         }\r
500                 }\r
501                 throw new MailBuildException("指定されたID[" + id + "]のメールデータは見つかりませんでした。");\r
502         }\r
503 \r
504 }