PingbackHandler.java [plain text]
package org.blojsom.extension.xmlrpc.handlers;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlrpc.XmlRpcException;
import org.blojsom.BlojsomException;
import org.blojsom.blog.*;
import org.blojsom.fetcher.BlojsomFetcherException;
import org.blojsom.util.BlojsomUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class PingbackHandler extends AbstractBlojsomAPIHandler {
private static final Log _logger = LogFactory.getLog(PingbackHandler.class);
private static final String TITLE_PATTERN = "<title>(.*)</title>";
protected static final String API_NAME = "pingback";
protected static final int PINGBACK_GENERIC_FAULT_CODE = 0;
protected static final int PINGBACK_SOURCE_URI_NON_EXISTENT_CODE = 16;
protected static final int PINGBACK_NO_LINK_TO_TARGET_URI_CODE = 17;
protected static final int PINGBACK_TARGET_URI_NON_EXISTENT_CODE = 32;
protected static final int PINGBACK_TARGET_URI_NOT_ENABLED_CODE = 33;
protected static final int PINGBACK_ALREADY_REGISTERED_CODE = 48;
protected static final int PINGBACK_ACCESS_DENIED_CODE = 49;
protected static final int PINGBACK_UPSTREAM_SERVER_ERROR_CODE = 50;
protected static final String PINGBACK_METADATA_IP_ADDRESS = "PINGBACK_IP_ADDRESS";
public PingbackHandler() {
}
public void setBlogUser(BlogUser blogUser) throws BlojsomException {
_blogUser = blogUser;
_blog = _blogUser.getBlog();
_blogEntryExtension = _blog.getBlogProperty(BLOG_XMLRPC_ENTRY_EXTENSION_IP);
if (BlojsomUtils.checkNullOrBlank(_blogEntryExtension)) {
_blogEntryExtension = DEFAULT_BLOG_XMLRPC_ENTRY_EXTENSION;
}
}
public String getName() {
return API_NAME;
}
protected String getTitleFromSource(String source) {
String title = null;
Pattern titlePattern = Pattern.compile(TITLE_PATTERN, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNICODE_CASE);
Matcher titleMatcher = titlePattern.matcher(source);
if (titleMatcher.find()) {
title = titleMatcher.group(1);
}
return title;
}
protected String getExcerptFromSource(String source, String targetURI) {
String excerpt = null;
int startOfTarget = source.indexOf(targetURI);
if (startOfTarget != -1) {
int startOfExcerpt = startOfTarget - 200;
if (startOfExcerpt < 0) {
startOfExcerpt = 0;
}
int endOfExcerpt = startOfTarget + 200;
if (endOfExcerpt > source.length()) {
endOfExcerpt = source.length();
}
excerpt = source.substring(startOfExcerpt, endOfExcerpt);
excerpt = BlojsomUtils.stripHTML(excerpt);
}
return excerpt;
}
public String ping(String sourceURI, String targetURI) throws XmlRpcException {
_logger.debug("Pingback from: " + sourceURI + " to: " + targetURI);
if (BlojsomUtils.checkNullOrBlank(sourceURI)) {
_logger.error("Pingback must include a source URI");
throw new XmlRpcException(PINGBACK_SOURCE_URI_NON_EXISTENT_CODE, "Pingback must include a source URI");
}
StringBuffer sourcePage = new StringBuffer();
try {
URL source = new URL(sourceURI);
HttpURLConnection sourceConnection = (HttpURLConnection) source.openConnection();
sourceConnection.setRequestMethod("GET");
sourceConnection.connect();
BufferedReader sourceReader = new BufferedReader(new InputStreamReader(sourceConnection.getInputStream(), UTF8));
String line;
sourcePage = new StringBuffer();
while ((line = sourceReader.readLine()) != null) {
sourcePage.append(line);
sourcePage.append(LINE_SEPARATOR);
}
} catch (IOException e) {
_logger.error(e);
throw new XmlRpcException(PINGBACK_GENERIC_FAULT_CODE, "Unable to retrieve source URI");
}
if (sourcePage.indexOf(targetURI) == -1) {
_logger.error("Target URI not found in Source URI");
throw new XmlRpcException(PINGBACK_NO_LINK_TO_TARGET_URI_CODE, "Target URI not found in source URI");
}
try {
URL target = new URL(targetURI);
HttpURLConnection httpURLConnection = (HttpURLConnection) target.openConnection();
httpURLConnection.setRequestMethod("HEAD");
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
_logger.error("Target URI does not exist");
throw new XmlRpcException(PINGBACK_TARGET_URI_NON_EXISTENT_CODE, "Target URI does not exist");
}
} catch (IOException e) {
_logger.error(e);
throw new XmlRpcException(PINGBACK_GENERIC_FAULT_CODE, "Unable to retrieve target URI");
}
String pingbackID = BlojsomUtils.digestString(sourceURI + ":" + targetURI);
BlogCategory blogCategory = getBlogCategory(_blogUser, _httpServletRequest);
String permalink = BlojsomUtils.getRequestValue(PERMALINK_PARAM, _httpServletRequest);
try {
BlogEntry blogEntry = BlojsomUtils.fetchEntry(_fetcher, _blogUser, blogCategory.getCategory(), permalink);
if (_blog.getBlogPingbacksEnabled().booleanValue() && blogEntry.supportsPingbacks()) {
Map pingbackMetaData = new HashMap();
pingbackMetaData.put(PINGBACK_METADATA_IP_ADDRESS, _httpServletRequest.getRemoteAddr());
Pingback pingback = new Pingback();
Integer status = addPingback(new HashMap(), blogCategory.getCategory(), permalink, blogEntry.getTitle(), getExcerptFromSource(sourcePage.toString(), targetURI),
sourceURI, getTitleFromSource(sourcePage.toString()), _blog.getBlogFileExtensions(), _blog.getBlogHome(),
_blog.getBlogPingbacksDirectory(), UTF8, pingbackMetaData, pingback, pingbackID);
if (status.intValue() != 0) {
throw new XmlRpcException(status.intValue(), "Unknown exception occurred");
}
} else {
_logger.debug("Target URI does not support pingbacks");
throw new XmlRpcException(PINGBACK_TARGET_URI_NOT_ENABLED_CODE, "Target URI does not support pingbacks");
}
} catch (BlojsomFetcherException e) {
_logger.error(e);
throw new XmlRpcException(PINGBACK_TARGET_URI_NON_EXISTENT_CODE, "Target URI does not exist");
}
return "Registered pingback from: " + sourceURI + " to: " + targetURI;
}
protected Integer addPingback(Map context, String category, String permalink, String title,
String excerpt, String url, String blogName,
String[] blogFileExtensions, String blogHome,
String blogPingbackDirectory, String blogFileEncoding, Map pingbackMetaData,
Pingback pingback, String id) throws XmlRpcException {
excerpt = BlojsomUtils.escapeMetaAndLink(excerpt);
pingback.setTitle(title);
pingback.setExcerpt(excerpt);
pingback.setUrl(url);
pingback.setBlogName(blogName);
pingback.setTrackbackDateLong(new Date().getTime());
pingback.setMetaData(pingbackMetaData);
pingback.setId(id);
StringBuffer pingbackDirectory = new StringBuffer();
String permalinkFilename = BlojsomUtils.getFilenameForPermalink(permalink, blogFileExtensions);
permalinkFilename = BlojsomUtils.urlDecode(permalinkFilename);
if (permalinkFilename == null) {
_logger.debug("Invalid permalink pingback for: " + permalink);
throw new XmlRpcException(PINGBACK_TARGET_URI_NON_EXISTENT_CODE, "Target URI does not exist");
}
pingbackDirectory.append(blogHome);
pingbackDirectory.append(BlojsomUtils.removeInitialSlash(category));
File blogEntry = new File(pingbackDirectory.toString() + File.separator + permalinkFilename);
_logger.debug("Directory: " + blogEntry.toString());
if (!blogEntry.exists()) {
_logger.error("Trying to create pingback for invalid blog entry: " + permalink);
throw new XmlRpcException(PINGBACK_TARGET_URI_NON_EXISTENT_CODE, "Target URI does not exist");
}
pingbackDirectory.append(blogPingbackDirectory);
pingbackDirectory.append(File.separator);
pingbackDirectory.append(permalinkFilename);
pingbackDirectory.append(File.separator);
String pingbackFilename = pingbackDirectory.toString() + id + PINGBACK_EXTENSION;
File pingbackDir = new File(pingbackDirectory.toString());
if (!pingbackDir.exists()) {
if (!pingbackDir.mkdirs()) {
_logger.error("Could not create directory for pingbacks: " + pingbackDirectory);
throw new XmlRpcException(PINGBACK_ACCESS_DENIED_CODE, "Access denied");
}
}
File pingbackEntry = new File(pingbackFilename);
if (pingbackEntry.exists()) {
_logger.debug("Pingback already registered");
throw new XmlRpcException(PINGBACK_ALREADY_REGISTERED_CODE, "Pingback already registered");
}
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(pingbackEntry), blogFileEncoding));
bw.write(BlojsomUtils.nullToBlank(pingback.getTitle()).trim());
bw.newLine();
bw.write(BlojsomUtils.nullToBlank(pingback.getUrl()).trim());
bw.newLine();
bw.write(BlojsomUtils.nullToBlank(pingback.getBlogName()).trim());
bw.newLine();
bw.write(BlojsomUtils.nullToBlank(pingback.getExcerpt()).trim());
bw.newLine();
bw.close();
_logger.debug("Added pingback: " + pingbackFilename);
Properties pingbackMetaDataProperties = BlojsomUtils.mapToProperties(pingbackMetaData, UTF8);
String pingbackMetaDataFilename = BlojsomUtils.getFilename(pingbackEntry.toString()) + DEFAULT_METADATA_EXTENSION;
FileOutputStream fos = new FileOutputStream(new File(pingbackMetaDataFilename));
pingbackMetaDataProperties.store(fos, null);
fos.close();
_logger.debug("Wrote pingback meta-data: " + pingbackMetaDataFilename);
} catch (IOException e) {
_logger.error(e);
throw new XmlRpcException(PINGBACK_GENERIC_FAULT_CODE, "Unknown exception occurred");
}
return new Integer(0);
}
protected BlogCategory getBlogCategory(BlogUser user, HttpServletRequest httpServletRequest) {
Blog blog = user.getBlog();
String requestedCategory = httpServletRequest.getPathInfo();
String userFromPath = BlojsomUtils.getUserFromPath(httpServletRequest.getPathInfo());
if (userFromPath == null) {
requestedCategory = httpServletRequest.getPathInfo();
} else {
_logger.debug("User: " + user.getId());
_logger.debug("Path: " + userFromPath);
if (userFromPath.equals(user.getId())) {
requestedCategory = BlojsomUtils.getCategoryFromPath(httpServletRequest.getPathInfo());
} else {
requestedCategory = httpServletRequest.getPathInfo();
}
}
requestedCategory = BlojsomUtils.normalize(requestedCategory);
_logger.debug("blojsom path info: " + requestedCategory);
String categoryParameter = httpServletRequest.getParameter(CATEGORY_PARAM);
if (!(categoryParameter == null) && !("".equals(categoryParameter))) {
categoryParameter = BlojsomUtils.normalize(categoryParameter);
_logger.debug("Category parameter override: " + categoryParameter);
requestedCategory = categoryParameter;
}
if (requestedCategory == null) {
requestedCategory = "/";
} else if (!requestedCategory.endsWith("/")) {
requestedCategory += "/";
}
requestedCategory = BlojsomUtils.urlDecode(requestedCategory);
_logger.debug("User requested category: " + requestedCategory);
BlogCategory category = _fetcher.newBlogCategory();
category.setCategory(requestedCategory);
category.setCategoryURL(blog.getBlogURL() + BlojsomUtils.removeInitialSlash(requestedCategory));
try {
category.load(user);
} catch (BlojsomException e) {
_logger.error(e);
}
return category;
}
}