Reworked handling of error-responses from the Graph-API
[facebook-utils] / src / main / java / de / juplo / facebook / client / GraphApiErrorHandler.java
1 package de.juplo.facebook.client;
2
3 import de.juplo.facebook.exceptions.GraphApiException;
4 import java.io.ByteArrayInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import org.springframework.http.HttpHeaders;
8 import org.springframework.http.HttpStatus;
9 import org.springframework.http.client.ClientHttpResponse;
10 import org.springframework.util.FileCopyUtils;
11 import org.springframework.web.client.ResponseErrorHandler;
12
13
14
15 /**
16  * Error-Handler for error-messages from the Facebook Graph-API.
17  * <p>
18  * This error-handler handels responses withe the HTTP-status code
19  * {@code 4xx}. It tries to extract and parse the error-message
20  * from the HTTP-body. Successfully extracted and parsed messages are mapped
21  * to a hierarchy of exceptions, that reflects the hierarchy of the error-
22  * codes and -types.
23  * <p>
24  * If the HTTP-status-code of the response is not {@code 4xx} or
25  * the HTTP-body could not be extracted or parsed, this error-handler
26  * delegates the handling to its parent.
27  *
28  * @see <a href="https://developers.facebook.com/docs/graph-api/using-graph-api/v2.5#errors">Graph-API Documentation</a>
29  * @see <a href="http://fbdevwiki.com/wiki/Error_codes">Inofficial Wiki For Facebook-Developers</a>
30  * @author Kai Moritz
31  */
32 public class GraphApiErrorHandler implements ResponseErrorHandler
33 {
34   private final ResponseErrorHandler parent;
35
36
37   public GraphApiErrorHandler(ResponseErrorHandler errorHandler)
38   {
39     this.parent = errorHandler;
40   }
41
42
43   @Override
44   public boolean hasError(ClientHttpResponse response) throws IOException
45   {
46     return
47         HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series())
48         || this.parent.hasError(response);
49   }
50
51   @Override
52   public void handleError(final ClientHttpResponse response) throws IOException
53   {
54     if (!HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series()))
55     {
56       // Let the parent-error-handler handle all errors, that are no client
57       // errors (4xx).
58       parent.handleError(response);
59       return;
60     }
61
62
63     if (response.getBody() == null)
64     {
65       // There is no body to interpret in the HTTP-message
66       parent.handleError(response);
67       return;
68     }
69
70     final byte[] body = FileCopyUtils.copyToByteArray(response.getBody());
71     GraphApiException error;
72
73     try
74     {
75       error = GraphApiException.create(body);
76     }
77     catch (Exception e)
78     {
79       // The body of the HTTP-message could not be parsed.
80       // Let the parent error-handler try to handle the response.
81
82       // To do so, we have to wrap the original response to fill in
83       // the buffered body, if needed
84       ClientHttpResponse buffered = new ClientHttpResponse()
85       {
86         @Override
87         public HttpStatus getStatusCode() throws IOException
88         {
89           return response.getStatusCode();
90         }
91
92         @Override
93         public synchronized InputStream getBody() throws IOException
94         {
95           return new ByteArrayInputStream(body);
96         }
97
98         @Override
99         public HttpHeaders getHeaders()
100         {
101           return response.getHeaders();
102         }
103
104         @Override
105         public String getStatusText() throws IOException
106         {
107           return response.getStatusText();
108         }
109
110         @Override
111         public void close()
112         {
113           response.close();
114         }
115
116         @Override
117         public int getRawStatusCode() throws IOException
118         {
119           return response.getRawStatusCode();
120         }
121       };
122
123       parent.handleError(buffered);
124       return;
125     }
126
127     throw error;
128   }
129 }