KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > blojsom > plugin > pingback > PingbackPlugin


1 /**
2  * Copyright (c) 2003-2006, David A. Czarnecki
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this list of conditions and the
9  * following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11  * following disclaimer in the documentation and/or other materials provided with the distribution.
12  * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
13  * endorse or promote products derived from this software without specific prior written permission.
14  * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
15  * without prior written permission of David A. Czarnecki.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21  * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */

31 package org.blojsom.plugin.pingback;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.commons.mail.Email;
36 import org.apache.commons.mail.EmailException;
37 import org.apache.commons.mail.HtmlEmail;
38 import org.apache.xmlrpc.AsyncCallback;
39 import org.apache.xmlrpc.XmlRpcClient;
40 import org.blojsom.blog.Blog;
41 import org.blojsom.blog.Entry;
42 import org.blojsom.blog.User;
43 import org.blojsom.event.Event;
44 import org.blojsom.event.EventBroadcaster;
45 import org.blojsom.event.Listener;
46 import org.blojsom.plugin.Plugin;
47 import org.blojsom.plugin.PluginException;
48 import org.blojsom.plugin.admin.event.EntryAddedEvent;
49 import org.blojsom.plugin.admin.event.EntryEvent;
50 import org.blojsom.plugin.admin.event.EntryUpdatedEvent;
51 import org.blojsom.plugin.email.EmailConstants;
52 import org.blojsom.plugin.pingback.event.PingbackAddedEvent;
53 import org.blojsom.plugin.velocity.StandaloneVelocityPlugin;
54 import org.blojsom.util.BlojsomConstants;
55 import org.blojsom.util.BlojsomUtils;
56 import org.blojsom.fetcher.FetcherException;
57 import org.blojsom.fetcher.Fetcher;
58
59 import javax.mail.Session JavaDoc;
60 import javax.naming.Context JavaDoc;
61 import javax.naming.InitialContext JavaDoc;
62 import javax.naming.NamingException JavaDoc;
63 import javax.servlet.http.HttpServletRequest JavaDoc;
64 import javax.servlet.http.HttpServletResponse JavaDoc;
65 import java.io.BufferedReader JavaDoc;
66 import java.io.IOException JavaDoc;
67 import java.io.InputStreamReader JavaDoc;
68 import java.net.HttpURLConnection JavaDoc;
69 import java.net.MalformedURLException JavaDoc;
70 import java.net.URL JavaDoc;
71 import java.util.Date JavaDoc;
72 import java.util.HashMap JavaDoc;
73 import java.util.Map JavaDoc;
74 import java.util.Vector JavaDoc;
75 import java.util.regex.Matcher JavaDoc;
76 import java.util.regex.Pattern JavaDoc;
77
78 /**
79  * Pingback plugin implements a pingback client to send pingbacks to any URLs in a blog entry according to the
80  * <a HREF="http://www.hixie.ch/specs/pingback/pingback">Pingback 1.0</a> specification.
81  *
82  * @author David Czarnecki
83  * @version $Id: PingbackPlugin.java,v 1.7 2006/06/23 18:45:51 czarneckid Exp $
84  * @since blojsom 3.0
85  */

86 public class PingbackPlugin extends StandaloneVelocityPlugin implements Plugin, Listener {
87
88     private static Log _logger = LogFactory.getLog(PingbackPlugin.class);
89
90     private static final String JavaDoc PINGBACK_PLUGIN_EMAIL_TEMPLATE_HTML = "org/blojsom/plugin/pingback/pingback-plugin-email-template-html.vm";
91     private static final String JavaDoc PINGBACK_PLUGIN_EMAIL_TEMPLATE_TEXT = "org/blojsom/plugin/pingback/pingback-plugin-email-template-text.vm";
92
93     private static final String JavaDoc DEFAULT_PINGBACK_PREFIX = "[blojsom] Pingback on: ";
94     public static final String JavaDoc PINGBACK_PREFIX_IP = "plugin-pingback-email-prefix";
95     private static final String JavaDoc BLOJSOM_PINGBACK_PLUGIN_BLOG_ENTRY = "BLOJSOM_PINGBACK_PLUGIN_BLOG_ENTRY";
96     private static final String JavaDoc BLOJSOM_PINGBACK_PLUGIN_PINGBACK = "BLOJSOM_PINGBACK_PLUGIN_PINGBACK";
97
98     private static final String JavaDoc PINGBACK_METHOD = "pingback.ping";
99     private static final String JavaDoc X_PINGBACK_HEADER = "X-Pingback";
100     private static final String JavaDoc PINGBACK_LINK_REGEX = "<link rel=\"pingback\" HREF=\"([^\"]+)\" ?/?>";
101     private static final String JavaDoc HREF_REGEX = "href\\s*=\\s*\"(.*?)\"";
102
103     /**
104      * IP address meta-data
105      */

106     public static final String JavaDoc BLOJSOM_PINGBACK_PLUGIN_METADATA_IP = "BLOJSOM_PINGBACK_PLUGIN_METADATA_IP";
107
108     // blog.properties property
109
public static final String JavaDoc PINGBACK_MODERATION_ENABLED = "pingback-moderation-enabled";
110
111     public static final String JavaDoc BLOJSOM_PINGBACK_PLUGIN_APPROVED = "BLOJSOM_PINGBACK_PLUGIN_APPROVED";
112     public static final String JavaDoc BLOJSOM_PLUGIN_PINGBACK_METADATA_DESTROY = "BLOJSOM_PLUGIN_PINGBACK_METADATA_DESTROY";
113     public static final String JavaDoc PINGBACK_PLUGIN_METADATA_SEND_PINGBACKS = "send-pingbacks";
114
115     private String JavaDoc _mailServer;
116     private String JavaDoc _mailServerUsername;
117     private String JavaDoc _mailServerPassword;
118     private Session JavaDoc _session;
119     private EventBroadcaster _eventBroadcaster;
120     private Fetcher _fetcher;
121
122     private PingbackPluginAsyncCallback _callbackHandler;
123
124     /**
125      * Create a new instance of the Pingback plugin
126      */

127     public PingbackPlugin() {
128     }
129
130     /**
131      * Set the {@link EventBroadcaster} event broadcaster
132      *
133      * @param eventBroadcaster {@link EventBroadcaster}
134      */

135     public void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
136         _eventBroadcaster = eventBroadcaster;
137     }
138
139     /**
140      * Set the {@link Fetcher}
141      *
142      * @param fetcher {@link Fetcher}
143      */

144     public void setFetcher(Fetcher fetcher) {
145         _fetcher = fetcher;
146     }
147
148     /**
149      * Initialize this plugin. This method only called when the plugin is instantiated.
150      *
151      * @throws PluginException If there is an error initializing the plugin
152      */

153     public void init() throws PluginException {
154         super.init();
155
156         _callbackHandler = new PingbackPluginAsyncCallback();
157
158         _mailServer = _servletConfig.getInitParameter(EmailConstants.SMTPSERVER_IP);
159
160         if (_mailServer != null) {
161             if (_mailServer.startsWith("java:comp/env")) {
162                 try {
163                     Context JavaDoc context = new InitialContext JavaDoc();
164                     _session = (Session JavaDoc) context.lookup(_mailServer);
165                 } catch (NamingException JavaDoc e) {
166                     _logger.error(e);
167                     throw new PluginException(e);
168                 }
169             } else {
170                 _mailServerUsername = _servletConfig.getInitParameter(EmailConstants.SMTPSERVER_USERNAME_IP);
171                 _mailServerPassword = _servletConfig.getInitParameter(EmailConstants.SMTPSERVER_PASSWORD_IP);
172             }
173         } else {
174             throw new PluginException("Missing SMTP servername servlet initialization parameter: " + EmailConstants.SMTPSERVER_IP);
175         }
176
177         _eventBroadcaster.addListener(this);
178
179         _logger.debug("Initialized pingback plugin");
180     }
181
182     /**
183      * Process the blog entries
184      *
185      * @param httpServletRequest Request
186      * @param httpServletResponse Response
187      * @param blog {@link Blog} instance
188      * @param context Context
189      * @param entries Blog entries retrieved for the particular request
190      * @return Modified set of blog entries
191      * @throws PluginException If there is an error processing the blog entries
192      */

193     public Entry[] process(HttpServletRequest JavaDoc httpServletRequest, HttpServletResponse JavaDoc httpServletResponse, Blog blog, Map JavaDoc context, Entry[] entries) throws PluginException {
194         return entries;
195     }
196
197     /**
198      * Perform any cleanup for the plugin. Called after {@link #process}.
199      *
200      * @throws org.blojsom.plugin.PluginException
201      * If there is an error performing cleanup for this plugin
202      */

203     public void cleanup() throws PluginException {
204     }
205
206     /**
207      * Called when BlojsomServlet is taken out of service
208      *
209      * @throws org.blojsom.plugin.PluginException
210      * If there is an error in finalizing this plugin
211      */

212     public void destroy() throws PluginException {
213     }
214
215     /**
216      * Setup the pingback e-mail
217      *
218      * @param blog {@link org.blojsom.blog.Blog} information
219      * @param email Email message
220      * @throws org.apache.commons.mail.EmailException
221      * If there is an error preparing the e-mail message
222      */

223     protected void setupEmail(Blog blog, Entry entry, Email email) throws EmailException {
224         email.setCharset(BlojsomConstants.UTF8);
225
226         // If we have a mail session for the environment, use that
227
if (_session != null) {
228             email.setMailSession(_session);
229         } else {
230             // Otherwise, if there is a username and password for the mail server, use that
231
if (!BlojsomUtils.checkNullOrBlank(_mailServerUsername) && !BlojsomUtils.checkNullOrBlank(_mailServerPassword)) {
232                 email.setHostName(_mailServer);
233                 email.setAuthentication(_mailServerUsername, _mailServerPassword);
234             } else {
235                 email.setHostName(_mailServer);
236             }
237         }
238
239         email.setFrom(blog.getBlogOwnerEmail(), "Blojsom Pingback");
240
241         String JavaDoc author = entry.getAuthor();
242         if (BlojsomUtils.checkNullOrBlank(author)) {
243             author = blog.getBlogOwner();
244         }
245
246         String JavaDoc authorEmail = blog.getBlogOwnerEmail();
247
248         if (author != null) {
249             try {
250                 User user = _fetcher.loadUser(blog, author);
251
252                 if (user == null) {
253                     authorEmail = blog.getBlogOwnerEmail();
254                 } else {
255                     authorEmail = user.getUserEmail();
256                     if (BlojsomUtils.checkNullOrBlank(authorEmail)) {
257                         authorEmail = blog.getBlogOwnerEmail();
258                     }
259                 }
260             } catch (FetcherException e) {
261             }
262         }
263
264         email.addTo(authorEmail, author);
265         email.setSentDate(new Date JavaDoc());
266     }
267
268     /**
269      * Handle an event broadcast from another component
270      *
271      * @param event {@link org.blojsom.event.Event} to be handled
272      */

273     public void handleEvent(Event event) {
274         if (event instanceof EntryAddedEvent || event instanceof EntryUpdatedEvent) {
275             EntryEvent entryEvent = (EntryEvent) event;
276
277             String JavaDoc text = entryEvent.getEntry().getDescription();
278             if (!BlojsomUtils.checkNullOrBlank(text) && BlojsomUtils.checkMapForKey(entryEvent.getEntry().getMetaData(), PINGBACK_PLUGIN_METADATA_SEND_PINGBACKS))
279             {
280                 String JavaDoc pingbackURL;
281                 StringBuffer JavaDoc sourceURI = new StringBuffer JavaDoc().append(entryEvent.getBlog().getBlogURL()).append(entryEvent.getEntry().getBlogCategory().getName()).append(entryEvent.getEntry().getPostSlug());
282                 String JavaDoc targetURI;
283
284                 Pattern JavaDoc hrefPattern = Pattern.compile(HREF_REGEX, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.UNICODE_CASE | Pattern.DOTALL);
285                 Matcher JavaDoc hrefMatcher = hrefPattern.matcher(text);
286                 if (_logger.isDebugEnabled()) {
287                     _logger.debug("Checking for href's in entry: " + entryEvent.getEntry().getId());
288                 }
289                 while (hrefMatcher.find()) {
290                     targetURI = hrefMatcher.group(1);
291                     if (_logger.isDebugEnabled()) {
292                         _logger.debug("Found potential targetURI: " + targetURI);
293                     }
294
295                     // Perform an HTTP request and first see if the X-Pingback header is available
296
try {
297                         HttpURLConnection JavaDoc urlConnection = (HttpURLConnection JavaDoc) new URL JavaDoc(targetURI).openConnection();
298                         urlConnection.setRequestMethod("GET");
299                         urlConnection.connect();
300                         pingbackURL = urlConnection.getHeaderField(X_PINGBACK_HEADER);
301
302                         // If the header is not available, look for the link in the URL content
303
if (pingbackURL == null) {
304                             BufferedReader JavaDoc bufferedReader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(urlConnection.getInputStream(), BlojsomConstants.UTF8));
305                             StringBuffer JavaDoc content = new StringBuffer JavaDoc();
306                             String JavaDoc input;
307                             while ((input = bufferedReader.readLine()) != null) {
308                                 content.append(input).append(BlojsomConstants.LINE_SEPARATOR);
309                             }
310                             bufferedReader.close();
311
312                             Pattern JavaDoc pingbackLinkPattern = Pattern.compile(PINGBACK_LINK_REGEX, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.UNICODE_CASE | Pattern.DOTALL);
313                             Matcher JavaDoc pingbackLinkMatcher = pingbackLinkPattern.matcher(content.toString());
314                             if (pingbackLinkMatcher.find()) {
315                                 pingbackURL = pingbackLinkMatcher.group(1);
316                             }
317                         }
318
319                         // Finally, send the pingback
320
if (pingbackURL != null && targetURI != null) {
321                             Vector JavaDoc parameters = new Vector JavaDoc();
322                             parameters.add(sourceURI.toString());
323                             parameters.add(targetURI);
324                             try {
325                                 if (_logger.isDebugEnabled()) {
326                                     _logger.debug("Sending pingback to: " + pingbackURL + " sourceURI: " + sourceURI + " targetURI: " + targetURI);
327                                 }
328                                
329                                 XmlRpcClient xmlRpcClient = new XmlRpcClient(pingbackURL);
330                                 xmlRpcClient.executeAsync(PINGBACK_METHOD, parameters, _callbackHandler);
331                             } catch (MalformedURLException JavaDoc e) {
332                                 if (_logger.isErrorEnabled()) {
333                                     _logger.error(e);
334                                 }
335                             }
336                         }
337                     } catch (IOException JavaDoc e) {
338                         if (_logger.isErrorEnabled()) {
339                             _logger.error(e);
340                         }
341                     }
342                 }
343             } else {
344                 if (_logger.isDebugEnabled()) {
345                     _logger.debug("No text in blog entry or " + PINGBACK_PLUGIN_METADATA_SEND_PINGBACKS + " not enabled.");
346                 }
347             }
348         } else if (event instanceof PingbackAddedEvent) {
349             HtmlEmail email = new HtmlEmail();
350             PingbackAddedEvent pingbackAddedEvent = (PingbackAddedEvent) event;
351
352             if (pingbackAddedEvent.getBlog().getBlogEmailEnabled().booleanValue()) {
353                 try {
354                     setupEmail(pingbackAddedEvent.getBlog(), pingbackAddedEvent.getEntry(), email);
355
356                     Map JavaDoc emailTemplateContext = new HashMap JavaDoc();
357                     emailTemplateContext.put(BlojsomConstants.BLOJSOM_BLOG, pingbackAddedEvent.getBlog());
358                     emailTemplateContext.put(BLOJSOM_PINGBACK_PLUGIN_PINGBACK, pingbackAddedEvent.getPingback());
359                     emailTemplateContext.put(BLOJSOM_PINGBACK_PLUGIN_BLOG_ENTRY, pingbackAddedEvent.getEntry());
360
361                     String JavaDoc htmlText = mergeTemplate(PINGBACK_PLUGIN_EMAIL_TEMPLATE_HTML, pingbackAddedEvent.getBlog(), emailTemplateContext);
362                     String JavaDoc plainText = mergeTemplate(PINGBACK_PLUGIN_EMAIL_TEMPLATE_TEXT, pingbackAddedEvent.getBlog(), emailTemplateContext);
363
364                     email.setHtmlMsg(htmlText);
365                     email.setTextMsg(plainText);
366
367                     String JavaDoc emailPrefix = (String JavaDoc) pingbackAddedEvent.getBlog().getProperties().get(PINGBACK_PREFIX_IP);
368                     if (BlojsomUtils.checkNullOrBlank(emailPrefix)) {
369                         emailPrefix = DEFAULT_PINGBACK_PREFIX;
370                     }
371
372                     email = (HtmlEmail) email.setSubject(emailPrefix + pingbackAddedEvent.getEntry().getTitle());
373
374                     email.send();
375                 } catch (EmailException e) {
376                     if (_logger.isErrorEnabled()) {
377                         _logger.error(e);
378                     }
379                 }
380             }
381         }
382     }
383
384     /**
385      * Process an event from another component
386      *
387      * @param event {@link Event} to be handled
388      */

389     public void processEvent(Event event) {
390     }
391
392     /**
393      * Asynchronous callback handler for the pingback ping
394      */

395     private class PingbackPluginAsyncCallback implements AsyncCallback {
396
397         /**
398          * Default constructor
399          */

400         public PingbackPluginAsyncCallback() {
401         }
402
403         /**
404          * Call went ok, handle result.
405          *
406          * @param o Return object
407          * @param url URL
408          * @param s String
409          */

410         public void handleResult(Object JavaDoc o, URL JavaDoc url, String JavaDoc s) {
411             if (_logger.isDebugEnabled()) {
412                 _logger.debug(o.toString());
413             }
414         }
415
416         /**
417          * Something went wrong, handle error.
418          *
419          * @param e Exception containing error from XML-RPC call
420          * @param url URL
421          * @param s String
422          */

423         public void handleError(Exception JavaDoc e, URL JavaDoc url, String JavaDoc s) {
424             if (_logger.isErrorEnabled()) {
425                 _logger.error(e);
426             }
427         }
428     }
429 }
Popular Tags