package com.fpcms.common.blog_post;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.fpcms.common.util.HtmlUtil;
public abstract class BaseBlogPoster implements BlogPoster,InitializingBean{
static Logger logger = LoggerFactory.getLogger(BaseBlogPoster.class);
private BlogPosterHelper helper = new BlogPosterHelper();
private String loginUrl = null;
private String postNewBlogUrl = null;
private String postNewBlogContentType = null;
private Map<String,String> postNewBlogHeaders = new HashMap<String,String>();
private HttpClient client = new HttpClient();
{
// client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
// CookiePolicy.registerCookieSpec("accept_all", AcceptAllCookieSpecBase.class);
// client.getParams().setCookiePolicy("accept_all");
}
// public static class AcceptAllCookieSpecBase extends CookieSpecBase{
// @Override
// public boolean domainMatch(String host, String domain) {
// return true;
// }
// @Override
// public boolean pathMatch(String path, String topmostPath) {
// return true;
// }
//// @Override
//// public boolean match(String host, int port, String path,
//// boolean secure, Cookie cookie) {
//// return true;
//// }
// }
public String getLoginUrl() {
return loginUrl;
}
public void setLoginUrl(String loginUrl) {
this.loginUrl = StringUtils.trim(loginUrl);
}
public String getPostNewBlogUrl() {
return postNewBlogUrl;
}
public void setPostNewBlogUrl(String postNewBlogUrl) {
this.postNewBlogUrl = StringUtils.trim(postNewBlogUrl);
}
public void setPostNewBlogHeaders(Map<String, String> postNewBlogHeaders) {
this.postNewBlogHeaders = postNewBlogHeaders;
}
@Override
public void postBlog(Blog blog) {
try {
List<BasicClientCookie> cookies = login(blog.getUsername(),blog.getPassword());
postNewBlog(blog.getTitle(),blog.getContent(),blog.getMetaDescription(),blog.getExt(),cookies);
}catch(Exception e) {
throw new RuntimeException(e);
}
}
protected List<BasicClientCookie> login(String username,String password) throws Exception,IOException {
Assert.hasText(getLoginUrl(),"loginUrl must be not empty");
PostMethod post = helper.newPostMethod(getLoginUrl());
try {
logger.info("start login with username:"+username+" loginUrl:"+getLoginUrl());
setLoginRequestBody(username, password, post);
client.executeMethod(post);
// printResponseHeaders(post);
Cookie[] cookies = client.getState().getCookies();
// printCookies(cookies);
InputStream stream = post.getResponseBodyAsStream();
String responseString = IOUtils.toString(stream,"UTF-8");
verifyHttpStatusCode(post.getStatusCode(),"login error,username:" + username+" response:"+responseString);
Assert.isTrue(verifyLoginResult(responseString),"login error,username:"+username + " response:"+responseString);
logger.info("login_success with username:"+username+" loginUrl:"+getLoginUrl());
logger.info("responseString:"+responseString);
return fromSetCookieHeader(post.getResponseHeaders("Set-Cookie"));
}finally {
post.releaseConnection();
}
}
private static List<BasicClientCookie> fromSetCookieHeader(Header[] responseHeaders) {
List<BasicClientCookie> cookies = new ArrayList<BasicClientCookie>();
for(Header h : responseHeaders) {
BasicClientCookie cookie = parseRawCookie(h.getValue());
cookies.add(cookie);
}
return cookies;
}
private static BasicClientCookie parseRawCookie(String rawCookie) {
String[] rawCookieParams = rawCookie.split(";");
String[] rawCookieNameAndValue = splitFirst(rawCookieParams[0],'=');
if (rawCookieNameAndValue.length < 2) {
throw new RuntimeException("Invalid cookie: missing name and value. "+rawCookieParams[0]+" raw cookie:"+rawCookie);
}
String cookieName = rawCookieNameAndValue[0].trim();
String cookieValue = rawCookieNameAndValue[1].trim();
BasicClientCookie cookie = new BasicClientCookie(cookieName, cookieValue);
for (int i = 1; i < rawCookieParams.length; i++) {
String rawCookieParamNameAndValue[] = rawCookieParams[i].trim().split("=");
String paramName = rawCookieParamNameAndValue[0].trim();
if(rawCookieParamNameAndValue.length == 1) {
continue;
}
if (paramName.equalsIgnoreCase("secure")) {
cookie.setSecure(true);
} else {
String paramValue = rawCookieParamNameAndValue[1].trim();
if (paramName.equalsIgnoreCase("expires")) {
cookie.setExpiryDate(new Date(paramValue));
} else if (paramName.equalsIgnoreCase("max-age")) {
long maxAge = Long.parseLong(paramValue);
Date expiryDate = new Date(System.currentTimeMillis() + maxAge);
cookie.setExpiryDate(expiryDate);
} else if (paramName.equalsIgnoreCase("domain")) {
cookie.setDomain(paramValue);
} else if (paramName.equalsIgnoreCase("path")) {
cookie.setPath(paramValue);
} else if (paramName.equalsIgnoreCase("comment")) {
cookie.setPath(paramValue);
} else {
throw new RuntimeException("Invalid cookie: invalid attribute name. cookie name:"+paramName);
}
}
}
return cookie;
}
private static String[] splitFirst(String str,char seperator) {
int index = str.indexOf(seperator);
if(index >= 0) {
return new String[]{str.substring(0, index),str.substring(index + 1,str.length())};
}
return new String[]{str};
}
private static void printResponseHeaders(PostMethod post) {
System.out.println("--------- printResponseHeaders ------");
Header[] headers = post.getResponseHeaders();
for(Header h : headers) {
System.out.println(h.getName()+"="+h.getValue());
}
}
private static void printCookies(Cookie[] cookies) {
System.out.println("--------- printCookies ------");
for(Cookie c : cookies) {
System.out.println(c.getName()+"="+c.getValue());
}
}
private static String toRequestHeaderCookieString(List<BasicClientCookie> cookies) {
String tmpcookies = "";
for(BasicClientCookie c : cookies) {
tmpcookies = tmpcookies + c.getName()+"="+c.getValue() + "; ";
}
return tmpcookies;
}
public static void verifyHttpStatusCode(int statusCode,String attachErrorMessage) {
if(statusCode >= 200 && statusCode < 400) {
return;
}
throw new IllegalStateException("error http statusCode:" + statusCode + "; " +attachErrorMessage);
}
protected void postNewBlog(String title,String content,String metaDescription,Map<String,String> ext, List<BasicClientCookie> cookies) throws Exception,IOException, HttpException {
Assert.hasText(getPostNewBlogUrl(),"postNewBlogUrl must be not empty");
PostMethod post = helper.newPostMethod(getPostNewBlogUrl());
if(StringUtils.isNotBlank(getPostNewBlogContentType())) {
post.setRequestHeader("Content-Type",getPostNewBlogContentType());
}
for(String key : postNewBlogHeaders.keySet()) {
post.setRequestHeader(key, postNewBlogHeaders.get(key));
}
String cookieHeader = toRequestHeaderCookieString(cookies);
post.setRequestHeader("Cookie",cookieHeader);
logger.debug("postNewBlog() cookieHeader:"+cookieHeader);
try {
logger.info("start postNewBlog:"+title+" url:"+getPostNewBlogUrl());
setPostNewBlogRequestBody(title, content,metaDescription, ext, post);
client.executeMethod(post);
String charset = StringUtils.defaultIfBlank(HtmlUtil.getCharsetFromHtml(post.getResponseBodyAsString()),post.getResponseCharSet());
InputStream stream = post.getResponseBodyAsStream();
String responseString = IOUtils.toString(stream,StringUtils.defaultIfBlank(charset,"UTF-8"));
stream.close();
verifyHttpStatusCode(post.getStatusCode(),"post new blog error,blog title:"+title);
Assert.isTrue(verifyPostNewBlogResult(responseString),"post blog error,title:"+title+" response:"+responseString);
logger.info("postNewBlog_success:"+title+" url:"+getPostNewBlogUrl());
}finally {
post.releaseConnection();
}
}
public String getPostNewBlogContentType() {
return postNewBlogContentType;
}
public void setPostNewBlogContentType(String postNewBlogContentType) {
this.postNewBlogContentType = postNewBlogContentType;
}
protected boolean verifyLoginResult(String responseString) {
return true;
}
protected abstract void setLoginRequestBody(String username, String password,PostMethod post) throws Exception;
protected boolean verifyPostNewBlogResult(String responseString) {
return true;
}
protected abstract void setPostNewBlogRequestBody(String title, String content,String metaDescription, Map<String, String> ext, PostMethod post) throws Exception;
public static String urlEncode(String content)
throws UnsupportedEncodingException {
if(StringUtils.isBlank(content)) {
return null;
}
return URLEncoder.encode(content,"UTF-8");
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(getLoginUrl(),"loginUrl must be not empty");
Assert.hasText(getPostNewBlogUrl(),"postNewBlogUrl must be not empty");
logger.info("loginUrl:"+loginUrl);
logger.info("postNewBlogUrl:"+postNewBlogUrl);
}
}