1 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 ; 47 import java.io.IOException ; 48 import java.io.InputStreamReader ; 49 import java.net.HttpURLConnection ; 50 import java.net.URL ; 51 import java.util.Date ; 52 import java.util.HashMap ; 53 import java.util.Map ; 54 import java.util.regex.Matcher ; 55 import java.util.regex.Pattern ; 56 57 65 public class PingbackHandler extends APIHandler { 66 67 private static final Log _logger = LogFactory.getLog(PingbackHandler.class); 68 69 private static final String TITLE_PATTERN = "<title>(.*)</title>"; 70 71 protected static final String 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 PINGBACK_SOURCE_URI_METADATA = "pingback-source-uri"; 83 protected static final String PINGBACK_TARGET_URI_METADATA = "pingback-target-uri"; 84 85 88 public PingbackHandler() { 89 } 90 91 96 public String getName() { 97 return API_NAME; 98 } 99 100 106 protected String getTitleFromSource(String source) { 107 String title = null; 108 Pattern titlePattern = Pattern.compile(TITLE_PATTERN, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNICODE_CASE); 109 Matcher titleMatcher = titlePattern.matcher(source); 110 if (titleMatcher.find()) { 111 title = titleMatcher.group(1); 112 } 113 114 return title; 115 } 116 117 125 protected String getExcerptFromSource(String source, String targetURI) { 126 String 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 158 public String ping(String sourceURI, String 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 StringBuffer sourcePage; 173 try { 174 URL source = new URL (sourceURI); 175 HttpURLConnection sourceConnection = (HttpURLConnection ) source.openConnection(); 176 sourceConnection.setRequestMethod("GET"); 177 sourceConnection.connect(); 178 BufferedReader sourceReader = new BufferedReader (new InputStreamReader (sourceConnection.getInputStream(), BlojsomConstants.UTF8)); 179 String line; 180 sourcePage = new StringBuffer (); 181 182 while ((line = sourceReader.readLine()) != null) { 183 sourcePage.append(line); 184 sourcePage.append(BlojsomConstants.LINE_SEPARATOR); 185 } 186 } catch (IOException 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 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 try { 205 URL target = new URL (targetURI); 206 HttpURLConnection httpURLConnection = (HttpURLConnection ) 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 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 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 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 try { 243 Entry entry = _fetcher.loadEntry(_blog, permalink); 244 245 if (_blog.getBlogPingbacksEnabled().booleanValue() && entry.allowsPingbacks().booleanValue()) { 246 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 pingbackMetaData = new HashMap (); 256 257 _eventBroadcaster.processEvent(new PingbackResponseSubmissionEvent(this, new Date (), _blog, _httpServletRequest, _httpServletResponse, getTitleFromSource(sourcePage.toString()), getTitleFromSource(sourcePage.toString()), sourceURI, getExcerptFromSource(sourcePage.toString(), targetURI), entry, pingbackMetaData)); 258 259 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 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 (), 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 return "Registered pingback from: " + sourceURI + " to: " + targetURI; 305 } 306 307 318 protected Integer addPingback(String title, String excerpt, String url, String blogName, Map 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 ()); 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 (0); 351 } 352 } | Popular Tags |