KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > blojsom > extension > xmlrpc > handler > PingbackHandler


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.extension.xmlrpc.handler;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.xmlrpc.XmlRpcException;
36 import org.blojsom.blog.Entry;
37 import org.blojsom.blog.Pingback;
38 import org.blojsom.fetcher.FetcherException;
39 import org.blojsom.plugin.common.ResponseConstants;
40 import org.blojsom.plugin.pingback.PingbackPlugin;
41 import org.blojsom.plugin.pingback.event.PingbackAddedEvent;
42 import org.blojsom.plugin.pingback.event.PingbackResponseSubmissionEvent;
43 import org.blojsom.util.BlojsomConstants;
44 import org.blojsom.util.BlojsomUtils;
45
46 import java.io.BufferedReader JavaDoc;
47 import java.io.IOException JavaDoc;
48 import java.io.InputStreamReader JavaDoc;
49 import java.net.HttpURLConnection JavaDoc;
50 import java.net.URL JavaDoc;
51 import java.util.Date JavaDoc;
52 import java.util.HashMap JavaDoc;
53 import java.util.Map JavaDoc;
54 import java.util.regex.Matcher JavaDoc;
55 import java.util.regex.Pattern JavaDoc;
56
57 /**
58  * Pingback handler provides support for the <a HREF="http://www.hixie.ch/specs/pingback/pingback">Pingback 1.0</a>
59  * specification.
60  *
61  * @author David Czarnecki
62  * @version $Id: PingbackHandler.java,v 1.7 2006/09/26 02:55:20 czarneckid Exp $
63  * @since blojsom 3.0
64  */

65 public class PingbackHandler extends APIHandler {
66
67     private static final Log _logger = LogFactory.getLog(PingbackHandler.class);
68
69     private static final String JavaDoc TITLE_PATTERN = "<title>(.*)</title>";
70
71     protected static final String JavaDoc API_NAME = "pingback";
72
73     protected static final int PINGBACK_GENERIC_FAULT_CODE = 0;
74     protected static final int PINGBACK_SOURCE_URI_NON_EXISTENT_CODE = 16;
75     protected static final int PINGBACK_NO_LINK_TO_TARGET_URI_CODE = 17;
76     protected static final int PINGBACK_TARGET_URI_NON_EXISTENT_CODE = 32;
77     protected static final int PINGBACK_TARGET_URI_NOT_ENABLED_CODE = 33;
78     protected static final int PINGBACK_ALREADY_REGISTERED_CODE = 48;
79     protected static final int PINGBACK_ACCESS_DENIED_CODE = 49;
80     protected static final int PINGBACK_UPSTREAM_SERVER_ERROR_CODE = 50;
81
82     protected static final String JavaDoc PINGBACK_SOURCE_URI_METADATA = "pingback-source-uri";
83     protected static final String JavaDoc PINGBACK_TARGET_URI_METADATA = "pingback-target-uri";
84
85     /**
86      * Construct a new Pingback handler
87      */

88     public PingbackHandler() {
89     }
90
91     /**
92      * Gets the name of API Handler. Used to bind to XML-RPC
93      *
94      * @return The API Name (ie: pingback)
95      */

96     public String JavaDoc getName() {
97         return API_NAME;
98     }
99
100     /**
101      * Try to find the &lt;title&gt;&lt/title&gt; tags from the source text
102      *
103      * @param source Source URI text
104      * @return Title of text or <code>null</code> if title tags are not found
105      */

106     protected String JavaDoc getTitleFromSource(String JavaDoc source) {
107         String JavaDoc title = null;
108         Pattern JavaDoc titlePattern = Pattern.compile(TITLE_PATTERN, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNICODE_CASE);
109         Matcher JavaDoc titleMatcher = titlePattern.matcher(source);
110         if (titleMatcher.find()) {
111             title = titleMatcher.group(1);
112         }
113
114         return title;
115     }
116
117     /**
118      * Try to extract an excerpt from the source text. Currently looks ahead 200 and ahead 200 characters from
119      * the location of the targetURI within the source.
120      *
121      * @param source Source URI text
122      * @param targetURI Target URI from which to start the excerpt
123      * @return Excerpt of text or <code>null</code> if we cannot find the targetURI
124      */

125     protected String JavaDoc getExcerptFromSource(String JavaDoc source, String JavaDoc targetURI) {
126         String JavaDoc excerpt = null;
127
128         int startOfTarget = source.indexOf(targetURI);
129         if (startOfTarget != -1) {
130             int startOfExcerpt = startOfTarget - 200;
131             if (startOfExcerpt < 0) {
132                 startOfExcerpt = 0;
133             }
134
135             int endOfExcerpt = startOfTarget + 200;
136             if (endOfExcerpt > source.length()) {
137                 endOfExcerpt = source.length();
138             }
139
140             excerpt = source.substring(startOfExcerpt, endOfExcerpt);
141             excerpt = BlojsomUtils.stripHTML(excerpt);
142             int firstSpace = excerpt.indexOf(' ') + 1;
143             int lastSpace = excerpt.lastIndexOf(' ');
144             if (-1 == lastSpace || lastSpace < firstSpace) lastSpace = excerpt.length();
145             excerpt = excerpt.substring(firstSpace, lastSpace);
146         }
147
148         return excerpt;
149     }
150
151     /**
152      * Notifies the server that a link has been added to sourceURI, pointing to targetURI.
153      *
154      * @param sourceURI The absolute URI of the post on the source page containing the link to the target site.
155      * @param targetURI The absolute URI of the target of the link, as given on the source page.
156      * @return
157      */

158     public String JavaDoc ping(String JavaDoc sourceURI, String JavaDoc targetURI) throws XmlRpcException {
159         if (_logger.isDebugEnabled()) {
160             _logger.debug("Pingback from: " + sourceURI + " to: " + targetURI);
161         }
162
163         if (BlojsomUtils.checkNullOrBlank(sourceURI)) {
164             if (_logger.isErrorEnabled()) {
165                 _logger.error("Pingback must include a source URI");
166             }
167
168             throw new XmlRpcException(PINGBACK_SOURCE_URI_NON_EXISTENT_CODE, "Pingback must include a source URI");
169         }
170
171         // Fetch sourceURI to make sure there is a link to the targetURI
172
StringBuffer JavaDoc sourcePage;
173         try {
174             URL JavaDoc source = new URL JavaDoc(sourceURI);
175             HttpURLConnection JavaDoc sourceConnection = (HttpURLConnection JavaDoc) source.openConnection();
176             sourceConnection.setRequestMethod("GET");
177             sourceConnection.connect();
178             BufferedReader JavaDoc sourceReader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(sourceConnection.getInputStream(), BlojsomConstants.UTF8));
179             String JavaDoc line;
180             sourcePage = new StringBuffer JavaDoc();
181
182             while ((line = sourceReader.readLine()) != null) {
183                 sourcePage.append(line);
184                 sourcePage.append(BlojsomConstants.LINE_SEPARATOR);
185             }
186         } catch (IOException JavaDoc e) {
187             if (_logger.isErrorEnabled()) {
188                 _logger.error(e);
189             }
190
191             throw new XmlRpcException(PINGBACK_GENERIC_FAULT_CODE, "Unable to retrieve source URI");
192         }
193
194         // Check that the sourceURI contains a link to the targetURI
195
if (sourcePage.indexOf(targetURI) == -1) {
196             if (_logger.isErrorEnabled()) {
197                 _logger.error("Target URI not found in Source URI");
198             }
199
200             throw new XmlRpcException(PINGBACK_NO_LINK_TO_TARGET_URI_CODE, "Target URI not found in source URI");
201         }
202
203         // Check targetURI exists and is a valid entry
204
try {
205             URL JavaDoc target = new URL JavaDoc(targetURI);
206             HttpURLConnection JavaDoc httpURLConnection = (HttpURLConnection JavaDoc) target.openConnection();
207             httpURLConnection.setRequestMethod("HEAD");
208             httpURLConnection.connect();
209
210             if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
211                 if (_logger.isErrorEnabled()) {
212                     _logger.error("Target URI does not exist");
213                 }
214
215                 throw new XmlRpcException(PINGBACK_TARGET_URI_NON_EXISTENT_CODE, "Target URI does not exist");
216             }
217         } catch (IOException JavaDoc e) {
218             if (_logger.isErrorEnabled()) {
219                 _logger.error(e);
220             }
221
222             throw new XmlRpcException(PINGBACK_GENERIC_FAULT_CODE, "Unable to retrieve target URI");
223         }
224
225         String JavaDoc permalink = BlojsomUtils.getRequestValue(BlojsomConstants.PERMALINK_PARAM, _httpServletRequest);
226         if (BlojsomUtils.checkNullOrBlank(permalink)) {
227             _logger.error("Permalink is null or blank: " + permalink);
228             throw new XmlRpcException(PINGBACK_GENERIC_FAULT_CODE, "Unable to retrieve target URI");
229         }
230
231         // Check that the resource hasn't already been registered
232
try {
233             Pingback pingback = _fetcher.loadPingback(_blog, sourceURI, targetURI);
234             
235             if (pingback != null) {
236                 throw new XmlRpcException(PINGBACK_ALREADY_REGISTERED_CODE, "Pingback already registered");
237             }
238         } catch (FetcherException e) {
239         }
240
241         // Check the resource is pingback-enabled
242
try {
243             Entry entry = _fetcher.loadEntry(_blog, permalink);
244
245             if (_blog.getBlogPingbacksEnabled().booleanValue() && entry.allowsPingbacks().booleanValue()) {
246                 // Record pingback
247
Pingback pingback = _fetcher.newPingback();
248                 pingback.setBlogEntryId(entry.getId());
249                 pingback.setBlogId(_blog.getId());
250                 pingback.setEntry(entry);
251                 pingback.setIp(_httpServletRequest.getRemoteAddr());
252                 pingback.setSourceURI(sourceURI);
253                 pingback.setTargetURI(targetURI);
254
255                 Map JavaDoc pingbackMetaData = new HashMap JavaDoc();
256
257                 _eventBroadcaster.processEvent(new PingbackResponseSubmissionEvent(this, new Date JavaDoc(), _blog, _httpServletRequest, _httpServletResponse, getTitleFromSource(sourcePage.toString()), getTitleFromSource(sourcePage.toString()), sourceURI, getExcerptFromSource(sourcePage.toString(), targetURI), entry, pingbackMetaData));
258
259                 // Check to see if the trackback should be destroyed (not saved) automatically
260
if (!pingbackMetaData.containsKey(PingbackPlugin.BLOJSOM_PLUGIN_PINGBACK_METADATA_DESTROY)) {
261
262                     pingback.setMetaData(pingbackMetaData);
263                     if (pingbackMetaData.containsKey(PingbackPlugin.BLOJSOM_PINGBACK_PLUGIN_APPROVED)
264                             && "true".equals(pingbackMetaData.get(PingbackPlugin.BLOJSOM_PINGBACK_PLUGIN_APPROVED))) {
265                         pingback.setStatus(ResponseConstants.APPROVED_STATUS);
266                     } else {
267                         if ("true".equals(_blog.getProperty(PingbackPlugin.PINGBACK_MODERATION_ENABLED))) {
268                             pingback.setStatus(ResponseConstants.NEW_STATUS);
269                         } else {
270                             pingback.setStatus(ResponseConstants.APPROVED_STATUS);
271                         }
272                     }
273
274                     Integer JavaDoc status = addPingback(entry.getTitle(), getExcerptFromSource(sourcePage.toString(), targetURI), sourceURI, getTitleFromSource(sourcePage.toString()), pingbackMetaData, pingback);
275
276                     if (status.intValue() != 0) {
277                         throw new XmlRpcException(status.intValue(), "Unknown exception occurred");
278                     } else {
279                         _eventBroadcaster.broadcastEvent(new PingbackAddedEvent(this, new Date JavaDoc(), pingback, _blog));
280                     }
281                 } else {
282                     if (_logger.isInfoEnabled()) {
283                         _logger.info("Pingback meta-data contained destroy key. Pingback was not saved");
284                     }
285
286                     throw new XmlRpcException(PINGBACK_ACCESS_DENIED_CODE, "Pingback meta-data contained destroy key. Pingback was not saved.");
287                 }
288             } else {
289                 if (_logger.isDebugEnabled()) {
290                     _logger.debug("Target URI does not support pingbacks");
291                 }
292
293                 throw new XmlRpcException(PINGBACK_TARGET_URI_NOT_ENABLED_CODE, "Target URI does not support pingbacks");
294             }
295         } catch (FetcherException e) {
296             if (_logger.isErrorEnabled()) {
297                 _logger.error(e);
298             }
299
300             throw new XmlRpcException(PINGBACK_TARGET_URI_NON_EXISTENT_CODE, "Target URI does not exist");
301         }
302
303         // Update notification
304
return "Registered pingback from: " + sourceURI + " to: " + targetURI;
305     }
306
307     /**
308      * Add a pingback for a given blog ID
309      *
310      * @param title Pingback title
311      * @param excerpt Pingback excerpt
312      * @param url Pingback URL
313      * @param blogName Pingback blog name
314      * @param pingbackMetaData Pingback meta-data
315      * @param pingback {@link Pingback}
316      * @return <code>0</code> if the pingback was registered, otherwise a fault code is returned
317      */

318     protected Integer JavaDoc addPingback(String JavaDoc title, String JavaDoc excerpt, String JavaDoc url, String JavaDoc blogName, Map JavaDoc pingbackMetaData, Pingback pingback) throws XmlRpcException {
319         title = BlojsomUtils.escapeStringSimple(title);
320         title = BlojsomUtils.stripLineTerminators(title, " ");
321         pingback.setTitle(title);
322
323         excerpt = BlojsomUtils.escapeStringSimple(excerpt);
324         excerpt = BlojsomUtils.stripLineTerminators(excerpt, " ");
325         pingback.setExcerpt(excerpt);
326
327         url = BlojsomUtils.escapeStringSimple(url);
328         url = BlojsomUtils.stripLineTerminators(url, " ");
329         pingback.setUrl(url);
330
331         blogName = BlojsomUtils.escapeStringSimple(blogName);
332         blogName = BlojsomUtils.stripLineTerminators(blogName, " ");
333         pingback.setBlogName(blogName);
334
335         pingback.setTrackbackDate(new Date JavaDoc());
336         pingback.setMetaData(pingbackMetaData);
337
338         try {
339             _fetcher.savePingback(_blog, pingback);
340         } catch (FetcherException e) {
341             if (_logger.isErrorEnabled()) {
342                 _logger.error(e);
343             }
344             
345             if (e.getCause() instanceof XmlRpcException) {
346                 throw (XmlRpcException) e.getCause();
347             }
348         }
349
350         return new Integer JavaDoc(0);
351     }
352 }
Popular Tags