From: Kai Moritz Date: Tue, 7 Jun 2016 13:10:08 +0000 (+0200) Subject: Refactoring: renamed package de.juplo.facebook.exceptions to errors X-Git-Tag: wip-webclient~78 X-Git-Url: http://juplo.de/gitweb/?a=commitdiff_plain;h=89065da8bbd59c4973d837c10cf63d967f6357cc;p=facebook-errors Refactoring: renamed package de.juplo.facebook.exceptions to errors --- diff --git a/src/main/java/de/juplo/facebook/FacebookUtils.java b/src/main/java/de/juplo/facebook/FacebookUtils.java index 1a76601..f6f6b37 100644 --- a/src/main/java/de/juplo/facebook/FacebookUtils.java +++ b/src/main/java/de/juplo/facebook/FacebookUtils.java @@ -1,8 +1,8 @@ package de.juplo.facebook; +import de.juplo.facebook.errors.GraphApiErrorHandler; import de.juplo.facebook.token.SignedRequestAwareAuthorizationCodeAccessTokenProvider; -import de.juplo.facebook.exceptions.GraphApiErrorHandler; import java.util.Arrays; import java.util.LinkedList; import java.util.List; diff --git a/src/main/java/de/juplo/facebook/errors/AccessTokenRequiredException.java b/src/main/java/de/juplo/facebook/errors/AccessTokenRequiredException.java new file mode 100644 index 0000000..5b54096 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/AccessTokenRequiredException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * 104: An access token is required to request this resource. + * @author Kai Moritz + */ +public class AccessTokenRequiredException extends OAuthException +{ + protected AccessTokenRequiredException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/CallbackVerificationFailedException.java b/src/main/java/de/juplo/facebook/errors/CallbackVerificationFailedException.java new file mode 100644 index 0000000..27ef936 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/CallbackVerificationFailedException.java @@ -0,0 +1,14 @@ +package de.juplo.facebook.errors; + + +/** + * 2200: Callback verification failed. + * @author Kai Moritz + */ +public class CallbackVerificationFailedException extends OAuthException +{ + protected CallbackVerificationFailedException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/FacebookErrorMessage.java b/src/main/java/de/juplo/facebook/errors/FacebookErrorMessage.java new file mode 100644 index 0000000..495c665 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/FacebookErrorMessage.java @@ -0,0 +1,42 @@ +package de.juplo.facebook.errors; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonRootName; + + + +/** + * This class represents an error message from the Graph-API + * + * @see Graph-API Documentation + * @author Kai Moritz + */ +@JsonRootName("error") +@JsonPropertyOrder({ + "message", + "type", + "code", + "error_subcode", + "error_user_title", + "error_user_msg", + "fbtrace_id" + }) +public class FacebookErrorMessage +{ + @JsonProperty("message") + String message; + @JsonProperty("type") + String type; + @JsonProperty("code") + Integer code; + @JsonProperty("error_subcode") + Integer subCode; + @JsonProperty("error_user_title") + String userTitle; + @JsonProperty("error_user_msg") + String userMessage; + @JsonProperty("fbtrace_id") + String traceId; +} diff --git a/src/main/java/de/juplo/facebook/errors/GraphApiErrorHandler.java b/src/main/java/de/juplo/facebook/errors/GraphApiErrorHandler.java new file mode 100644 index 0000000..13a93e8 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/GraphApiErrorHandler.java @@ -0,0 +1,140 @@ +package de.juplo.facebook.errors; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.client.ResponseErrorHandler; + + + +/** + * Error-Handler for error-messages from the Facebook Graph-API. + *

+ * This error-handler handels responses withe the HTTP-status code + * {@code 400 BAD REQUEST}. It tries to extract and parse the error-message + * from the HTTP-body. Successfully extracted and parsed messages are mapped + * to a hierarchy of exceptions, that reflects the hierarchy of the error- + * codes and -types. + *

+ * If the HTTP-status-code of the response is not {@code 400 BAD REQUEST} or + * the HTTP-body could not be extracted or parsed, this error-handler + * delegates the handling to its parent. + * + * @see Graph-API Documentation + * @see Inofficial Wiki For Facebook-Developers + * @author Kai Moritz + */ +public class GraphApiErrorHandler implements ResponseErrorHandler +{ + private final static Logger LOG = + LoggerFactory.getLogger(GraphApiErrorHandler.class); + + private final ResponseErrorHandler parent; + + + public GraphApiErrorHandler(ResponseErrorHandler errorHandler) + { + this.parent = errorHandler; + } + + + @Override + public boolean hasError(ClientHttpResponse response) throws IOException + { + return + HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series()) + || this.parent.hasError(response); + } + + @Override + public void handleError(final ClientHttpResponse response) throws IOException + { + if (!HttpStatus.BAD_REQUEST.equals(response.getStatusCode())) + { + // We will only handle 400 BAD REQUEST + LOG.debug("ignoring response with status-code {}.", response.getStatusCode()); + parent.handleError(response); + return; + } + + + if (response.getBody() == null) + { + // There is no body to interpret in the HTTP-message + LOG.warn("Could not convert the response into an exception, because there is no message-body."); + parent.handleError(response); + return; + } + + final byte[] body = FileCopyUtils.copyToByteArray(response.getBody()); + GraphApiException error; + + try + { + error = GraphApiException.create(body); + if (LOG.isInfoEnabled()) + LOG.info("error-response: {}", new String(body, Charset.forName("UTF-8"))); + } + catch (Exception e) + { + // The body of the HTTP-message could not be parsed. + // Let the parent error-handler try to handle the response. + + LOG.warn("Could not convert the response into an exception, because the body is unparsable: {}", body); + + // To do so, we have to wrap the original response to fill in + // the buffered body, if needed + ClientHttpResponse buffered = new ClientHttpResponse() + { + @Override + public HttpStatus getStatusCode() throws IOException + { + return response.getStatusCode(); + } + + @Override + public synchronized InputStream getBody() throws IOException + { + return new ByteArrayInputStream(body); + } + + @Override + public HttpHeaders getHeaders() + { + return response.getHeaders(); + } + + @Override + public String getStatusText() throws IOException + { + return response.getStatusText(); + } + + @Override + public void close() + { + response.close(); + } + + @Override + public int getRawStatusCode() throws IOException + { + return response.getRawStatusCode(); + } + }; + + parent.handleError(buffered); + return; + } + + throw error; + } +} diff --git a/src/main/java/de/juplo/facebook/errors/GraphApiException.java b/src/main/java/de/juplo/facebook/errors/GraphApiException.java new file mode 100644 index 0000000..45dd38a --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/GraphApiException.java @@ -0,0 +1,147 @@ +package de.juplo.facebook.errors; + + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.io.IOException; +import java.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; + + + +/** + * Base exception for Facebook Graph-Api exceptions. + * + * @author Kai Moritz + */ +public class GraphApiException extends OAuth2Exception +{ + public enum Type { OAuthException, GraphMethodException } + + + final static Logger LOG = LoggerFactory.getLogger(GraphApiException.class); + final static ObjectMapper OBJECT_MAPPER; + + private final FacebookErrorMessage error; + + + static + { + OBJECT_MAPPER = new ObjectMapper(); + OBJECT_MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true); + OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false); + OBJECT_MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, true); + } + + + public static GraphApiException create(InputStream in) + throws + IOException, + JsonParseException, + JsonMappingException + { + return create(OBJECT_MAPPER.readValue(in, FacebookErrorMessage.class)); + } + + public static GraphApiException create(byte[] message) + throws + IOException, + JsonParseException, + JsonMappingException + { + return create(OBJECT_MAPPER.readValue(message, FacebookErrorMessage.class)); + } + + public static GraphApiException create(FacebookErrorMessage error) + { + // see: http://fbdevwiki.com/wiki/Error_codes + switch(error.code) + { + // 1..99: general errors + case 1: return new UnknownErrorException(error); + case 2: return new UnexpectedErrorException(error); + case 21: return new PageMigratedException(error); + // 100..199: graph method errors + case 100: return new UnsupportedGetRequestException(error); + case 104: return new AccessTokenRequiredException(error); + // 200..299: permission errors + // 300..399: data editing errors + // 400..449: authentication error + // 450..499: session errors + // 500..599: application messaging errors + // 600..699: FQL errors + case 613: return new RateExceededException(error); + // 700..749: ref errors + // 750..799: application integration errors + // 900..949: application information errors + // 950..999: batch api errors + // 1000..1099: event api errors + // 1100..1199: live-message errors + case 2200: return new CallbackVerificationFailedException(error); + + default: + LOG.info("unmapped error: {}", error); + return new UnmappedErrorException(error); + } + } + + + protected GraphApiException(FacebookErrorMessage error) + { + super(error.message); + this.error = error; + } + + + public Type getType() + { + return error.type == null ? null : Type.valueOf(error.type); + } + + public Integer getCode() + { + return error.code; + } + + public Integer getSubCode() + { + return error.subCode; + } + + public String getUserTitle() + { + return error.userTitle; + } + + public String getUserMessage() + { + return error.userMessage; + } + + public String getTraceId() + { + return error.traceId; + } + + + @Override + public String toString() + { + try + { + return OBJECT_MAPPER.writeValueAsString(error); + } + catch(JsonProcessingException e) + { + // This should never happen. But in case of a mistake: be verbose! + LOG.error("could not convert message into JSON: {}", e); + return e.getMessage(); + } + } +} diff --git a/src/main/java/de/juplo/facebook/errors/GraphMethodException.java b/src/main/java/de/juplo/facebook/errors/GraphMethodException.java new file mode 100644 index 0000000..afe83cb --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/GraphMethodException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * Baseclass for exceptions of type {@code GraphMethodException}. + * @author Kai Moritz + */ +public abstract class GraphMethodException extends GraphApiException +{ + GraphMethodException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/OAuthException.java b/src/main/java/de/juplo/facebook/errors/OAuthException.java new file mode 100644 index 0000000..4153dbc --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/OAuthException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * Baseclass for exceptions of type {@code OAuthException}. + * @author Kai Moritz + */ +public class OAuthException extends GraphApiException +{ + protected OAuthException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/PageMigratedException.java b/src/main/java/de/juplo/facebook/errors/PageMigratedException.java new file mode 100644 index 0000000..c339d83 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/PageMigratedException.java @@ -0,0 +1,45 @@ +package de.juplo.facebook.errors; + + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + + +/** + * 21: Page ID (XXX) was migrated to page ID (YYY). + * @author Kai Moritz + */ +public class PageMigratedException extends OAuthException +{ + private final static Pattern pattern = + Pattern.compile("Page ID ([0-9]+) was migrated to page ID ([0-9]+)"); + + private final Long oldId, newId; + + + protected PageMigratedException(FacebookErrorMessage error) + { + super(error); + Matcher matcher = pattern.matcher(error.message); + if (!matcher.find()) + { + String warning = "Could not parse migration-error: " + error.message; + LOG.error(warning); + throw new RuntimeException(warning); + } + oldId = Long.parseLong(matcher.group(1)); + newId = Long.parseLong(matcher.group(2)); + } + + + public Long getOldId() + { + return oldId; + } + + public Long getNewId() + { + return newId; + } +} diff --git a/src/main/java/de/juplo/facebook/errors/RateExceededException.java b/src/main/java/de/juplo/facebook/errors/RateExceededException.java new file mode 100644 index 0000000..e57cc45 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/RateExceededException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * 613: Calls to stream have exceeded the rate of 600 calls per 600 seconds. + * @author Kai Moritz + */ +public class RateExceededException extends OAuthException +{ + protected RateExceededException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/UnexpectedErrorException.java b/src/main/java/de/juplo/facebook/errors/UnexpectedErrorException.java new file mode 100644 index 0000000..72c071b --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/UnexpectedErrorException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * 2: An unexpected error has occurred. + * @author Kai Moritz + */ +public class UnexpectedErrorException extends OAuthException +{ + protected UnexpectedErrorException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/UnknownErrorException.java b/src/main/java/de/juplo/facebook/errors/UnknownErrorException.java new file mode 100644 index 0000000..7f5e8ff --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/UnknownErrorException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * 1: An unknown error has occurred. + * @author Kai Moritz + */ +public class UnknownErrorException extends OAuthException +{ + protected UnknownErrorException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/UnmappedErrorException.java b/src/main/java/de/juplo/facebook/errors/UnmappedErrorException.java new file mode 100644 index 0000000..839de09 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/UnmappedErrorException.java @@ -0,0 +1,18 @@ +package de.juplo.facebook.errors; + + + +/** + * Marker class for error-messages, that are not mapped yet. + * Pleas help us to complete the list of possible errors and report errors, + * that are mapped to this class to info@juplo.de. Thanxs! + * + * @author Kai Moritz + */ +public class UnmappedErrorException extends GraphApiException +{ + protected UnmappedErrorException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/errors/UnsupportedGetRequestException.java b/src/main/java/de/juplo/facebook/errors/UnsupportedGetRequestException.java new file mode 100644 index 0000000..4a5a9b8 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/UnsupportedGetRequestException.java @@ -0,0 +1,15 @@ +package de.juplo.facebook.errors; + + + +/** + * 100: Unsupported get request. + * @author Kai Moritz + */ +public class UnsupportedGetRequestException extends GraphMethodException +{ + protected UnsupportedGetRequestException(FacebookErrorMessage error) + { + super(error); + } +} diff --git a/src/main/java/de/juplo/facebook/exceptions/AccessTokenRequiredException.java b/src/main/java/de/juplo/facebook/exceptions/AccessTokenRequiredException.java deleted file mode 100644 index c55fc36..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/AccessTokenRequiredException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.juplo.facebook.exceptions; - - - -/** - * 104: An access token is required to request this resource. - * @author Kai Moritz - */ -public class AccessTokenRequiredException extends OAuthException -{ - protected AccessTokenRequiredException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/CallbackVerificationFailedException.java b/src/main/java/de/juplo/facebook/exceptions/CallbackVerificationFailedException.java deleted file mode 100644 index 5951471..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/CallbackVerificationFailedException.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.juplo.facebook.exceptions; - - -/** - * 2200: Callback verification failed. - * @author Kai Moritz - */ -public class CallbackVerificationFailedException extends OAuthException -{ - protected CallbackVerificationFailedException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/FacebookErrorMessage.java b/src/main/java/de/juplo/facebook/exceptions/FacebookErrorMessage.java deleted file mode 100644 index a1bd4b3..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/FacebookErrorMessage.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.juplo.facebook.exceptions; - - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonRootName; - - - -/** - * This class represents an error message from the Graph-API - * - * @see Graph-API Documentation - * @author Kai Moritz - */ -@JsonRootName("error") -@JsonPropertyOrder({ - "message", - "type", - "code", - "error_subcode", - "error_user_title", - "error_user_msg", - "fbtrace_id" - }) -public class FacebookErrorMessage -{ - @JsonProperty("message") - String message; - @JsonProperty("type") - String type; - @JsonProperty("code") - Integer code; - @JsonProperty("error_subcode") - Integer subCode; - @JsonProperty("error_user_title") - String userTitle; - @JsonProperty("error_user_msg") - String userMessage; - @JsonProperty("fbtrace_id") - String traceId; -} diff --git a/src/main/java/de/juplo/facebook/exceptions/GraphApiErrorHandler.java b/src/main/java/de/juplo/facebook/exceptions/GraphApiErrorHandler.java deleted file mode 100644 index 974bf85..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/GraphApiErrorHandler.java +++ /dev/null @@ -1,140 +0,0 @@ -package de.juplo.facebook.exceptions; - - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.util.FileCopyUtils; -import org.springframework.web.client.ResponseErrorHandler; - - - -/** - * Error-Handler for error-messages from the Facebook Graph-API. - *

- * This error-handler handels responses withe the HTTP-status code - * {@code 400 BAD REQUEST}. It tries to extract and parse the error-message - * from the HTTP-body. Successfully extracted and parsed messages are mapped - * to a hierarchy of exceptions, that reflects the hierarchy of the error- - * codes and -types. - *

- * If the HTTP-status-code of the response is not {@code 400 BAD REQUEST} or - * the HTTP-body could not be extracted or parsed, this error-handler - * delegates the handling to its parent. - * - * @see Graph-API Documentation - * @see Inofficial Wiki For Facebook-Developers - * @author Kai Moritz - */ -public class GraphApiErrorHandler implements ResponseErrorHandler -{ - private final static Logger LOG = - LoggerFactory.getLogger(GraphApiErrorHandler.class); - - private final ResponseErrorHandler parent; - - - public GraphApiErrorHandler(ResponseErrorHandler errorHandler) - { - this.parent = errorHandler; - } - - - @Override - public boolean hasError(ClientHttpResponse response) throws IOException - { - return - HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series()) - || this.parent.hasError(response); - } - - @Override - public void handleError(final ClientHttpResponse response) throws IOException - { - if (!HttpStatus.BAD_REQUEST.equals(response.getStatusCode())) - { - // We will only handle 400 BAD REQUEST - LOG.debug("ignoring response with status-code {}.", response.getStatusCode()); - parent.handleError(response); - return; - } - - - if (response.getBody() == null) - { - // There is no body to interpret in the HTTP-message - LOG.warn("Could not convert the response into an exception, because there is no message-body."); - parent.handleError(response); - return; - } - - final byte[] body = FileCopyUtils.copyToByteArray(response.getBody()); - GraphApiException error; - - try - { - error = GraphApiException.create(body); - if (LOG.isInfoEnabled()) - LOG.info("error-response: {}", new String(body, Charset.forName("UTF-8"))); - } - catch (Exception e) - { - // The body of the HTTP-message could not be parsed. - // Let the parent error-handler try to handle the response. - - LOG.warn("Could not convert the response into an exception, because the body is unparsable: {}", body); - - // To do so, we have to wrap the original response to fill in - // the buffered body, if needed - ClientHttpResponse buffered = new ClientHttpResponse() - { - @Override - public HttpStatus getStatusCode() throws IOException - { - return response.getStatusCode(); - } - - @Override - public synchronized InputStream getBody() throws IOException - { - return new ByteArrayInputStream(body); - } - - @Override - public HttpHeaders getHeaders() - { - return response.getHeaders(); - } - - @Override - public String getStatusText() throws IOException - { - return response.getStatusText(); - } - - @Override - public void close() - { - response.close(); - } - - @Override - public int getRawStatusCode() throws IOException - { - return response.getRawStatusCode(); - } - }; - - parent.handleError(buffered); - return; - } - - throw error; - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/GraphApiException.java b/src/main/java/de/juplo/facebook/exceptions/GraphApiException.java deleted file mode 100644 index 375c5b8..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/GraphApiException.java +++ /dev/null @@ -1,144 +0,0 @@ -package de.juplo.facebook.exceptions; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import java.io.IOException; -import java.io.InputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; - -/** - * Base exception for Facebook Graph-Api exceptions. - * - * @author Kai Moritz - */ -public class GraphApiException extends OAuth2Exception -{ - public enum Type { OAuthException, GraphMethodException } - - - final static Logger LOG = LoggerFactory.getLogger(GraphApiException.class); - final static ObjectMapper OBJECT_MAPPER; - - private final FacebookErrorMessage error; - - - static - { - OBJECT_MAPPER = new ObjectMapper(); - OBJECT_MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true); - OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false); - OBJECT_MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, true); - } - - - public static GraphApiException create(InputStream in) - throws - IOException, - JsonParseException, - JsonMappingException - { - return create(OBJECT_MAPPER.readValue(in, FacebookErrorMessage.class)); - } - - public static GraphApiException create(byte[] message) - throws - IOException, - JsonParseException, - JsonMappingException - { - return create(OBJECT_MAPPER.readValue(message, FacebookErrorMessage.class)); - } - - public static GraphApiException create(FacebookErrorMessage error) - { - // see: http://fbdevwiki.com/wiki/Error_codes - switch(error.code) - { - // 1..99: general errors - case 1: return new UnknownErrorException(error); - case 2: return new UnexpectedErrorException(error); - case 21: return new PageMigratedException(error); - // 100..199: graph method errors - case 100: return new UnsupportedGetRequestException(error); - case 104: return new AccessTokenRequiredException(error); - // 200..299: permission errors - // 300..399: data editing errors - // 400..449: authentication error - // 450..499: session errors - // 500..599: application messaging errors - // 600..699: FQL errors - case 613: return new RateExceededException(error); - // 700..749: ref errors - // 750..799: application integration errors - // 900..949: application information errors - // 950..999: batch api errors - // 1000..1099: event api errors - // 1100..1199: live-message errors - case 2200: return new CallbackVerificationFailedException(error); - - default: - LOG.info("unmapped error: {}", error); - return new UnmappedErrorException(error); - } - } - - - protected GraphApiException(FacebookErrorMessage error) - { - super(error.message); - this.error = error; - } - - - public Type getType() - { - return error.type == null ? null : Type.valueOf(error.type); - } - - public Integer getCode() - { - return error.code; - } - - public Integer getSubCode() - { - return error.subCode; - } - - public String getUserTitle() - { - return error.userTitle; - } - - public String getUserMessage() - { - return error.userMessage; - } - - public String getTraceId() - { - return error.traceId; - } - - - @Override - public String toString() - { - try - { - return OBJECT_MAPPER.writeValueAsString(error); - } - catch(JsonProcessingException e) - { - // This should never happen. But in case of a mistake: be verbose! - LOG.error("could not convert message into JSON: {}", e); - return e.getMessage(); - } - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/GraphMethodException.java b/src/main/java/de/juplo/facebook/exceptions/GraphMethodException.java deleted file mode 100644 index 7a8afc5..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/GraphMethodException.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.juplo.facebook.exceptions; - - -/** - * Baseclass for exceptions of type {@code GraphMethodException}. - * @author Kai Moritz - */ -public abstract class GraphMethodException extends GraphApiException -{ - GraphMethodException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/OAuthException.java b/src/main/java/de/juplo/facebook/exceptions/OAuthException.java deleted file mode 100644 index 2235dde..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/OAuthException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.juplo.facebook.exceptions; - - - -/** - * Baseclass for exceptions of type {@code OAuthException}. - * @author Kai Moritz - */ -public class OAuthException extends GraphApiException -{ - protected OAuthException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/PageMigratedException.java b/src/main/java/de/juplo/facebook/exceptions/PageMigratedException.java deleted file mode 100644 index 88917dc..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/PageMigratedException.java +++ /dev/null @@ -1,45 +0,0 @@ -package de.juplo.facebook.exceptions; - - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - - -/** - * 21: Page ID (XXX) was migrated to page ID (YYY). - * @author Kai Moritz - */ -public class PageMigratedException extends OAuthException -{ - private final static Pattern pattern = - Pattern.compile("Page ID ([0-9]+) was migrated to page ID ([0-9]+)"); - - private final Long oldId, newId; - - - protected PageMigratedException(FacebookErrorMessage error) - { - super(error); - Matcher matcher = pattern.matcher(error.message); - if (!matcher.find()) - { - String warning = "Could not parse migration-error: " + error.message; - LOG.error(warning); - throw new RuntimeException(warning); - } - oldId = Long.parseLong(matcher.group(1)); - newId = Long.parseLong(matcher.group(2)); - } - - - public Long getOldId() - { - return oldId; - } - - public Long getNewId() - { - return newId; - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/RateExceededException.java b/src/main/java/de/juplo/facebook/exceptions/RateExceededException.java deleted file mode 100644 index adc0b4a..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/RateExceededException.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.juplo.facebook.exceptions; - - -/** - * 613: Calls to stream have exceeded the rate of 600 calls per 600 seconds. - * @author Kai Moritz - */ -public class RateExceededException extends OAuthException -{ - protected RateExceededException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/UnexpectedErrorException.java b/src/main/java/de/juplo/facebook/exceptions/UnexpectedErrorException.java deleted file mode 100644 index c639c26..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/UnexpectedErrorException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.juplo.facebook.exceptions; - - - -/** - * 2: An unexpected error has occurred. - * @author Kai Moritz - */ -public class UnexpectedErrorException extends OAuthException -{ - protected UnexpectedErrorException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/UnknownErrorException.java b/src/main/java/de/juplo/facebook/exceptions/UnknownErrorException.java deleted file mode 100644 index b38341a..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/UnknownErrorException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.juplo.facebook.exceptions; - - - -/** - * 1: An unknown error has occurred. - * @author Kai Moritz - */ -public class UnknownErrorException extends OAuthException -{ - protected UnknownErrorException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/UnmappedErrorException.java b/src/main/java/de/juplo/facebook/exceptions/UnmappedErrorException.java deleted file mode 100644 index 2ed9b95..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/UnmappedErrorException.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.juplo.facebook.exceptions; - - -/** - * Marker class for error-messages, that are not mapped yet. - * Pleas help us to complete the list of possible errors and report errors, - * that are mapped to this class to info@juplo.de. Thanxs! - * - * @author Kai Moritz - */ -public class UnmappedErrorException extends GraphApiException -{ - protected UnmappedErrorException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/main/java/de/juplo/facebook/exceptions/UnsupportedGetRequestException.java b/src/main/java/de/juplo/facebook/exceptions/UnsupportedGetRequestException.java deleted file mode 100644 index 6905808..0000000 --- a/src/main/java/de/juplo/facebook/exceptions/UnsupportedGetRequestException.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.juplo.facebook.exceptions; - - -/** - * 100: Unsupported get request. - * @author Kai Moritz - */ -public class UnsupportedGetRequestException extends GraphMethodException -{ - protected UnsupportedGetRequestException(FacebookErrorMessage error) - { - super(error); - } -} diff --git a/src/test/java/de/juplo/facebook/errors/FacebookErrorMessageMappingTest.java b/src/test/java/de/juplo/facebook/errors/FacebookErrorMessageMappingTest.java new file mode 100644 index 0000000..08fb372 --- /dev/null +++ b/src/test/java/de/juplo/facebook/errors/FacebookErrorMessageMappingTest.java @@ -0,0 +1,61 @@ +package de.juplo.facebook.errors; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import static de.juplo.facebook.errors.GraphApiException.OBJECT_MAPPER; +import de.juplo.facebook.errors.GraphApiException.Type; +import java.io.IOException; +import org.junit.Test; +import static org.junit.Assert.assertEquals; + + + +/** + * @author Kai Moritz + */ +public class FacebookErrorMessageMappingTest +{ + final String example = + "{" + + "\"error\":{" + + "\"message\":\"Message describing the error\"," + + "\"type\":\"OAuthException\"," + + "\"code\":190," + + "\"error_subcode\":460," + + "\"error_user_title\":\"A title\"," + + "\"error_user_msg\":\"A message\"," + + "\"fbtrace_id\":\"EJplcsCHuLu\"" + + "}" + + "}"; + + + @Test + public void testSerialize() throws JsonProcessingException + { + FacebookErrorMessage error = new FacebookErrorMessage(); + error.message = "Message describing the error"; + error.type = Type.OAuthException.name(); + error.code = 190; + error.subCode = 460; + error.userTitle = "A title"; + error.userMessage = "A message"; + error.traceId = "EJplcsCHuLu"; + + assertEquals(example, OBJECT_MAPPER.writeValueAsString(error)); + } + + @Test + public void testDeserialize() throws IOException + { + FacebookErrorMessage error = + OBJECT_MAPPER.readValue(example, FacebookErrorMessage.class); + + assertEquals("Message describing the error", error.message); + assertEquals(Type.OAuthException.name(), error.type); + assertEquals(new Integer(190), error.code); + assertEquals(new Integer(460), error.subCode); + assertEquals("A title", error.userTitle); + assertEquals("A message", error.userMessage); + assertEquals("EJplcsCHuLu", error.traceId); + } +} diff --git a/src/test/java/de/juplo/facebook/errors/GraphApiErrorHandlerTest.java b/src/test/java/de/juplo/facebook/errors/GraphApiErrorHandlerTest.java new file mode 100644 index 0000000..9fc7fc3 --- /dev/null +++ b/src/test/java/de/juplo/facebook/errors/GraphApiErrorHandlerTest.java @@ -0,0 +1,802 @@ +package de.juplo.facebook.errors; + + +import de.juplo.facebook.errors.GraphApiException.Type; +import java.util.Date; +import java.util.Map; +import java.util.Set; +import javax.annotation.Resource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException; +import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; +import org.springframework.security.oauth2.client.token.AccessTokenProvider; +import org.springframework.security.oauth2.client.token.AccessTokenRequest; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import static org.springframework.security.oauth2.common.OAuth2AccessToken.OAUTH2_TYPE; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.client.HttpClientErrorException; + + + +/** + * + * @author Kai Moritz + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration( + locations = { + "classpath:/spring/test-facebook-error-handler.xml" + }) +public class GraphApiErrorHandlerTest +{ + private static final Logger log = + LoggerFactory.getLogger(GraphApiErrorHandlerTest.class); + + @Resource + private OAuth2RestTemplate clientTemplate; + + private MockClientHttpRequestFactory requestFactory; + + + @Test + public void testError1() + { + log.info("testError1"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"An unknown error has occurred.\",\n" + + " \"type\": \"OAuthException\",\n" + + " \"code\": 1\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnknownErrorException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(1), e.getCode()); + assertEquals("An unknown error has occurred.", e.getMessage()); + assertEquals(Type.OAuthException, e.getType()); + } + } + + @Test + public void testError2() + { + log.info("testError2"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"An unexpected error has occurred. Please retry your request later.\",\n" + + " \"type\": \"OAuthException\",\n" + + " \"code\": 2\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnexpectedErrorException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(2), e.getCode()); + assertEquals("An unexpected error has occurred. Please retry your request later.", e.getMessage()); + assertEquals(Type.OAuthException, e.getType()); + } + } + + @Test + public void testError21() + { + log.info("testError21"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603. Please update your API calls to the new ID\",\n" + + " \"type\": \"OAuthException\",\n" + + " \"code\": 21\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(PageMigratedException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(21), e.getCode()); + assertEquals("(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603. Please update your API calls to the new ID", e.getMessage()); + assertEquals(Type.OAuthException, e.getType()); + } + } + + @Test + public void testError100() + { + log.info("testError100"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"Unsupported get request.\",\n" + + " \"type\": \"GraphMethodException\",\n" + + " \"code\": 100\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnsupportedGetRequestException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(100), e.getCode()); + assertEquals("Unsupported get request.", e.getMessage()); + assertEquals(Type.GraphMethodException, e.getType()); + } + } + + @Test + public void testError104() + { + log.info("testError104"); + + requestFactory.setBody("{\"error\":{\"message\":\"An access token is required to request this resource.\",\"type\":\"OAuthException\",\"code\":104,\"fbtrace_id\":\"E2Jjkj5++LL\"}}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(AccessTokenRequiredException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(104), e.getCode()); + assertEquals("An access token is required to request this resource.", e.getMessage()); + assertEquals(Type.OAuthException, e.getType()); + assertEquals("E2Jjkj5++LL", e.getTraceId()); + } + } + + @Test + public void testError613() + { + log.info("testError613"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.\",\n" + + " \"type\": \"OAuthException\",\n" + + " \"code\": 613\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(RateExceededException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(613), e.getCode()); + assertEquals("(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.", e.getMessage()); + assertEquals(Type.OAuthException, e.getType()); + } + } + + @Test + public void testError2200() + { + requestFactory.setBody("{\"error\":{\"message\":\"(#2200) callback verification failed: \",\"type\":\"OAuthException\",\"code\":2200,\"fbtrace_id\":\"ESLjoZKvPXg\"}}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(CallbackVerificationFailedException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(2200), e.getCode()); + assertEquals("(#2200) callback verification failed: ", e.getMessage()); + assertEquals(Type.OAuthException, e.getType()); + assertEquals("ESLjoZKvPXg", e.getTraceId()); + } + } + + @Test + public void testUnmappedError() + { + log.info("testUnmappedError"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"This error does not exist.\",\n" + + " \"type\": \"NonexistentTypeException\",\n" + + " \"code\": 999999999\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(GraphApiException e) + { + log.debug("{}", e.toString()); + assertEquals("invalid_request", e.getOAuth2ErrorCode()); + assertEquals(new Integer(999999999), e.getCode()); + assertEquals("This error does not exist.", e.getMessage()); + try + { + Type type = e.getType(); + log.error("unknown type: {}", type); + fail("unmapped type was resolved by enum: " + type); + } + catch (IllegalArgumentException ee) {} + } + } + + @Test + public void testUnmappedErrors() + { + log.info("testUnmappedErrors"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": null,\n" + + " \"type\": \"WhateverTypeException\",\n" + + " \"code\": 999999999\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnmappedErrorException e) + { + log.debug("{}", e.toString()); + assertNull(e.getMessage()); + try + { + Type type = e.getType(); + log.error("unknown type: {}", type); + fail("unmapped type was resolved by enum: " + type); + } + catch (IllegalArgumentException ee) {} + assertEquals(new Integer(999999999), e.getCode()); + assertNull(e.getSubCode()); + assertNull(e.getUserTitle()); + assertNull(e.getUserMessage()); + assertNull(e.getTraceId()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"type\": \"WhateverTypeException\",\n" + + " \"code\": 999999999\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnmappedErrorException e) + { + log.debug("{}", e.toString()); + assertNull(e.getMessage()); + try + { + Type type = e.getType(); + log.error("unknown type: {}", type); + fail("unmapped type was resolved by enum: " + type); + } + catch (IllegalArgumentException ee) {} + assertEquals(new Integer(999999999), e.getCode()); + assertNull(e.getSubCode()); + assertNull(e.getUserTitle()); + assertNull(e.getUserMessage()); + assertNull(e.getTraceId()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"An unmapped Graph-API-Exception.\",\n" + + " \"type\": null,\n" + + " \"code\": 999999999\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnmappedErrorException e) + { + log.debug("{}", e.toString()); + assertEquals("An unmapped Graph-API-Exception.", e.getMessage()); + assertNull(e.getType()); + assertEquals(new Integer(999999999), e.getCode()); + assertNull(e.getSubCode()); + assertNull(e.getUserTitle()); + assertNull(e.getUserMessage()); + assertNull(e.getTraceId()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"An unmapped Graph-API-Exception.\",\n" + + " \"code\": 999999999\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(UnmappedErrorException e) + { + log.debug("{}", e.toString()); + assertEquals("An unmapped Graph-API-Exception.", e.getMessage()); + assertNull(e.getType()); + assertEquals(new Integer(999999999), e.getCode()); + assertNull(e.getSubCode()); + assertNull(e.getUserTitle()); + assertNull(e.getUserMessage()); + assertNull(e.getTraceId()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + } + + @Test + public void testInvlalidErrors() + { + log.info("testInvalidErrors"); + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"Not a Graph-Api-Exception.\",\n" + + " \"type\": \"Whatever\",\n" + + " \"code\": \"some string\"\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"Not a Graph-Api-Exception.\",\n" + + " \"type\": \"Whatever\",\n" + + " \"code\": 9.9\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"Not a Graph-Api-Exception.\",\n" + + " \"type\": \"Whatever\",\n" + + " \"code\": null\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody( + "{\n" + + " \"error\":\n" + + " {\n" + + " \"message\": \"Not a Graph-Api-Exception.\",\n" + + " \"type\": \"Whatever\"\n" + + " }\n" + + "}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"error\":{\"message\":null}}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"error\":{\"type\":null}}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"error\":{\"code\":null}}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"error\":{}}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"error\":\"some message\"}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"error\":null}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{\"some filed\":\"some message\"}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody("{}"); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + + + requestFactory.setBody(""); + + try + { + clientTemplate.getForObject("ANY", SOME.class); + fail("The expected exception was not thrown"); + } + catch(HttpClientErrorException e) + { + log.debug("{}", e.toString()); + } + catch(Exception e) + { + fail("A wrong exception was thrown: " + e.toString()); + } + } + + + @Before + public void setUp() + { + requestFactory = new MockClientHttpRequestFactory(); + requestFactory.setStatus(HttpStatus.BAD_REQUEST); + requestFactory.addHeader("Content-Type", "application/json"); + clientTemplate.setRequestFactory(requestFactory); + + clientTemplate.setErrorHandler( + new GraphApiErrorHandler( + (OAuth2ErrorHandler)clientTemplate.getErrorHandler() + ) + ); + + clientTemplate.setAccessTokenProvider(new AccessTokenProvider() + { + @Override + public OAuth2AccessToken obtainAccessToken( + OAuth2ProtectedResourceDetails details, + AccessTokenRequest parameters + ) + throws + UserRedirectRequiredException, + UserApprovalRequiredException, + AccessDeniedException + { + return new OAuth2AccessToken() { + + @Override + public Map getAdditionalInformation() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getScope() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public OAuth2RefreshToken getRefreshToken() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getTokenType() + { + return OAUTH2_TYPE; + } + + @Override + public boolean isExpired() + { + return false; + } + + @Override + public Date getExpiration() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getExpiresIn() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getValue() + { + return "ANY"; + } + }; + } + + @Override + public boolean supportsResource(OAuth2ProtectedResourceDetails resource) + { + return true; + } + + @Override + public OAuth2AccessToken refreshAccessToken( + OAuth2ProtectedResourceDetails resource, + OAuth2RefreshToken refreshToken, + AccessTokenRequest request + ) + throws + UserRedirectRequiredException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource) + { + return false; + } + }); + } + + + static class SOME + { + } +} diff --git a/src/test/java/de/juplo/facebook/errors/MockClientHttpRequestFactory.java b/src/test/java/de/juplo/facebook/errors/MockClientHttpRequestFactory.java new file mode 100644 index 0000000..d5b24c3 --- /dev/null +++ b/src/test/java/de/juplo/facebook/errors/MockClientHttpRequestFactory.java @@ -0,0 +1,145 @@ +package de.juplo.facebook.errors; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpResponse; + + + +/** + * + * @author kai + */ +public class MockClientHttpRequestFactory implements ClientHttpRequestFactory +{ + private static final Logger log = + LoggerFactory.getLogger(MockClientHttpRequestFactory.class); + + private HttpStatus status = HttpStatus.OK; + private HttpHeaders headers = new HttpHeaders(); + private String body = ""; + + + @Override + public ClientHttpRequest createRequest(URI uri, HttpMethod method) throws IOException + { + return new MockClientHttpRequest(uri, method); + } + + public void setStatus(HttpStatus status) + { + this.status = status; + } + + public void setHeaders(HttpHeaders headers) + { + this.headers = headers; + } + + public void addHeader(String name, String value) + { + headers.add(name, value); + } + + public void setBody(String body) + { + log.trace(body); + this.body = body; + } + + + class MockClientHttpRequest implements ClientHttpRequest + { + private final URI uri; + private final HttpMethod method; + + + public MockClientHttpRequest(URI uri, HttpMethod method) + { + this.uri = uri; + this.method = method; + } + + + @Override + public ClientHttpResponse execute() throws IOException + { + return new MockClientHttpResponse(); + } + + @Override + public HttpMethod getMethod() + { + return method; + } + + @Override + public URI getURI() + { + return uri; + } + + @Override + public HttpHeaders getHeaders() + { + return headers; + } + + @Override + public OutputStream getBody() throws IOException + { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + + class MockClientHttpResponse implements ClientHttpResponse + { + @Override + public HttpStatus getStatusCode() throws IOException + { + return status; + } + + @Override + public int getRawStatusCode() throws IOException + { + return status.value(); + } + + @Override + public String getStatusText() throws IOException + { + return status.getReasonPhrase(); + } + + @Override + public void close() + { + } + + @Override + public InputStream getBody() throws IOException + { + return new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public HttpHeaders getHeaders() + { + return headers; + } + } +} diff --git a/src/test/java/de/juplo/facebook/exceptions/FacebookErrorMessageMappingTest.java b/src/test/java/de/juplo/facebook/exceptions/FacebookErrorMessageMappingTest.java deleted file mode 100644 index ed1cba8..0000000 --- a/src/test/java/de/juplo/facebook/exceptions/FacebookErrorMessageMappingTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.juplo.facebook.exceptions; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import static de.juplo.facebook.exceptions.GraphApiException.OBJECT_MAPPER; -import de.juplo.facebook.exceptions.GraphApiException.Type; -import java.io.IOException; -import org.junit.Test; -import static org.junit.Assert.assertEquals; - - - -/** - * @author Kai Moritz - */ -public class FacebookErrorMessageMappingTest -{ - final String example = - "{" + - "\"error\":{" + - "\"message\":\"Message describing the error\"," + - "\"type\":\"OAuthException\"," + - "\"code\":190," + - "\"error_subcode\":460," + - "\"error_user_title\":\"A title\"," + - "\"error_user_msg\":\"A message\"," + - "\"fbtrace_id\":\"EJplcsCHuLu\"" + - "}" + - "}"; - - - @Test - public void testSerialize() throws JsonProcessingException - { - FacebookErrorMessage error = new FacebookErrorMessage(); - error.message = "Message describing the error"; - error.type = Type.OAuthException.name(); - error.code = 190; - error.subCode = 460; - error.userTitle = "A title"; - error.userMessage = "A message"; - error.traceId = "EJplcsCHuLu"; - - assertEquals(example, OBJECT_MAPPER.writeValueAsString(error)); - } - - @Test - public void testDeserialize() throws IOException - { - FacebookErrorMessage error = - OBJECT_MAPPER.readValue(example, FacebookErrorMessage.class); - - assertEquals("Message describing the error", error.message); - assertEquals(Type.OAuthException.name(), error.type); - assertEquals(new Integer(190), error.code); - assertEquals(new Integer(460), error.subCode); - assertEquals("A title", error.userTitle); - assertEquals("A message", error.userMessage); - assertEquals("EJplcsCHuLu", error.traceId); - } -} diff --git a/src/test/java/de/juplo/facebook/exceptions/GraphApiErrorHandlerTest.java b/src/test/java/de/juplo/facebook/exceptions/GraphApiErrorHandlerTest.java deleted file mode 100644 index 86e1dfd..0000000 --- a/src/test/java/de/juplo/facebook/exceptions/GraphApiErrorHandlerTest.java +++ /dev/null @@ -1,801 +0,0 @@ -package de.juplo.facebook.exceptions; - -import de.juplo.facebook.exceptions.GraphApiException.Type; -import java.util.Date; -import java.util.Map; -import java.util.Set; -import javax.annotation.Resource; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.oauth2.client.OAuth2RestTemplate; -import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler; -import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; -import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException; -import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; -import org.springframework.security.oauth2.client.token.AccessTokenProvider; -import org.springframework.security.oauth2.client.token.AccessTokenRequest; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import static org.springframework.security.oauth2.common.OAuth2AccessToken.OAUTH2_TYPE; -import org.springframework.security.oauth2.common.OAuth2RefreshToken; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.web.client.HttpClientErrorException; - - - -/** - * - * @author Kai Moritz - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration( - locations = { - "classpath:/spring/test-facebook-error-handler.xml" - }) -public class GraphApiErrorHandlerTest -{ - private static final Logger log = - LoggerFactory.getLogger(GraphApiErrorHandlerTest.class); - - @Resource - private OAuth2RestTemplate clientTemplate; - - private MockClientHttpRequestFactory requestFactory; - - - @Test - public void testError1() - { - log.info("testError1"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"An unknown error has occurred.\",\n" + - " \"type\": \"OAuthException\",\n" + - " \"code\": 1\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnknownErrorException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(1), e.getCode()); - assertEquals("An unknown error has occurred.", e.getMessage()); - assertEquals(Type.OAuthException, e.getType()); - } - } - - @Test - public void testError2() - { - log.info("testError2"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"An unexpected error has occurred. Please retry your request later.\",\n" + - " \"type\": \"OAuthException\",\n" + - " \"code\": 2\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnexpectedErrorException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(2), e.getCode()); - assertEquals("An unexpected error has occurred. Please retry your request later.", e.getMessage()); - assertEquals(Type.OAuthException, e.getType()); - } - } - - @Test - public void testError21() - { - log.info("testError21"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603. Please update your API calls to the new ID\",\n" + - " \"type\": \"OAuthException\",\n" + - " \"code\": 21\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(PageMigratedException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(21), e.getCode()); - assertEquals("(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603. Please update your API calls to the new ID", e.getMessage()); - assertEquals(Type.OAuthException, e.getType()); - } - } - - @Test - public void testError100() - { - log.info("testError100"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"Unsupported get request.\",\n" + - " \"type\": \"GraphMethodException\",\n" + - " \"code\": 100\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnsupportedGetRequestException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(100), e.getCode()); - assertEquals("Unsupported get request.", e.getMessage()); - assertEquals(Type.GraphMethodException, e.getType()); - } - } - - @Test - public void testError104() - { - log.info("testError104"); - - requestFactory.setBody("{\"error\":{\"message\":\"An access token is required to request this resource.\",\"type\":\"OAuthException\",\"code\":104,\"fbtrace_id\":\"E2Jjkj5++LL\"}}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(AccessTokenRequiredException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(104), e.getCode()); - assertEquals("An access token is required to request this resource.", e.getMessage()); - assertEquals(Type.OAuthException, e.getType()); - assertEquals("E2Jjkj5++LL", e.getTraceId()); - } - } - - @Test - public void testError613() - { - log.info("testError613"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.\",\n" + - " \"type\": \"OAuthException\",\n" + - " \"code\": 613\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(RateExceededException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(613), e.getCode()); - assertEquals("(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.", e.getMessage()); - assertEquals(Type.OAuthException, e.getType()); - } - } - - @Test - public void testError2200() - { - requestFactory.setBody("{\"error\":{\"message\":\"(#2200) callback verification failed: \",\"type\":\"OAuthException\",\"code\":2200,\"fbtrace_id\":\"ESLjoZKvPXg\"}}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(CallbackVerificationFailedException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(2200), e.getCode()); - assertEquals("(#2200) callback verification failed: ", e.getMessage()); - assertEquals(Type.OAuthException, e.getType()); - assertEquals("ESLjoZKvPXg", e.getTraceId()); - } - } - - @Test - public void testUnmappedError() - { - log.info("testUnmappedError"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"This error does not exist.\",\n" + - " \"type\": \"NonexistentTypeException\",\n" + - " \"code\": 999999999\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(GraphApiException e) - { - log.debug("{}", e.toString()); - assertEquals("invalid_request", e.getOAuth2ErrorCode()); - assertEquals(new Integer(999999999), e.getCode()); - assertEquals("This error does not exist.", e.getMessage()); - try - { - Type type = e.getType(); - log.error("unknown type: {}", type); - fail("unmapped type was resolved by enum: " + type); - } - catch (IllegalArgumentException ee) {} - } - } - - @Test - public void testUnmappedErrors() - { - log.info("testUnmappedErrors"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": null,\n" + - " \"type\": \"WhateverTypeException\",\n" + - " \"code\": 999999999\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnmappedErrorException e) - { - log.debug("{}", e.toString()); - assertNull(e.getMessage()); - try - { - Type type = e.getType(); - log.error("unknown type: {}", type); - fail("unmapped type was resolved by enum: " + type); - } - catch (IllegalArgumentException ee) {} - assertEquals(new Integer(999999999), e.getCode()); - assertNull(e.getSubCode()); - assertNull(e.getUserTitle()); - assertNull(e.getUserMessage()); - assertNull(e.getTraceId()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"type\": \"WhateverTypeException\",\n" + - " \"code\": 999999999\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnmappedErrorException e) - { - log.debug("{}", e.toString()); - assertNull(e.getMessage()); - try - { - Type type = e.getType(); - log.error("unknown type: {}", type); - fail("unmapped type was resolved by enum: " + type); - } - catch (IllegalArgumentException ee) {} - assertEquals(new Integer(999999999), e.getCode()); - assertNull(e.getSubCode()); - assertNull(e.getUserTitle()); - assertNull(e.getUserMessage()); - assertNull(e.getTraceId()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"An unmapped Graph-API-Exception.\",\n" + - " \"type\": null,\n" + - " \"code\": 999999999\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnmappedErrorException e) - { - log.debug("{}", e.toString()); - assertEquals("An unmapped Graph-API-Exception.", e.getMessage()); - assertNull(e.getType()); - assertEquals(new Integer(999999999), e.getCode()); - assertNull(e.getSubCode()); - assertNull(e.getUserTitle()); - assertNull(e.getUserMessage()); - assertNull(e.getTraceId()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"An unmapped Graph-API-Exception.\",\n" + - " \"code\": 999999999\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(UnmappedErrorException e) - { - log.debug("{}", e.toString()); - assertEquals("An unmapped Graph-API-Exception.", e.getMessage()); - assertNull(e.getType()); - assertEquals(new Integer(999999999), e.getCode()); - assertNull(e.getSubCode()); - assertNull(e.getUserTitle()); - assertNull(e.getUserMessage()); - assertNull(e.getTraceId()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - } - - @Test - public void testInvlalidErrors() - { - log.info("testInvalidErrors"); - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"Not a Graph-Api-Exception.\",\n" + - " \"type\": \"Whatever\",\n" + - " \"code\": \"some string\"\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"Not a Graph-Api-Exception.\",\n" + - " \"type\": \"Whatever\",\n" + - " \"code\": 9.9\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"Not a Graph-Api-Exception.\",\n" + - " \"type\": \"Whatever\",\n" + - " \"code\": null\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody( - "{\n" + - " \"error\":\n" + - " {\n" + - " \"message\": \"Not a Graph-Api-Exception.\",\n" + - " \"type\": \"Whatever\"\n" + - " }\n" + - "}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"error\":{\"message\":null}}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"error\":{\"type\":null}}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"error\":{\"code\":null}}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"error\":{}}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"error\":\"some message\"}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"error\":null}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{\"some filed\":\"some message\"}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody("{}"); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - - - requestFactory.setBody(""); - - try - { - clientTemplate.getForObject("ANY", SOME.class); - fail("The expected exception was not thrown"); - } - catch(HttpClientErrorException e) - { - log.debug("{}", e.toString()); - } - catch(Exception e) - { - fail("A wrong exception was thrown: " + e.toString()); - } - } - - - @Before - public void setUp() - { - requestFactory = new MockClientHttpRequestFactory(); - requestFactory.setStatus(HttpStatus.BAD_REQUEST); - requestFactory.addHeader("Content-Type", "application/json"); - clientTemplate.setRequestFactory(requestFactory); - - clientTemplate.setErrorHandler( - new GraphApiErrorHandler( - (OAuth2ErrorHandler)clientTemplate.getErrorHandler() - ) - ); - - clientTemplate.setAccessTokenProvider(new AccessTokenProvider() - { - @Override - public OAuth2AccessToken obtainAccessToken( - OAuth2ProtectedResourceDetails details, - AccessTokenRequest parameters - ) - throws - UserRedirectRequiredException, - UserApprovalRequiredException, - AccessDeniedException - { - return new OAuth2AccessToken() { - - @Override - public Map getAdditionalInformation() - { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Set getScope() - { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public OAuth2RefreshToken getRefreshToken() - { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public String getTokenType() - { - return OAUTH2_TYPE; - } - - @Override - public boolean isExpired() - { - return false; - } - - @Override - public Date getExpiration() - { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int getExpiresIn() - { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public String getValue() - { - return "ANY"; - } - }; - } - - @Override - public boolean supportsResource(OAuth2ProtectedResourceDetails resource) - { - return true; - } - - @Override - public OAuth2AccessToken refreshAccessToken( - OAuth2ProtectedResourceDetails resource, - OAuth2RefreshToken refreshToken, - AccessTokenRequest request - ) - throws - UserRedirectRequiredException - { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource) - { - return false; - } - }); - } - - - static class SOME - { - } -} diff --git a/src/test/java/de/juplo/facebook/exceptions/MockClientHttpRequestFactory.java b/src/test/java/de/juplo/facebook/exceptions/MockClientHttpRequestFactory.java deleted file mode 100644 index 34dc793..0000000 --- a/src/test/java/de/juplo/facebook/exceptions/MockClientHttpRequestFactory.java +++ /dev/null @@ -1,144 +0,0 @@ -package de.juplo.facebook.exceptions; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpRequest; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.ClientHttpResponse; - - - -/** - * - * @author kai - */ -public class MockClientHttpRequestFactory implements ClientHttpRequestFactory -{ - private static final Logger log = - LoggerFactory.getLogger(MockClientHttpRequestFactory.class); - - private HttpStatus status = HttpStatus.OK; - private HttpHeaders headers = new HttpHeaders(); - private String body = ""; - - - @Override - public ClientHttpRequest createRequest(URI uri, HttpMethod method) throws IOException - { - return new MockClientHttpRequest(uri, method); - } - - public void setStatus(HttpStatus status) - { - this.status = status; - } - - public void setHeaders(HttpHeaders headers) - { - this.headers = headers; - } - - public void addHeader(String name, String value) - { - headers.add(name, value); - } - - public void setBody(String body) - { - log.trace(body); - this.body = body; - } - - - class MockClientHttpRequest implements ClientHttpRequest - { - private final URI uri; - private final HttpMethod method; - - - public MockClientHttpRequest(URI uri, HttpMethod method) - { - this.uri = uri; - this.method = method; - } - - - @Override - public ClientHttpResponse execute() throws IOException - { - return new MockClientHttpResponse(); - } - - @Override - public HttpMethod getMethod() - { - return method; - } - - @Override - public URI getURI() - { - return uri; - } - - @Override - public HttpHeaders getHeaders() - { - return headers; - } - - @Override - public OutputStream getBody() throws IOException - { - throw new UnsupportedOperationException("Not supported yet."); - } - } - - - class MockClientHttpResponse implements ClientHttpResponse - { - @Override - public HttpStatus getStatusCode() throws IOException - { - return status; - } - - @Override - public int getRawStatusCode() throws IOException - { - return status.value(); - } - - @Override - public String getStatusText() throws IOException - { - return status.getReasonPhrase(); - } - - @Override - public void close() - { - } - - @Override - public InputStream getBody() throws IOException - { - return new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); - } - - @Override - public HttpHeaders getHeaders() - { - return headers; - } - } -}