package net.dev123.mblog.twitter;
import java.io.IOException;
import java.util.Date;
import net.dev123.commons.Constants;
import net.dev123.commons.ServiceProvider;
import net.dev123.exception.ExceptionCode;
import net.dev123.exception.LibRuntimeException;
import net.dev123.mblog.entity.RateLimitStatus;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TwitterResponseHandler Twitter Http响应处理类,包级别访问权限控制
*
* @version
* @author 马庆升
* @time 2010-8-30 下午02:32:40
*/
class TwitterResponseHandler implements ResponseHandler<String> {
private static final Logger logger = LoggerFactory.getLogger(TwitterResponseHandler.class.getSimpleName());
private static final String STATUS_OVER_LENGTH = "Status is over 140 characters.";
private static final String STATUS_DUPLICATE = "Status is a duplicate.";
public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException {
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
String responseString = (entity == null ? null : EntityUtils.toString(entity));
if (Constants.DEBUG) {
logger.debug("TwitterResponseHandler : {}", responseString);
}
int statusCode = statusLine.getStatusCode();
if (responseString!= null
&& responseString.contains("error")
&& responseString.startsWith("{")) {
//因为代理在出现异常的情况下Status仍可能为200,所以根据内容判断异常而不是statusCode
//确认响应是JSON对象字符串
try {
JSONObject json = new JSONObject(responseString);
if (json.has("error")) {
// 确定是异常JSON响应
String error = json.getString("error");
String request = json.getString("request");
//如果是代理的情况,搜索接口响应420 Enhance Your Calm的时候,代理可能会返回的是200,这个时候做下判断
if (statusCode == HttpStatus.SC_OK
&& TwitterRateLimitStatusAdaptor.ENHANCE_YOUR_CALM_ERROR.equals(error)) {
statusCode = TwitterRateLimitStatusAdaptor.ENHANCE_YOUR_CALM_CODE;
}
if (STATUS_OVER_LENGTH.equals(error)) {
statusCode = ExceptionCode.MicroBlog.API_CONTENT_OVER_LENGTH;
} else if (STATUS_DUPLICATE.equals(error)) {
statusCode = ExceptionCode.MicroBlog.API_TWEET_REPEAT;
}
RateLimitStatus rateLimitStatus = null;
if (statusCode == TwitterRateLimitStatusAdaptor.ENHANCE_YOUR_CALM_CODE) {
throw new LibRuntimeException(ExceptionCode.MicroBlog.API_SEARCH_RATE_LIMITED,
request, error, ServiceProvider.Twitter);
} else {
rateLimitStatus = getRateLimitStatus(response);
}
if (rateLimitStatus != null && rateLimitStatus.getRemainingHits() == 0) {
throw new LibRuntimeException(ExceptionCode.MicroBlog.API_RATE_LIMITED,
request, error, ServiceProvider.Twitter);
}
throw new LibRuntimeException(statusCode, request, error, ServiceProvider.Twitter);
}
} catch (JSONException e) {
throw new LibRuntimeException(ExceptionCode.JSON_PARSE_ERROR,
e, ServiceProvider.Twitter);
}
}
if (statusCode >= 300) {
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
return responseString;
}
private RateLimitStatus getFeatureRateLimitStatus(final HttpResponse response) {
int remainingHits; // "X-FeatureRateLimit-Remaining"
int hourlyLimit; // "X-FeatureRateLimit-Limit"
int resetTimeInSeconds; // Need to be calculated.
Date resetTime; // new Date("X-FeatureRateLimit-Reset")
Header limit = response.getFirstHeader("X-FeatureRateLimit-Limit");
if (null != limit) {
hourlyLimit = Integer.parseInt(limit.getValue());
} else {
return null;
}
Header remaining = response.getFirstHeader("X-FeatureRateLimit-Remaining");
if (null != remaining) {
remainingHits = Integer.parseInt(remaining.getValue());
} else {
return null;
}
Header reset = response.getFirstHeader("X-FeatureRateLimit-Reset");
if (null != reset) {
long longReset = Long.parseLong(reset.getValue());
resetTimeInSeconds = (int) (longReset / 1000);
resetTime = new Date(longReset * 1000);
} else {
return null;
}
RateLimitStatus rateLimit = new RateLimitStatus();
rateLimit.setHourlyLimit(hourlyLimit);
rateLimit.setRemainingHits(remainingHits);
rateLimit.setResetTime(resetTime);
rateLimit.setResetTimeInSeconds(resetTimeInSeconds);
return rateLimit;
}
private RateLimitStatus getRateLimitStatus(final HttpResponse response) {
int remainingHits; // "X-RateLimit-Remaining"
int hourlyLimit; // "X-RateLimit-Limit"
int resetTimeInSeconds; // Need to be calculated.
Date resetTime; // new Date("X-RateLimit-Reset")
Header limit = response.getFirstHeader("X-RateLimit-Limit");
if (null != limit) {
hourlyLimit = Integer.parseInt(limit.getValue());
} else {
return null;
}
Header remaining = response.getFirstHeader("X-RateLimit-Remaining");
if (null != remaining) {
remainingHits = Integer.parseInt(remaining.getValue());
} else {
return null;
}
Header reset = response.getFirstHeader("X-RateLimit-Reset");
if (null != reset) {
long longReset = Long.parseLong(reset.getValue());
resetTimeInSeconds = (int) (longReset / 1000);
resetTime = new Date(longReset * 1000);
} else {
return null;
}
RateLimitStatus rateLimit = new RateLimitStatus();
rateLimit.setHourlyLimit(hourlyLimit);
rateLimit.setRemainingHits(remainingHits);
rateLimit.setResetTime(resetTime);
rateLimit.setResetTimeInSeconds(resetTimeInSeconds);
return rateLimit;
}
}