WIP
[facebook-errors] / src / main / java / de / juplo / facebook / exceptions / GraphApiException.java
1 package de.juplo.facebook.exceptions;
2
3 import com.fasterxml.jackson.annotation.JsonProperty;
4 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
5 import com.fasterxml.jackson.annotation.JsonRootName;
6 import com.fasterxml.jackson.core.JsonParseException;
7 import com.fasterxml.jackson.core.JsonProcessingException;
8 import com.fasterxml.jackson.databind.DeserializationFeature;
9 import com.fasterxml.jackson.databind.JsonMappingException;
10 import com.fasterxml.jackson.databind.ObjectMapper;
11 import com.fasterxml.jackson.databind.SerializationFeature;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
17
18 /**
19  * Base exception for Facebook Graph-Api exceptions.
20  * 
21  * @author Kai Moritz
22  */
23 public class GraphApiException extends OAuth2Exception
24 {
25   public enum Type { OAuthException, GraphMethodException }
26
27
28   final static Logger LOG = LoggerFactory.getLogger(GraphApiException.class);
29   final static ObjectMapper OBJECT_MAPPER;
30
31   private final FacebookErrorMessage error;
32
33
34   static
35   {
36     OBJECT_MAPPER = new ObjectMapper();
37     OBJECT_MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
38     OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false);
39     OBJECT_MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
40     OBJECT_MAPPER.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
41   }
42
43
44   public static GraphApiException create(InputStream in)
45       throws
46         IOException,
47         JsonParseException,
48         JsonMappingException
49   {
50     return create(OBJECT_MAPPER.readValue(in, FacebookErrorMessage.class));
51   }
52
53   public static GraphApiException create(byte[] message)
54       throws
55         IOException,
56         JsonParseException,
57         JsonMappingException
58   {
59     return create(OBJECT_MAPPER.readValue(message, FacebookErrorMessage.class));
60   }
61
62   public static GraphApiException create(FacebookErrorMessage error)
63   {
64     // see: http://fbdevwiki.com/wiki/Error_codes
65     switch(error.code)
66     {
67       // 1..99: general errors
68       case 1:     return new UnknownErrorException(error);
69       case 2:     return new UnexpectedErrorException(error);
70       case 21:    return new PageMigratedException(error);
71       // 100..199: graph method errors
72       case 100:   return new UnsupportedGetRequestException(error);
73       case 104:   return new AccessTokenRequiredException(error);
74       // 200..299: permission errors
75       // 300..399: data editing errors
76       // 400..449: authentication error
77       // 450..499: session errors
78       // 500..599: application messaging errors
79       // 600..699: FQL errors
80       case 613:   return new RateExceededException(error);
81       // 700..749: ref errors
82       // 750..799: application integration errors
83       // 900..949: application information errors
84       // 950..999: batch api errors
85       // 1000..1099: event api errors
86       // 1100..1199: live-message errors
87       case 2200:  return new CallbackVerificationFailedException(error);
88
89       default:
90         LOG.info("unmapped error: {}", error);
91         return new UnmappedErrorException(error);
92     }
93   }
94
95
96   protected GraphApiException(FacebookErrorMessage error)
97   {
98     super(error.message);
99     this.error = error;
100   }
101
102
103   public Type getType()
104   {
105     return error.type == null ? null : Type.valueOf(error.type);
106   }
107
108   public Integer getCode()
109   {
110     return error.code;
111   }
112
113   public Integer getSubCode()
114   {
115     return error.subCode;
116   }
117
118   public String getUserTitle()
119   {
120     return error.userTitle;
121   }
122
123   public String getUserMessage()
124   {
125     return error.userMessage;
126   }
127
128   public String getTraceId()
129   {
130     return error.traceId;
131   }
132
133
134   @Override
135   public String toString()
136   {
137     try
138     {
139       return OBJECT_MAPPER.writeValueAsString(error);
140     }
141     catch(JsonProcessingException e)
142     {
143       // This should never happen. But in case of a mistake: be verbose!
144       LOG.error("could not convert message into JSON: {}", e);
145       return e.getMessage();
146     }
147   }
148
149
150   /**
151    * This class represents an error message from the Graph-API
152    *
153    * @see <a href="https://developers.facebook.com/docs/graph-api/using-graph-api/v2.5#errors">Graph-API Documentation</a>
154    */
155   @JsonRootName("error")
156   @JsonPropertyOrder({ "message", "type", "code", "error_subcode", "error_user_title", "error_user_msg", "fbtrace_id" })
157   public static class FacebookErrorMessage
158   {
159     @JsonProperty("message")
160     String message;
161     @JsonProperty("type")
162     String type;
163     @JsonProperty("code")
164     Integer code;
165     @JsonProperty("error_subcode")
166     Integer subCode;
167     @JsonProperty("error_user_title")
168     String userTitle;
169     @JsonProperty("error_user_msg")
170     String userMessage;
171     @JsonProperty("fbtrace_id")
172     String traceId;
173   }
174 }