KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > knowgate > scheduler > jobs > EmailSender


1 /*
2   Copyright (C) 2003 Know Gate S.L. All rights reserved.
3                       C/Oņa, 107 1š2 28050 Madrid (Spain)
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
8
9   1. Redistributions of source code must retain the above copyright
10      notice, this list of conditions and the following disclaimer.
11
12   2. The end-user documentation included with the redistribution,
13      if any, must include the following acknowledgment:
14      "This product includes software parts from hipergate
15      (http://www.hipergate.org/)."
16      Alternately, this acknowledgment may appear in the software itself,
17      if and wherever such third-party acknowledgments normally appear.
18
19   3. The name hipergate must not be used to endorse or promote products
20      derived from this software without prior written permission.
21      Products derived from this software may not be called hipergate,
22      nor may hipergate appear in their name, without prior written
23      permission.
24
25   This library is distributed in the hope that it will be useful,
26   but WITHOUT ANY WARRANTY; without even the implied warranty of
27   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28
29   You should have received a copy of hipergate License with this code;
30   if not, visit http://www.hipergate.org or mail to info@hipergate.org
31 */

32
33 package com.knowgate.scheduler.jobs;
34
35 import java.lang.ref.SoftReference JavaDoc;
36
37 import java.util.HashMap JavaDoc;
38 import java.util.Iterator JavaDoc;
39
40 import java.sql.SQLException JavaDoc;
41
42 import java.io.IOException JavaDoc;
43 import java.io.FileNotFoundException JavaDoc;
44 import java.io.FileReader JavaDoc;
45 import java.io.File JavaDoc;
46 import java.io.StringBufferInputStream JavaDoc;
47
48 import java.net.URL JavaDoc;
49 import java.net.MalformedURLException JavaDoc;
50
51 import javax.activation.DataHandler JavaDoc;
52 import javax.activation.DataSource JavaDoc;
53 import javax.activation.FileDataSource JavaDoc;
54 import javax.activation.URLDataSource JavaDoc;
55
56 import javax.mail.Session JavaDoc;
57 import javax.mail.Transport JavaDoc;
58 import javax.mail.MessagingException JavaDoc;
59 import javax.mail.NoSuchProviderException JavaDoc;
60 import javax.mail.BodyPart JavaDoc;
61
62 import javax.mail.internet.AddressException JavaDoc;
63 import javax.mail.internet.InternetAddress JavaDoc;
64 import javax.mail.internet.MimeMessage JavaDoc;
65 import javax.mail.internet.MimeBodyPart JavaDoc;
66 import javax.mail.internet.MimeMultipart JavaDoc;
67
68 import org.htmlparser.Parser;
69 import org.htmlparser.Node;
70 import org.htmlparser.util.NodeIterator;
71 import org.htmlparser.util.ParserException;
72 import org.htmlparser.tags.ImageTag;
73
74 import org.apache.oro.text.regex.*;
75
76 import com.knowgate.debug.DebugFile;
77 import com.knowgate.jdc.JDCConnection;
78 import com.knowgate.dataobjs.DB;
79 import com.knowgate.dataxslt.FastStreamReplacer;
80 import com.knowgate.dfs.FileSystem;
81
82 import com.knowgate.scheduler.Atom;
83 import com.knowgate.scheduler.Job;
84
85
86 /**
87  * <p>Add database fields to a document template and send it to a mail recipient</p>
88  * <p>Mails are send using Sun JavaMail</p>
89  * @author Sergio Montoro Ten
90  * @version 1.0
91  */

92
93 public class EmailSender extends Job {
94
95   // This flag is set if the first Job execution finds replacements of the form
96
// {#Section.Field} witch is data retrived from the database and inserted
97
// dynamically into the document final template.
98
// If the execution of this job for the first Atom find no tags of the form
99
// {#Section.Field} then the replacement subroutine can be skipped in next
100
// execution saving CPU cycles.
101
private boolean bHasReplacements;
102
103   // This is a soft reference to a String holding the base document template
104
// if virtual memory runs low the garbage collector can discard the soft
105
// reference that would be reloaded from disk later upon the next atom processing
106
private SoftReference JavaDoc oFileStr;
107
108   // A reference to the replacer class witch maps tags of the form {#Section.Field}
109
// to their corresponding database fields.
110
private FastStreamReplacer oReplacer;
111
112   // javax.mail objects
113
Session JavaDoc oMailSession;
114   Transport JavaDoc oMailTransport;
115
116   // Images repeated at HTML document are only attached once and referenced multiple times
117
// This hashmap keeps a record of the file names of images that have been already attached.
118
HashMap JavaDoc oDocumentImages;
119
120   // Because the HTML may be loaded once and then passed throught FastStreamReplacer
121
// and be send multiple times, a Soft Reference to a String holding the HTML is kept.
122
private SoftReference JavaDoc oHTMLStr;
123
124
125
126   // ---------------------------------------------------------------------------
127

128   public EmailSender() {
129     bHasReplacements = true;
130     oFileStr = null;
131     oHTMLStr = null;
132     oReplacer = new FastStreamReplacer();
133     oDocumentImages = new HashMap JavaDoc();
134     oMailSession = null;
135     oMailTransport = null;
136   }
137
138   // ---------------------------------------------------------------------------
139

140   public void free() {}
141
142   // ---------------------------------------------------------------------------
143

144   /**
145    * <p>Set Job Status</p>
146    * <p>If Status if set to Job.STATUS_FINISHED then dt_finished is set to current
147    * system date.</p>
148    * <p>If Status if set to any value other than Job.STATUS_RUNNING then the MailTransport is closed.
149    * @param oConn Database Connection
150    * @param iStatus Job Status
151    * @throws SQLException
152    */

153   public void setStatus(JDCConnection oConn, int iStatus) throws SQLException JavaDoc {
154
155     if (DebugFile.trace) {
156       DebugFile.writeln("Begin EmailSender.setStatus([Connection], " + String.valueOf(iStatus) + ")");
157       DebugFile.incIdent();
158     }
159
160     super.setStatus(oConn, iStatus);
161
162     if (Job.STATUS_RUNNING!=iStatus) {
163
164       if (oMailTransport!=null) {
165         try {
166           if (oMailTransport.isConnected())
167             oMailTransport.close();
168         }
169         catch (MessagingException JavaDoc msge) {
170           if ( DebugFile.trace)
171             DebugFile.writeln("Transport.close() MessagingException " + msge.getMessage());
172         }
173
174         oMailTransport = null;
175       } // fi (oMailTransport)
176

177       if (null!=oMailSession) oMailSession = null;
178
179     } // fi (STATUS_RUNNING)
180

181     if (DebugFile.trace) {
182       DebugFile.decIdent();
183       DebugFile.writeln("End EMailSender.setStatus()");
184     }
185   } // setStatus
186

187   // ---------------------------------------------------------------------------
188

189   private String JavaDoc attachFiles(String JavaDoc sHTMLPath) throws FileNotFoundException JavaDoc,IOException JavaDoc {
190     String JavaDoc sHtml = null;
191
192     if (DebugFile.trace) {
193       DebugFile.writeln("Begin EmailSender.attachFiles(" + sHTMLPath + ")");
194       DebugFile.incIdent();
195       DebugFile.writeln("new File(" + sHTMLPath + ")");
196     }
197
198     try {
199       FileSystem oFS = new FileSystem();
200       sHtml = oFS.readfilestr(sHTMLPath, null);
201       oFS = null;
202     }
203     catch (com.enterprisedt.net.ftp.FTPException ftpe) {}
204
205     PatternMatcher oMatcher = new Perl5Matcher();
206     PatternCompiler oCompiler = new Perl5Compiler();
207
208     Parser parser = Parser.createParser(sHtml, null);
209
210     StringBuffer JavaDoc oRetVal = new StringBuffer JavaDoc(sHtml.length());
211
212     try {
213       for (NodeIterator i = parser.elements(); i.hasMoreNodes(); ) {
214         Node node = i.nextNode();
215
216         if (node instanceof ImageTag) {
217           ImageTag oImgNode = (ImageTag) node;
218           String JavaDoc sSrc = oImgNode.extractImageLocn();
219           String JavaDoc sTag = oImgNode.getText();
220
221           Pattern oPattern;
222
223           try {
224             oPattern = oCompiler.compile(sSrc);
225           } catch (MalformedPatternException neverthrown) { oPattern=null; }
226
227           if (!oDocumentImages.containsKey(sSrc)) {
228             int iSlash = sSrc.lastIndexOf('/');
229             String JavaDoc sCid;
230
231             if (iSlash>=0) {
232               while (sSrc.charAt(iSlash)=='/') { if (++iSlash==sSrc.length()) break; }
233               sCid = sSrc.substring(iSlash);
234             }
235             else
236               sCid = sSrc;
237
238             oDocumentImages.put(sSrc, sCid);
239           }
240
241           oRetVal.append(Util.substitute(oMatcher, oPattern,
242                          new Perl5Substitution("cid:"+oDocumentImages.get(sSrc),
243                                                Perl5Substitution.INTERPOLATE_ALL),
244                          sTag, Util.SUBSTITUTE_ALL));
245
246         }
247         else {
248           oRetVal.append(node.getText());
249         }
250       }
251     }
252     catch (ParserException pe) {
253       if (DebugFile.trace) {
254         DebugFile.writeln("ParserException " + pe.getMessage());
255       }
256
257       oRetVal = new StringBuffer JavaDoc(sHtml.length());
258       oRetVal.append(sHtml);
259     }
260
261     if (DebugFile.trace) {
262       DebugFile.decIdent();
263       DebugFile.writeln("End EmailSender.attachFiles()");
264     }
265
266     return oRetVal.toString();
267   } // attachFiles
268

269   // ---------------------------------------------------------------------------
270

271   /**
272    * <p>Send PageSet document instance by e-mail.</p>
273    * <p>Transforming and sending aPageSet is a two stages task. First the PageSet
274    * stylesheet is combined via XSLT with user defined XML data and an XHTML
275    * document is pre-generated. This document still contains fixed database reference
276    * tags. At second stage the database reference tags are replaced for each document
277    * using FastStreamReplacer. Thus PageSet templates must have been previously
278    * transformed via XSLT before sending the PageSet instance by e-mail.</p>
279    * <p>This method uses javax.mail package for e-mail sending</p>
280    * <p>Parameters for locating e-mail server are stored at properties
281    * mail.transport.protocol, mail.host, mail.user from hipergate.cnf</p>
282    * <p>If parameter bo_attachimages is set to "1" then any &lt;IMG SRC=""&gt; tag
283    * will be replaced by a cid: reference to an attached file.</p>
284    * @param oAtm Atom containing reference to PageSet.<br>
285    * Atom must have the following parameters set:<br>
286    * <table border=1 cellpadding=4>
287    * <tr><td>gu_workarea</td><td>GUID of WorkArea owner of document to be sent</td></tr>
288    * <tr><td>gu_pageset</td><td>GUID of PageSet to be sent</td></tr>
289    * <tr><td>nm_pageset</td><td>Name of PageSet to be sent</td></tr>
290    * <tr><td>bo_attachimages</td><td>"1" if must attach images on document,<br>"0" if images must be absolute references</td></tr>
291    * <tr><td>tx_sender</td><td>Full Name of sender to be displayed</td></tr>
292    * <tr><td>tx_from</td><td>Sender e-mail address</td></tr>
293    * <tr><td>tx_subject</td><td>e-mail subject</td></tr>
294    * </table>
295    * @return String with document template after replacing database tags
296    * @throws FileNotFoundException
297    * @throws IOException
298    * @throws MessagingException
299    * @see com.knowgate.dataxslt.FastStreamReplacer
300    */

301   public Object JavaDoc process (Atom oAtm) throws FileNotFoundException JavaDoc,IOException JavaDoc,MessagingException JavaDoc {
302
303     File JavaDoc oFile; // Document Template File
304
FileReader JavaDoc oFileRead; // Document Template Reader
305
String JavaDoc sPathHTML; // Full Path to Document Template File
306
char cBuffer[]; // Internal Buffer for Document Template File Data
307
StringBufferInputStream JavaDoc oInStrm; // Document Template File Data after replacing images src http: with cid:
308
Object JavaDoc oReplaced; // Document Template File Data after FastStreamReplacer processing
309
final String JavaDoc Yes = "1";
310
311     final String JavaDoc sSep = System.getProperty("file.separator"); // Alias for file.separator
312

313     if (DebugFile.trace) {
314       DebugFile.writeln("Begin EMailSender.process([Job:" + getStringNull(DB.gu_job, "") + ", Atom:" + String.valueOf(oAtm.getInt(DB.pg_atom)) + "])");
315       DebugFile.incIdent();
316     }
317
318     if (bHasReplacements) { // Initially the document is assumed to have tags to replace
319

320       // *************************************************
321
// Compose the full path to document template file
322

323       // First get the storage base path from hipergate.cnf
324
sPathHTML = getProperty("workareasput");
325       if (!sPathHTML.endsWith(sSep)) sPathHTML += sSep;
326
327         // Concatenate PageSet workarea guid and subpath to Mailwire application directory
328
sPathHTML += getParameter("gu_workarea") + sSep + "apps" + sSep + "Mailwire" + sSep + "html" + sSep + getParameter("gu_pageset") + sSep;
329
330       // Concatenate PageSet Name
331
sPathHTML += getParameter("nm_pageset").replace(' ', '_') + ".html";
332
333       if (DebugFile.trace) DebugFile.writeln("PathHTML = " + sPathHTML);
334
335       // ***********************************************************************
336
// Change <IMG SRC=""> tags for embeding document images into mime message
337

338       if (Yes.equals(getParameter("bo_attachimages"))) {
339
340         if (DebugFile.trace) DebugFile.writeln("bo_attachimages=true");
341
342         // Check first the SoftReference to the tag-replaced in-memory String cache
343
oInStrm = null;
344
345         if (null!=oHTMLStr) {
346           if (null!=oHTMLStr.get())
347             // Get substituted html source as a StringBufferInputStream suitable
348
// for FastStreamReplacer replace() method.
349
oInStrm = new StringBufferInputStream JavaDoc((String JavaDoc) oHTMLStr.get());
350         }
351         if (null==oInStrm)
352           // If SoftReference was not found then
353
// call html processor for <IMG> tag substitution
354
oInStrm = new StringBufferInputStream JavaDoc(attachFiles(sPathHTML));
355
356         oHTMLStr = new SoftReference JavaDoc(oInStrm);
357
358         // Call FastStreamReplacer for {#Section.Field} tags
359
oReplaced = oReplacer.replace(oInStrm, oAtm.getItemMap());
360       }
361
362       else { // do not attach images with message body
363

364         if (DebugFile.trace) DebugFile.writeln("bo_attachimages=false");
365
366         // Call FastStreamReplacer for {#Section.Field} tags
367
oReplaced = oReplacer.replace(sPathHTML, oAtm.getItemMap());
368       }
369
370       // Count number of replacements done and update bHasReplacements flag accordingly
371
bHasReplacements = (oReplacer.lastReplacements() > 0);
372     }
373
374     else {
375
376       oReplaced = null;
377
378       if (null != oFileStr)
379         oReplaced = oFileStr.get();
380
381       if (null == oReplaced) {
382
383         // If document template has no database replacement tags
384
// then just cache the document template into a SoftReference String
385

386         // Compose the full path to document template file
387
sPathHTML = getProperty("workareasput");
388         if (!sPathHTML.endsWith(sSep)) sPathHTML += sSep;
389
390         sPathHTML += getParameter("gu_workarea") + sSep + "apps" + sSep + "Mailwire" + sSep + "html" + sSep + getParameter("gu_pageset") + sSep + getParameter("nm_pageset").replace(' ', '_') + ".html";
391
392         if (DebugFile.trace) DebugFile.writeln("PathHTML = " + sPathHTML);
393
394         // ***************************
395
// Read document template file
396

397         if (DebugFile.trace) DebugFile.writeln("new File(" + sPathHTML + ")");
398
399         oFile = new File JavaDoc(sPathHTML);
400
401         cBuffer = new char[new Long JavaDoc(oFile.length()).intValue()];
402
403         oFileRead = new FileReader JavaDoc(oFile);
404         oFileRead.read(cBuffer);
405         oFileRead.close();
406
407         if (DebugFile.trace) DebugFile.writeln(String.valueOf(cBuffer.length) + " characters readed");
408
409         if (Yes.equals(getParameter("bo_attachimages")))
410           oReplaced = attachFiles(new String JavaDoc(cBuffer));
411         else
412           oReplaced = new String JavaDoc(cBuffer);
413
414         // *********************************************************
415
// Assign SoftReference to File cached in-memory as a String
416

417         oFileStr = new SoftReference JavaDoc(oReplaced);
418
419       } // fi (oReplaced)
420

421     } // fi (bHasReplacements)
422

423     // ***********************************************
424
// Send replaced file data by e-mail
425

426     if (null==oMailSession) {
427       if (DebugFile.trace) DebugFile.writeln("Session.getInstance(Job.getProperties(), null)");
428
429       java.util.Properties JavaDoc oMailProps = getProperties();
430
431       if (oMailProps.getProperty("mail.transport.protocol")==null)
432         oMailProps.put("mail.transport.protocol","smtp");
433
434       if (oMailProps.getProperty("mail.host")==null)
435         oMailProps.put("mail.host","localhost");
436
437       oMailSession = Session.getInstance(getProperties(), null);
438
439       if (null!=oMailSession) {
440         oMailTransport = oMailSession.getTransport();
441
442         try {
443           oMailTransport.connect();
444         }
445         catch (NoSuchProviderException JavaDoc nspe) {
446           if (DebugFile.trace) DebugFile.writeln("MailTransport.connect() NoSuchProviderException " + nspe.getMessage());
447           throw new MessagingException JavaDoc(nspe.getMessage(), nspe);
448         }
449       } // fi (Session.getInstance())
450
} // fi (oMailSession)
451

452     MimeMessage JavaDoc oMsg;
453     InternetAddress JavaDoc oFrom, oTo;
454
455     try {
456       if (null==getParameter("tx_sender"))
457         oFrom = new InternetAddress JavaDoc(getParameter("tx_from"));
458       else
459         oFrom = new InternetAddress JavaDoc(getParameter("tx_from"), getParameter("tx_sender"));
460
461       if (DebugFile.trace) DebugFile.writeln("to: " + oAtm.getStringNull(DB.tx_email, "ERROR Atom[" + String.valueOf(oAtm.getInt(DB.pg_atom)) + "].tx_email is null!"));
462
463       oTo = new InternetAddress JavaDoc(oAtm.getString(DB.tx_email), oAtm.getStringNull(DB.tx_name,"") + " " + oAtm.getStringNull(DB.tx_surname,""));
464     }
465     catch (AddressException JavaDoc adre) {
466       if (DebugFile.trace) DebugFile.writeln("AddressException " + adre.getMessage() + " job " + getString(DB.gu_job) + " atom " + String.valueOf(oAtm.getInt(DB.pg_atom)));
467
468       oFrom = null;
469       oTo = null;
470
471       throw new MessagingException JavaDoc ("AddressException " + adre.getMessage() + " job " + getString(DB.gu_job) + " atom " + String.valueOf(oAtm.getInt(DB.pg_atom)));
472     }
473
474     if (DebugFile.trace) DebugFile.writeln("new MimeMessage([Session])");
475
476     oMsg = new MimeMessage JavaDoc(oMailSession);
477
478     oMsg.setSubject(getParameter("tx_subject"));
479
480     oMsg.setFrom(oFrom);
481
482     if (DebugFile.trace) DebugFile.writeln("MimeMessage.addRecipient(MimeMessage.RecipientType.TO, " + oTo.getAddress());
483
484     oMsg.addRecipient(MimeMessage.RecipientType.TO, oTo);
485
486     String JavaDoc sSrc = null, sCid = null;
487
488     try {
489
490       // Images may be attached into message or be absolute http source references
491
if (Yes.equals(getParameter("bo_attachimages"))) {
492
493         BodyPart JavaDoc oMsgBodyPart = new MimeBodyPart JavaDoc();
494         oMsgBodyPart.setContent(oReplaced, "text/html");
495
496         // Create a related multi-part to combine the parts
497
MimeMultipart JavaDoc oMultiPart = new MimeMultipart JavaDoc("related");
498         oMultiPart.addBodyPart(oMsgBodyPart);
499
500         Iterator JavaDoc oImgs = oDocumentImages.keySet().iterator();
501
502         while (oImgs.hasNext()) {
503           BodyPart JavaDoc oImgBodyPart = new MimeBodyPart JavaDoc();
504
505           sSrc = (String JavaDoc) oImgs.next();
506           sCid = (String JavaDoc) oDocumentImages.get(sSrc);
507
508           if (sSrc.startsWith("www."))
509             sSrc = "http://" + sSrc;
510
511           if (sSrc.startsWith("http://") || sSrc.startsWith("https://")) {
512             oImgBodyPart.setDataHandler(new DataHandler JavaDoc(new URL JavaDoc(sSrc)));
513           }
514           else {
515             oImgBodyPart.setDataHandler(new DataHandler JavaDoc(new FileDataSource JavaDoc(sSrc)));
516           }
517
518           oImgBodyPart.setHeader("Content-ID", sCid);
519
520           // Add part to multi-part
521
oMultiPart.addBodyPart(oImgBodyPart);
522         } // wend
523

524         if (DebugFile.trace) DebugFile.writeln("MimeMessage.setContent([MultiPart])");
525
526         oMsg.setContent(oMultiPart);
527       }
528
529       else {
530
531         if (DebugFile.trace) DebugFile.writeln("MimeMessage.setContent([String], \"text/html\")");
532
533         oMsg.setContent(oReplaced, "text/html");
534
535       }
536
537       oMsg.saveChanges();
538
539       if (DebugFile.trace) DebugFile.writeln("Transport.sendMessage([MimeMessage], MimeMessage.getAllRecipients())");
540
541       oMailTransport.sendMessage(oMsg, oMsg.getAllRecipients());
542
543       // ************************************************************
544
// Decrement de count of atoms peding of processing at this job
545
iPendingAtoms--;
546     }
547     catch (MalformedURLException JavaDoc urle) {
548
549       if (DebugFile.trace) DebugFile.writeln("MalformedURLException " + sSrc);
550       throw new MessagingException JavaDoc("MalformedURLException " + sSrc);
551     }
552
553     if (DebugFile.trace) {
554       DebugFile.writeln("End EMailSender.process([Job:" + getStringNull(DB.gu_job, "") + ", Atom:" + String.valueOf(oAtm.getInt(DB.pg_atom)) + "])");
555       DebugFile.decIdent();
556     }
557
558     return oReplaced;
559
560   } //process
561

562 } // EmailSender
563
Popular Tags