1 package cn.home1.oss.lib.errorhandle.api;
2
3 import static com.google.common.collect.Maps.newLinkedHashMap;
4 import static lombok.AccessLevel.PRIVATE;
5
6 import com.fasterxml.jackson.annotation.JsonIgnore;
7 import com.fasterxml.jackson.annotation.JsonInclude;
8 import com.fasterxml.jackson.annotation.JsonProperty;
9
10 import lombok.AllArgsConstructor;
11 import lombok.Builder;
12 import lombok.EqualsAndHashCode;
13 import lombok.Getter;
14 import lombok.Setter;
15 import lombok.ToString;
16 import lombok.extern.slf4j.Slf4j;
17
18 import org.apache.commons.lang3.ArrayUtils;
19 import org.codehaus.jackson.map.annotate.JsonSerialize;
20 import org.springframework.http.HttpHeaders;
21 import org.springframework.http.HttpStatus;
22
23 import java.io.Serializable;
24 import java.util.Map;
25
26 import javax.xml.bind.annotation.XmlAccessType;
27 import javax.xml.bind.annotation.XmlAccessorType;
28 import javax.xml.bind.annotation.XmlElement;
29 import javax.xml.bind.annotation.XmlElementWrapper;
30 import javax.xml.bind.annotation.XmlElements;
31 import javax.xml.bind.annotation.XmlRootElement;
32 import javax.xml.bind.annotation.XmlType;
33
34
35
36
37
38
39
40
41 @XmlRootElement(name = "error")
42 @XmlAccessorType(XmlAccessType.FIELD)
43 @XmlType(propOrder = {
44 "error", "exception", "message", "path", "status", "timestamp", "trace", "validationErrors",
45 "datetime", "headers", "localizedMessage", "tracks"})
46 @JsonInclude(JsonInclude.Include.NON_EMPTY)
47 @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
48 @Builder(builderMethodName = "resolvedErrorBuilder")
49 @AllArgsConstructor(access = PRIVATE)
50 @ToString
51 @EqualsAndHashCode(of = {"error", "exception", "path", "status", "timestamp", "localizedMessage"})
52 @Setter(PRIVATE)
53 @Getter
54 @Slf4j
55 public class ResolvedError implements Serializable {
56
57 public static final String RESOLVED_ERROR_COOKIE = "resolvedErrorCookie";
58 public static final String RESOLVED_ERROR_OBJECT = "resolvedError";
59 static final String HEADER_RESOLVED_ERROR = "RESOLVED-ERROR";
60 private static final long serialVersionUID = 1L;
61
62
63 @JsonProperty("error")
64 private String error;
65 @XmlElement
66 private String exception;
67 private String message;
68 private String path;
69 private Integer status;
70 private Long timestamp;
71 private String trace;
72
73
74
75 @JsonProperty("validationErrors")
76 @XmlElementWrapper(name = "validationErrors")
77 @XmlElement(name = "validationError")
78
79 private ValidationError[] validationErrors;
80
81
82
83
84 private String datetime;
85
86
87
88 @JsonProperty("headers")
89 @XmlElementWrapper(name = "headers")
90 @XmlElement(name = "header")
91 private HttpHeader[] headers;
92
93
94
95 private String localizedMessage;
96
97
98
99 @JsonProperty("tracks")
100 @XmlElementWrapper(name = "tracks")
101 @XmlElement(name = "track")
102 private String[] tracks;
103
104 private ResolvedError() {
105 this.headers = HttpHeader.fromHttpHeaders(newHttpHeaders());
106 }
107
108 public static HttpHeaders newHttpHeaders() {
109 final HttpHeaders headers = new HttpHeaders();
110 headers.add(HEADER_RESOLVED_ERROR, HEADER_RESOLVED_ERROR);
111 return headers;
112 }
113
114 public static ResolvedError fromErrorAttributes(final Map<String, Object> errorAttributes) {
115 return errorAttributes == null ? null : ResolvedError.resolvedErrorBuilder()
116
117 .error((String) errorAttributes.get("error"))
118 .exception((String) errorAttributes.get("exception"))
119 .message((String) errorAttributes.get("message"))
120 .path((String) errorAttributes.get("path"))
121 .status((Integer) errorAttributes.get("status"))
122 .timestamp((Long) errorAttributes.get("timestamp"))
123 .trace((String) errorAttributes.get("trace"))
124 .validationErrors((ValidationError[]) errorAttributes.get("validationErrors"))
125
126 .datetime((String) errorAttributes.get("datetime"))
127 .headers((HttpHeader[]) errorAttributes.get("headers"))
128 .localizedMessage((String) errorAttributes.get("localizedMessage"))
129 .tracks((String[]) errorAttributes.get("tracks")).build();
130 }
131
132 @JsonIgnore
133 @org.codehaus.jackson.annotate.JsonIgnore
134 public HttpStatus getHttpStatus() {
135 HttpStatus result;
136 try {
137 result = HttpStatus.valueOf(this.status);
138 } catch (final Exception ex) {
139 result = HttpStatus.INTERNAL_SERVER_ERROR;
140 log.debug("error parse http status {}", this.status, ex);
141 }
142 return result;
143 }
144
145
146
147
148
149
150 public ResolvedError eraseTraces() {
151 this.setTracks(null);
152 this.setTrace(null);
153 return this;
154 }
155
156 public ResolvedError trackPrepend(final String track) {
157 this.tracks = this.tracks != null ?
158 ArrayUtils.add(this.tracks, 0, track) :
159 new String[]{track};
160 return this;
161 }
162
163 public Map<String, Object> toErrorAttributes() {
164 final Map<String, Object> map = newLinkedHashMap();
165
166 map.put("error", this.error);
167 map.put("exception", this.exception);
168 map.put("message", this.message);
169 map.put("path", this.path);
170 map.put("status", this.status);
171 map.put("timestamp", this.timestamp);
172 map.put("trace", this.trace);
173 map.put("validationErrors", this.validationErrors);
174
175 map.put("datetime", datetime);
176 map.put("headers", this.headers);
177 map.put("localizedMessage", this.localizedMessage);
178 map.put("tracks", this.tracks);
179
180 map.entrySet().removeIf(e -> e.getValue() == null);
181 return map;
182 }
183 }