blob: 441dabedb7a67f84e2ef49944d128c2ddcf2fd67 [file] [log] [blame]
package com.intellij.tasks.impl.httpclient;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.tasks.impl.RequestFailedException;
import com.intellij.tasks.impl.TaskUtil;
import org.apache.commons.httpclient.HeaderElement;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ResponseHandler;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
/**
* @author Mikhail Golubev
*/
public class ResponseUtil {
public static final Logger LOG = Logger.getInstance(ResponseUtil.class);
public static final String DEFAULT_CHARSET_NAME = CharsetToolkit.UTF8;
public final static Charset DEFAULT_CHARSET = Charset.forName(DEFAULT_CHARSET_NAME);
/**
* Utility class
*/
private ResponseUtil() {
}
public static Reader getResponseContentAsReader(@NotNull HttpResponse response) throws IOException {
Header header = response.getEntity().getContentEncoding();
Charset charset = header == null ? DEFAULT_CHARSET : Charset.forName(header.getValue());
return new InputStreamReader(response.getEntity().getContent(), charset);
}
public static String getResponseContentAsString(@NotNull HttpResponse response) throws IOException {
return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
}
public static String getResponseContentAsString(@NotNull HttpMethod response) throws IOException {
// Sometimes servers don't specify encoding and HttpMethod#getResponseBodyAsString
// by default decodes from Latin-1, so we got to read byte stream and decode it from UTF-8
// manually
//if (!response.hasBeenUsed()) {
// return "";
//}
org.apache.commons.httpclient.Header header = response.getResponseHeader(HTTP.CONTENT_TYPE);
if (header != null && header.getValue().contains("charset")) {
// ISO-8859-1 if charset wasn't specified in response
return StringUtil.notNullize(response.getResponseBodyAsString());
}
else {
InputStream stream = response.getResponseBodyAsStream();
return stream == null ? "" : StreamUtil.readText(stream, DEFAULT_CHARSET_NAME);
}
}
public static Reader getResponseContentAsReader(@NotNull HttpMethod response) throws IOException {
//if (!response.hasBeenUsed()) {
// return new StringReader("");
//}
InputStream stream = response.getResponseBodyAsStream();
String charsetName = null;
org.apache.commons.httpclient.Header header = response.getResponseHeader(HTTP.CONTENT_TYPE);
if (header != null) {
// find out encoding
for (HeaderElement part : header.getElements()) {
NameValuePair pair = part.getParameterByName("charset");
if (pair != null) {
charsetName = pair.getValue();
}
}
}
return new InputStreamReader(stream, charsetName == null ? DEFAULT_CHARSET_NAME : charsetName);
}
public static final class GsonSingleObjectDeserializer<T> implements ResponseHandler<T> {
private final Gson myGson;
private final Class<T> myClass;
private final boolean myIgnoreNotFound;
public GsonSingleObjectDeserializer(@NotNull Gson gson, @NotNull Class<T> cls) {
this(gson, cls, false);
}
public GsonSingleObjectDeserializer(@NotNull Gson gson, @NotNull Class<T> cls, boolean ignoreNotFound) {
myGson = gson;
myClass = cls;
myIgnoreNotFound = ignoreNotFound;
}
@Override
public T handleResponse(HttpResponse response) throws IOException {
int statusCode = response.getStatusLine().getStatusCode();
LOG.info("Status code: " + statusCode);
if (!isSuccessful(statusCode)) {
if (statusCode == HttpStatus.SC_NOT_FOUND && myIgnoreNotFound) {
return null;
}
throw RequestFailedException.forStatusCode(statusCode);
}
try {
if (LOG.isDebugEnabled()) {
String content = getResponseContentAsString(response);
TaskUtil.prettyFormatJsonToLog(LOG, content);
return myGson.fromJson(content, myClass);
}
return myGson.fromJson(getResponseContentAsReader(response), myClass);
}
catch (JsonSyntaxException e) {
LOG.warn("Malformed server response", e);
return null;
}
}
}
public static final class GsonMultipleObjectsDeserializer<T> implements ResponseHandler<List<T>> {
private final Gson myGson;
private final TypeToken<List<T>> myTypeToken;
private final boolean myIgnoreNotFound;
public GsonMultipleObjectsDeserializer(Gson gson, TypeToken<List<T>> typeToken) {
this(gson, typeToken, false);
}
public GsonMultipleObjectsDeserializer(@NotNull Gson gson, @NotNull TypeToken<List<T>> token, boolean ignoreNotFound) {
myGson = gson;
myTypeToken = token;
myIgnoreNotFound = ignoreNotFound;
}
@Override
public List<T> handleResponse(HttpResponse response) throws IOException {
int statusCode = response.getStatusLine().getStatusCode();
if (!isSuccessful(statusCode)) {
if (statusCode == HttpStatus.SC_NOT_FOUND && myIgnoreNotFound) {
return Collections.emptyList();
}
throw RequestFailedException.forStatusCode(statusCode);
}
LOG.info("Status code: " + statusCode);
try {
if (LOG.isDebugEnabled()) {
String content = getResponseContentAsString(response);
TaskUtil.prettyFormatJsonToLog(LOG, content);
return myGson.fromJson(content, myTypeToken.getType());
}
return myGson.fromJson(getResponseContentAsReader(response), myTypeToken.getType());
}
catch (JsonSyntaxException e) {
LOG.warn("Malformed server response", e);
return Collections.emptyList();
}
}
}
public static boolean isSuccessful(int statusCode) {
return statusCode / 100 == 2;
}
public static boolean isClientError(int statusCode) {
return statusCode / 100 == 4;
}
public static boolean isServerError(int statusCode) {
return statusCode / 100 == 5;
}
}