KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > roller > presentation > velocity > CommentServlet


1 package org.roller.presentation.velocity;
2
3 import java.io.IOException JavaDoc;
4 import java.net.MalformedURLException JavaDoc;
5 import java.util.Date JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.List JavaDoc;
8 import java.util.ResourceBundle JavaDoc;
9 import java.util.Set JavaDoc;
10 import java.util.TreeSet JavaDoc;
11
12 import javax.mail.MessagingException JavaDoc;
13 import javax.mail.Session JavaDoc;
14 import javax.naming.InitialContext JavaDoc;
15 import javax.servlet.ServletException JavaDoc;
16 import javax.servlet.http.HttpServletRequest JavaDoc;
17 import javax.servlet.http.HttpServletResponse JavaDoc;
18 import javax.servlet.http.HttpSession JavaDoc;
19 import javax.servlet.jsp.JspFactory JavaDoc;
20 import javax.servlet.jsp.PageContext JavaDoc;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.struts.util.RequestUtils;
25 import org.apache.velocity.Template;
26 import org.apache.velocity.context.Context;
27 import org.roller.RollerException;
28 import org.roller.config.RollerConfig;
29 import org.roller.config.RollerRuntimeConfig;
30 import org.roller.model.IndexManager;
31 import org.roller.model.Roller;
32 import org.roller.model.UserManager;
33 import org.roller.model.WeblogManager;
34 import org.roller.pojos.CommentData;
35 import org.roller.pojos.PageData;
36 import org.roller.pojos.UserData;
37 import org.roller.pojos.WeblogEntryData;
38 import org.roller.pojos.WebsiteData;
39 import org.roller.presentation.LanguageUtil;
40 import org.roller.presentation.RollerContext;
41 import org.roller.presentation.RollerRequest;
42 import org.roller.presentation.RollerSession;
43 import org.roller.presentation.pagecache.PageCacheFilter;
44 import org.roller.presentation.weblog.formbeans.CommentFormEx;
45 import org.roller.util.CommentSpamChecker;
46 import org.roller.util.MailUtil;
47 import org.roller.util.StringUtils;
48
49 /**
50  * Extend PageServlet to do special handling needed to support viewing and
51  * posting of comments. Handles in-page comments and popup-style comments.
52  * <p />
53  * This servlet overrides the VelocityServlet's handleRequest method so that
54  * the correct comments page template can be loaded for popup comments.
55  * If this servlet is called with the request paramteter 'popup'
56  * defined, then it will load the user's _popupcomments page and if no such
57  * page is found it will use /popupcomments.vm which looks just like the old
58  * pre-0.9.9 popup comments page.
59  * <p />
60  * This servlet also overrides doPost() to handle review and posting of new
61  * comments. If the request paramter 'method' is set to 'preview' then the
62  * posted comment will be previewed, otherwise if it will be posted.
63  * <p />
64  * Incoming comments are tested against the MT Blacklist. If they are found
65  * to be spam, then they are marked as spam and hidden from view.
66  * <p />
67  * If email notification is turned on, each new comment will result in an
68  * email sent to the blog owner and all who have commented on the same post.
69  *
70  * @web.servlet name="CommentServlet"
71  * @web.servlet-mapping url-pattern="/comments/*"
72  * @web.servlet-init-param name="org.apache.velocity.properties"
73  * value="/WEB-INF/velocity.properties"
74  *
75  * @author Dave Johnson
76  */

77 public class CommentServlet extends PageServlet
78 {
79     private static final String JavaDoc COMMENT_SPAM_MSG =
80               "Your comment has been recognized as "
81             + "<a HREF='http://www.jayallen.org/projects/mt-blacklist/'>"
82             + "Comment Spam</a> and rejected.";
83     private transient ResourceBundle JavaDoc bundle =
84         ResourceBundle.getBundle("ApplicationResources");
85     private static Log mLogger =
86         LogFactory.getFactory().getInstance(CommentServlet.class);
87     
88     //-----------------------------------------------------------------------
89
/**
90      * Override VelocityServlet so we can pick the right page and stick
91      * the right stuff into the VelocityContext before page execution.
92      */

93     public Template handleRequest( HttpServletRequest JavaDoc request,
94                                    HttpServletResponse JavaDoc response,
95                                    Context JavaDoc ctx ) throws Exception JavaDoc
96     {
97         Template template = null;
98         if (request.getParameter("popup") == null)
99         {
100             // Request does not specify popup, so normal return
101
template = super.handleRequest(request, response, ctx);
102         }
103         else
104         {
105             PageContext JavaDoc pageContext =
106                 JspFactory.getDefaultFactory().getPageContext(
107                     this, request, response,"", true, 8192, true);
108             RollerRequest rreq= RollerRequest.getRollerRequest(pageContext);
109             UserManager userMgr = rreq.getRoller().getUserManager();
110             WebsiteData website = rreq.getWebsite();
111                 
112             // Request specifies popup
113
PageData page = null;
114             Exception JavaDoc pageException = null;
115             try
116             {
117                 // Does user have a popupcomments page?
118
page = userMgr.getPageByName(website, "_popupcomments");
119             }
120             catch(Exception JavaDoc e )
121             {
122                pageException = e;
123                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
124             }
125             if (pageException != null)
126             {
127                 mLogger.error("EXCEPTION: in RollerServlet", pageException);
128                 request.setAttribute("DisplayException", pageException);
129             }
130             // User doesn't have one so return the default
131
if (page == null)
132             {
133                 page = new PageData("/popupcomments.vm", website, "Comments",
134                     "Comments", "dummy_link", "dummy_template", new Date JavaDoc());
135             }
136             rreq.setPage(page);
137             template = prepareForPageExecution(ctx, rreq, response, page);
138         }
139         return template;
140     }
141     
142     //-----------------------------------------------------------------------
143
/**
144      * Handle POST from comment form, then hand off to super for page rendering.
145      */

146     public void doPost(
147             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
148             throws IOException JavaDoc, ServletException JavaDoc
149     {
150         if (request.getParameter("method") != null
151             && request.getParameter("method").equals("preview"))
152         {
153             doPreviewPost(request, response);
154             return;
155         }
156
157         RollerRequest rreq = RollerRequest.getRollerRequest(request);
158         HttpSession JavaDoc session = request.getSession();
159         try
160         {
161             // Get weblog entry object, put in page context
162
WeblogEntryData wd = rreq.getWeblogEntry();
163             if (wd == null || wd.getId() == null)
164             {
165                 throw new RollerException(
166                     "Unable to find WeblogEntry for "
167                     + request.getParameter(RollerRequest.WEBLOGENTRYID_KEY));
168             }
169             if ( !wd.getWebsite().getAllowComments().booleanValue()
170                 || !wd.getCommentsStillAllowed())
171             {
172                 throw new RollerException("ERROR comments not allowed");
173             }
174             
175             request.setAttribute("blogEntry", wd);
176
177             // get the User to which the blog belongs
178
UserData user = wd.getWebsite().getUser();
179             
180             // TODO: A hack to be replaced by Object.canEdit()
181
request.setAttribute(RollerRequest.OWNING_USER, user);
182
183             // Save comment
184
WeblogManager mgr = rreq.getRoller().getWeblogManager();
185             CommentFormEx cf = new CommentFormEx();
186             CommentData cd = new CommentData();
187             RequestUtils.populate(cf, request);
188             cf.copyTo(cd, request.getLocale());
189             cd.setWeblogEntry(wd);
190             cd.setRemoteHost(request.getRemoteHost());
191             cd.setPostTime(new java.sql.Timestamp JavaDoc(System.currentTimeMillis()));
192             
193             if (!testCommentSpam(cd, request))
194             {
195                 if (RollerContext.getCommentAuthenticator().authenticate(cd, request))
196                 {
197                     cd.save();
198                     rreq.getRoller().commit();
199                     reindexEntry(rreq.getRoller(), wd);
200
201                     // Refresh user's entries in page cache
202
PageCacheFilter.removeFromCache(request, user);
203
204                     // Put array of comments in context
205
List JavaDoc comments = mgr.getComments(wd.getId());
206                     request.setAttribute("blogComments", comments);
207
208                     // MR: Added functionality to e-mail comments
209
sendEmailNotification(request, rreq, wd, cd, user,comments);
210                     
211                     super.doPost(request, response);
212                     return;
213                 }
214                 else
215                 {
216                     request.getSession().setAttribute(
217                         RollerSession.ERROR_MESSAGE,
218                         bundle.getString("error.commentAuthFailed"));
219                 }
220             }
221             doPreviewPost(request, response);
222         }
223         catch (Exception JavaDoc e)
224         {
225             mLogger.error("ERROR posting comment", e);
226             // Noted: this never gets back to the user. Not sure why it is being set.
227
session.setAttribute(RollerSession.ERROR_MESSAGE, e.getMessage());
228         }
229     }
230
231     //-----------------------------------------------------------------------
232
/**
233      * Load comment and blog entry objects and forward to either the popup
234      * or the in-page comment page for comment preview.
235      */

236     public void doPreviewPost(
237         HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
238         throws IOException JavaDoc, ServletException JavaDoc
239     {
240         RollerRequest rreq = RollerRequest.getRollerRequest(request);
241         try
242         {
243             WeblogEntryData wd = rreq.getWeblogEntry();
244             if (wd == null || wd.getId() == null)
245             {
246                 throw new RollerException(
247                    "Unable to find WeblogEntry for "
248                    + request.getParameter(RollerRequest.WEBLOGENTRYID_KEY));
249             }
250             request.setAttribute("blogEntry", wd);
251
252             // TODO: A hack to be replaced by Object.canEdit()
253
request.setAttribute(RollerRequest.OWNING_USER, wd.getWebsite().getUser());
254
255             CommentFormEx cf = new CommentFormEx();
256             RequestUtils.populate(cf, request);
257             cf.setWeblogEntry(wd);
258             cf.setPostTime(new java.sql.Timestamp JavaDoc(System.currentTimeMillis()));
259             request.setAttribute("commentForm", cf);
260             request.setAttribute("previewComments","dummy");
261         }
262         catch (Exception JavaDoc e)
263         {
264             // TODO: error message for browser and log
265
mLogger.error(e);
266         }
267         super.doPost(request, response);
268     }
269
270     /**
271      * Re-index the WeblogEntry so that the new comment gets indexed.
272      * @param entry
273      */

274     private void reindexEntry(Roller roller, WeblogEntryData entry) throws RollerException
275     {
276         IndexManager manager = roller.getIndexManager();
277
278         // remove entry before (re)adding it, or in case it isn't Published
279
manager.removeEntryIndexOperation(entry);
280
281         // if published, index the entry
282
if (entry.getPublishEntry() == Boolean.TRUE)
283         {
284             manager.addEntryIndexOperation(entry);
285         }
286     }
287
288     //-----------------------------------------------------------------------
289
/**
290      * Test CommentData to see if it is spam, if it is set it's spam property
291      * to true and put a RollerSession.ERROR_MESSAGE message in the session.
292      * @param cd CommentData to be tested.
293      */

294     private boolean testCommentSpam(CommentData cd, HttpServletRequest JavaDoc req)
295     {
296         boolean ret = false;
297         CommentSpamChecker checker = new CommentSpamChecker();
298         checker.testComment(cd);
299         if (cd.getSpam().booleanValue())
300         {
301            HttpSession JavaDoc session = req.getSession();
302            session.setAttribute(
303               RollerSession.ERROR_MESSAGE, COMMENT_SPAM_MSG);
304           ret = true;
305         }
306         return ret;
307     }
308
309     //-----------------------------------------------------------------------
310

311     // Email notification
312

313     // agangolli: Incorporated suggested changes from Ken Blackler, with server-wide configurable options
314
// TODO: Make the addressing options configurable on a per-website basis.
315

316     private static final String JavaDoc EMAIL_ADDR_REGEXP = "^.*@.*[.].{2,}$";
317
318     // Servlet init params that control how messages are addressed server-wide. These default to false for old behavior
319
// Controls whether the owner and commenters get separate messages (owner's message contains a link to the entry edit page).
320
private static final String JavaDoc SEPARATE_OWNER_MSG_PARAM = CommentServlet.class.getName() + ".separateOwnerMessage";
321     // Controls whether the commenters addresses are placed in a Bcc header or a visible address field
322
private static final String JavaDoc HIDE_COMMENTER_ADDRESSES_PARAM = CommentServlet.class.getName() + ".hideCommenterAddresses";
323
324
325     /**
326      * Send email notification of comment.
327      */

328     private void sendEmailNotification(
329         HttpServletRequest JavaDoc request,
330         RollerRequest rreq,
331         WeblogEntryData wd,
332         CommentData cd,
333         UserData user,
334         List JavaDoc comments) throws MalformedURLException JavaDoc
335     {
336         RollerContext rc = RollerContext.getRollerContext(request);
337         ResourceBundle JavaDoc resources = ResourceBundle.getBundle(
338             "ApplicationResources",LanguageUtil.getViewLocale(request));
339         UserManager userMgr = null;
340         WebsiteData site = null;
341         try
342         {
343             userMgr = RollerContext.getRoller(request).getUserManager();
344             site = userMgr.getWebsite(user.getUserName());
345         }
346         catch (RollerException re)
347         {
348             re.printStackTrace();
349             mLogger.error(
350               "Couldn't get UserManager from RollerContext", re.getRootCause());
351         }
352
353         // Send e-mail to owner and subscribed users (if enabled)
354
boolean notify = RollerRuntimeConfig.getBooleanProperty("users.comments.emailnotify");
355         if (notify && site.getEmailComments().booleanValue())
356         {
357             // Determine message and addressing options from init parameters
358
boolean separateMessages =
359                     RollerConfig.getBooleanProperty("comment.notification.separateOwnerMessage");
360             boolean hideCommenterAddrs =
361                     RollerConfig.getBooleanProperty("comment.notification.hideCommenterAddresses");
362
363             //------------------------------------------
364
// --- Determine the "from" address
365
// --- Use either the site configured from address or the user's address
366

367             String JavaDoc from =
368                (StringUtils.isEmpty(site.getEmailFromAddress()))
369                   ? user.getEmailAddress()
370                   : site.getEmailFromAddress();
371             
372             //------------------------------------------
373
// --- Build list of email addresses to send notification to
374

375             // Get all the subscribers to this comment thread
376
Set JavaDoc subscribers = new TreeSet JavaDoc();
377             for (Iterator JavaDoc it = comments.iterator(); it.hasNext();)
378             {
379                 CommentData comment = (CommentData) it.next();
380                 if (!StringUtils.isEmpty(comment.getEmail()))
381                 {
382                     // If user has commented twice,
383
// count the most recent notify setting
384
if (comment.getNotify().booleanValue())
385                     {
386                         // only add those with valid email
387
if (comment.getEmail().matches(EMAIL_ADDR_REGEXP))
388                         {
389                             subscribers.add(comment.getEmail());
390                         }
391                     }
392                     else
393                     {
394                         // remove user who doesn't want to be notified
395
subscribers.remove(comment.getEmail());
396                     }
397                 }
398             }
399
400             // Form array of commenter addrs
401
String JavaDoc[] commenterAddrs = (String JavaDoc[])subscribers.toArray(new String JavaDoc[0]);
402
403             //------------------------------------------
404
// --- Form the messages to be sent -
405
// For simplicity we always build separate owner and commenter messages even if sending a single one
406

407             // Determine with mime type to use for e-mail
408
StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
409             StringBuffer JavaDoc ownermsg = new StringBuffer JavaDoc();
410             boolean escapeHtml = RollerRuntimeConfig.getBooleanProperty("users.comments.escapehtml");
411                         
412             if (!escapeHtml)
413             {
414                 msg.append("<html><body style=\"background: white; ");
415                 msg.append(" color: black; font-size: 12px\">");
416             }
417
418             if (!StringUtils.isEmpty(cd.getName()))
419             {
420                 msg.append(cd.getName() + " "
421                            + resources.getString("email.comment.wrote")+": ");
422             }
423             else
424             {
425                 msg.append(resources.getString("email.comment.anonymous")+": ");
426             }
427
428             msg.append((escapeHtml) ? "\n\n" : "<br /><br />");
429             msg.append(cd.getContent());
430             msg.append((escapeHtml) ? "\n\n----\n"
431                     : "<br /><br /><hr /><span style=\"font-size: 11px\">");
432             msg.append(resources.getString("email.comment.respond") + ": ");
433             msg.append((escapeHtml) ? "\n" : "<br />");
434
435             String JavaDoc rootURL = rc.getAbsoluteContextUrl(request);
436             if (rootURL == null || rootURL.trim().length()==0)
437             {
438                 rootURL = RequestUtils.serverURL(request) + request.getContextPath();
439             }
440
441             // Build link back to comment
442

443             StringBuffer JavaDoc commentURL = new StringBuffer JavaDoc(rootURL);
444             commentURL.append("/comments/");
445             commentURL.append(rreq.getUser().getUserName());
446             
447             PageData page = rreq.getPage();
448             if (page == null)
449             {
450                 commentURL.append("?entry=");
451             }
452             else
453             {
454                 commentURL.append("/").append(page.getLink()).append("/");
455             }
456
457             commentURL.append(wd.getAnchor());
458     
459             if (escapeHtml)
460             {
461                 msg.append(commentURL.toString());
462             }
463             else
464             {
465              msg.append("<a HREF=\""+commentURL+"\">"+commentURL+"</a></span>");
466             }
467             
468             ownermsg.append(msg);
469
470              // add link to weblog edit page so user can login to manage comments
471
ownermsg.append((escapeHtml) ? "\n\n----\n" :
472                     "<br /><br /><hr /><span style=\"font-size: 11px\">");
473             ownermsg.append("Link to comment management page:");
474             ownermsg.append((escapeHtml) ? "\n" : "<br />");
475             
476             StringBuffer JavaDoc deleteURL = new StringBuffer JavaDoc(rootURL);
477             deleteURL.append("/editor/weblog.do?method=edit&entryid="+wd.getId());
478             
479             if (escapeHtml)
480             {
481                  ownermsg.append(deleteURL.toString());
482             }
483             else
484             {
485                  ownermsg.append(
486                   "<a HREF=\"" + deleteURL + "\">" + deleteURL + "</a></span>");
487                  msg.append("</Body></html>");
488                  ownermsg.append("</Body></html>");
489             }
490             
491             String JavaDoc subject = null;
492             if ((subscribers.size() > 1) ||
493                 (StringUtils.equals(cd.getEmail(), user.getEmailAddress())))
494             {
495                 subject= "RE: "+resources.getString("email.comment.title")+": ";
496             }
497             else
498             {
499                 subject = resources.getString("email.comment.title") + ": ";
500             }
501             subject += wd.getTitle();
502
503             //------------------------------------------
504
// --- Send message to email recipients
505
try
506             {
507                 javax.naming.Context JavaDoc ctx = (javax.naming.Context JavaDoc)
508                     new InitialContext JavaDoc().lookup("java:comp/env");
509                 Session JavaDoc session = (Session JavaDoc)ctx.lookup("mail/Session");
510                 boolean isHtml = !escapeHtml;
511                 if (separateMessages)
512                 {
513                     // Send separate messages to owner and commenters
514
sendMessage(session, from,
515                         new String JavaDoc[]{user.getEmailAddress()}, null, null, subject, ownermsg.toString(), isHtml);
516                     if (commenterAddrs.length > 0)
517                     {
518                         // If hiding commenter addrs, they go in Bcc: otherwise in the To: of the second message
519
String JavaDoc[] to = hideCommenterAddrs ? null : commenterAddrs;
520                         String JavaDoc[] bcc = hideCommenterAddrs ? commenterAddrs : null;
521                         sendMessage(session, from, to, null, bcc, subject, msg.toString(), isHtml);
522
523                     }
524                 }
525                 else
526                 {
527                     // Single message. User in To: header, commenters in either cc or bcc depending on hiding option
528
String JavaDoc[] cc = hideCommenterAddrs ? null : commenterAddrs;
529                     String JavaDoc[] bcc = hideCommenterAddrs ? commenterAddrs : null;
530                     sendMessage(session, from, new String JavaDoc[]{user.getEmailAddress()}, cc, bcc, subject,
531                         ownermsg.toString(), isHtml);
532                 }
533             }
534             catch (javax.naming.NamingException JavaDoc ne)
535             {
536                 mLogger.error("Unable to lookup mail session. Check configuration. NamingException: " + ne.getMessage());
537             }
538             catch (Exception JavaDoc e)
539             {
540                 mLogger.warn("Exception sending comment mail: " + e.getMessage());
541                 // This will log the stack trace if debug is enabled
542
if (mLogger.isDebugEnabled())
543                 {
544                     mLogger.debug(e);
545                 }
546             }
547
548         } // if email enabled
549
}
550
551     // This is somewhat ridiculous, but avoids duplicating a bunch of logic in the already messy sendEmailNotification
552
private void sendMessage(Session JavaDoc session, String JavaDoc from, String JavaDoc[] to, String JavaDoc[] cc, String JavaDoc[] bcc, String JavaDoc subject,
553                              String JavaDoc msg, boolean isHtml) throws MessagingException JavaDoc
554     {
555         if (isHtml)
556             MailUtil.sendHTMLMessage(session, from, to, cc, bcc, subject, msg);
557         else
558             MailUtil.sendTextMessage(session, from, to, cc, bcc, subject, msg);
559     }
560
561     /* old method not used anymore -- Allen G
562     private boolean getBooleanContextParam(String paramName, boolean defaultValue) {
563         String paramValue = getServletContext().getInitParameter(paramName);
564         if (paramValue == null) return defaultValue;
565         return Boolean.valueOf(paramValue).booleanValue();
566     }
567     */

568 }
569
570
Popular Tags