The exception stores the HttpStatus and HttpHeaders of the failed request
[facebook-errors] / src / main / java / de / juplo / facebook / errors / GraphApiException.java
1 package de.juplo.facebook.errors;
2
3
4 import com.fasterxml.jackson.core.JsonParseException;
5 import com.fasterxml.jackson.core.JsonProcessingException;
6 import com.fasterxml.jackson.databind.DeserializationFeature;
7 import com.fasterxml.jackson.databind.JsonMappingException;
8 import com.fasterxml.jackson.databind.ObjectMapper;
9 import com.fasterxml.jackson.databind.SerializationFeature;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.springframework.http.HttpHeaders;
15 import org.springframework.http.HttpStatus;
16
17
18
19 /**
20  * Base exception for Facebook Graph-Api exceptions.
21  * 
22  * @author Kai Moritz
23  */
24 public class GraphApiException extends RuntimeException
25 {
26   public enum Type { OAuthException, GraphMethodException }
27
28
29   final static Logger LOG = LoggerFactory.getLogger(GraphApiException.class);
30   final static ObjectMapper OBJECT_MAPPER;
31
32   public final HttpStatus status;
33   public final HttpHeaders headers;
34   public final FacebookErrorMessage error;
35
36
37   static
38   {
39     OBJECT_MAPPER = new ObjectMapper();
40     OBJECT_MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
41     OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false);
42     OBJECT_MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
43   }
44
45
46   public static GraphApiException create(
47       HttpStatus status,
48       HttpHeaders headers,
49       InputStream in
50       )
51       throws
52         IOException,
53         JsonParseException,
54         JsonMappingException
55   {
56     return create(status, headers, OBJECT_MAPPER.readValue(in, FacebookErrorMessage.class));
57   }
58
59   public static GraphApiException create(
60       HttpStatus status,
61       HttpHeaders headers,
62       byte[] message
63       )
64       throws
65         IOException,
66         JsonParseException,
67         JsonMappingException
68   {
69     return create(status, headers, OBJECT_MAPPER.readValue(message, FacebookErrorMessage.class));
70   }
71
72   public static GraphApiException create(
73       HttpStatus status,
74       HttpHeaders headers,
75       FacebookErrorMessage error
76       )
77   {
78     // see: http://fbdevwiki.com/wiki/Error_codes
79     switch(error.code)
80     {
81       // 1..99: general errors
82       case 1:     return new UnknownErrorException(status, headers, error);
83       case 2:     return new UnexpectedErrorException(status, headers, error);
84       case 4:     return new ApplicationRequestLimitReachedException(status, headers, error);
85       case 10:    return new AuthorizationMissingException(status, headers, error);
86       case 12:    return new DeprecatedException(status, headers, error);
87       case 17:    return new AccountRequestLimitReachedException(status, headers, error);
88       case 21:    return new PageMigratedException(status, headers, error);
89       case 32:    return new PageRequestLimitReachedException(status, headers, error);
90       // 100..199: graph method errors
91       case 100:   return new UnsupportedGetRequestException(status, headers, error);
92       case 102:   return new UserAccessTokenRequiredException(status, headers, error);
93       case 104:   return new AccessTokenRequiredException(status, headers, error);
94       // 200..299: permission errors
95       case 200:
96       case 201:
97       case 202:
98       case 203:
99       case 204:
100       case 205:
101       case 206:
102       case 207:
103       case 208:
104       case 209:
105       case 210:
106       case 211:
107       case 212:
108       case 213:
109       case 214:
110       case 215:
111       case 216:
112       case 217:
113       case 218:
114       case 219:
115       case 220:
116       case 221:
117       case 222:
118       case 223:
119       case 224:
120       case 225:
121       case 226:
122       case 227:
123       case 228:
124       case 229:
125       case 230:
126       case 231:
127       case 232:
128       case 233:
129       case 234:
130       case 235:
131       case 236:
132       case 237:
133       case 238:
134       case 239:
135       case 240:
136       case 241:
137       case 242:
138       case 243:
139       case 244:
140       case 245:
141       case 246:
142       case 247:
143       case 248:
144       case 249:
145       case 250:
146       case 251:
147       case 252:
148       case 253:
149       case 254:
150       case 255:
151       case 256:
152       case 257:
153       case 258:
154       case 259:
155       case 260:
156       case 261:
157       case 262:
158       case 263:
159       case 264:
160       case 265:
161       case 266:
162       case 267:
163       case 268:
164       case 269:
165       case 270:
166       case 271:
167       case 272:
168       case 273:
169       case 274:
170       case 275:
171       case 276:
172       case 277:
173       case 278:
174       case 279:
175       case 280:
176       case 281:
177       case 282:
178       case 283:
179       case 284:
180       case 285:
181       case 286:
182       case 287:
183       case 288:
184       case 289:
185       case 290:
186       case 291:
187       case 292:
188       case 293:
189       case 294:
190       case 295:
191       case 296:
192       case 297:
193       case 298:
194       case 299:   return new AuthorizationMissingException(status, headers, error);
195       // 200..299: permission errors
196       // 300..399: data editing errors ?
197       case 341:   return new TemporaryRateLimitExceededException(status, headers, error);
198       // 400..449: authentication error
199       // 450..499: session errors
200       // 500..599: application messaging errors ?
201       case 506:   return new MultipleConcurrentPostsException(status, headers, error);
202       // 600..699: FQL errors
203       case 613:   return new CustomRequestLimitReachedException(status, headers, error);
204       // 700..749: ref errors
205       // 750..799: application integration errors
206       // 900..949: application information errors
207       // 950..999: batch api errors
208       // 1000..1099: event api errors
209       // 1100..1199: live-message errors
210       case 1609005: return new LinkPostFailureException(status, headers, error);
211       case 2200:  return new CallbackVerificationFailedException(status, headers, error);
212
213       default:
214         LOG.info("unmapped error: {}", error);
215         return new UnmappedErrorException(status, headers, error);
216     }
217   }
218
219
220   protected GraphApiException(
221       HttpStatus status,
222       HttpHeaders headers,
223       FacebookErrorMessage error
224       )
225   {
226     super(error.message);
227     this.status = status;
228     this.headers = headers;
229     this.error = error;
230   }
231
232
233   public HttpStatus getStatus()
234   {
235     return status;
236   }
237
238   public HttpHeaders getHeaders()
239   {
240     return headers;
241   }
242
243   public Type getType()
244   {
245     return error.type == null ? null : Type.valueOf(error.type);
246   }
247
248   public Integer getCode()
249   {
250     return error.code;
251   }
252
253   public Integer getSubCode()
254   {
255     return error.subCode;
256   }
257
258   public String getUserTitle()
259   {
260     return error.userTitle;
261   }
262
263   public String getUserMessage()
264   {
265     return error.userMessage;
266   }
267
268   public String getTraceId()
269   {
270     return error.traceId;
271   }
272
273
274   @Override
275   public String toString()
276   {
277     try
278     {
279       return OBJECT_MAPPER.writeValueAsString(error);
280     }
281     catch(JsonProcessingException e)
282     {
283       // This should never happen. But in case of a mistake: be verbose!
284       LOG.error("could not convert message into JSON: {}", e);
285       return e.getMessage();
286     }
287   }
288 }