1 package com.atlassian.plugins.rest.common;
2
3 import com.google.common.base.Preconditions;
4 import com.google.common.collect.Lists;
5 import org.apache.commons.lang.builder.EqualsBuilder;
6 import org.apache.commons.lang.builder.HashCodeBuilder;
7
8 import javax.ws.rs.core.CacheControl;
9 import javax.ws.rs.core.Response;
10 import javax.xml.bind.annotation.XmlAttribute;
11 import javax.xml.bind.annotation.XmlElement;
12 import javax.xml.bind.annotation.XmlElementWrapper;
13 import javax.xml.bind.annotation.XmlRootElement;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
17
18 import static javax.ws.rs.core.MediaType.*;
19
20
21
22
23 @XmlRootElement
24 public class Status
25 {
26
27
28
29 @XmlElement
30 private final Plugin plugin;
31
32
33
34
35
36 @XmlElement(name = "status-code")
37 private final Integer code;
38
39
40
41
42 @XmlElement(name = "sub-code")
43 private final Integer subCode;
44
45
46
47
48 @XmlElement
49 private final String message;
50
51
52
53
54
55 @XmlElement(name = "etag")
56 private final String eTag;
57
58
59
60
61 @XmlElementWrapper(name = "resources-created")
62 @XmlElement(name = "link")
63 private final Collection<Link> resourcesCreated;
64
65
66
67
68 @XmlElementWrapper(name = "resources-updated")
69 @XmlElement(name = "link")
70 private final Collection<Link> resourcesUpdated;
71
72
73 private Status()
74 {
75 this.plugin = null;
76 this.code = -1;
77 this.subCode = -1;
78 this.message = null;
79 this.eTag = null;
80 this.resourcesCreated = null;
81 this.resourcesUpdated = null;
82 }
83
84 private Status(Plugin plugin, Integer code, Integer subCode, String message, String eTag, Collection<Link> resourcesCreated, Collection<Link> resourcesUpdated)
85 {
86 this.plugin = plugin;
87 this.code = code;
88 this.subCode = subCode;
89 this.message = message;
90 this.eTag = eTag;
91 this.resourcesCreated = resourcesCreated;
92 this.resourcesUpdated = resourcesUpdated;
93 }
94
95 public static StatusResponseBuilder ok()
96 {
97 return new StatusResponseBuilder(Response.Status.OK);
98 }
99
100 public static StatusResponseBuilder notFound()
101 {
102 return new StatusResponseBuilder(Response.Status.NOT_FOUND);
103 }
104
105 public static StatusResponseBuilder error()
106 {
107
108 return new StatusResponseBuilder(Response.Status.INTERNAL_SERVER_ERROR).noCache().noStore();
109 }
110
111 public static StatusResponseBuilder badRequest()
112 {
113
114 return new StatusResponseBuilder(Response.Status.BAD_REQUEST).noCache().noStore();
115 }
116
117 public static StatusResponseBuilder forbidden()
118 {
119 return new StatusResponseBuilder(Response.Status.FORBIDDEN);
120 }
121
122 public static StatusResponseBuilder unauthorized()
123 {
124 return new StatusResponseBuilder(Response.Status.UNAUTHORIZED);
125 }
126
127 public static StatusResponseBuilder created(Link link)
128 {
129 return new StatusResponseBuilder(Response.Status.CREATED).created(Preconditions.checkNotNull(link));
130 }
131
132 public Plugin getPlugin()
133 {
134 return plugin;
135 }
136
137 public int getCode()
138 {
139 return code;
140 }
141
142 public int getSubCode()
143 {
144 return subCode;
145 }
146
147 public String getMessage()
148 {
149 return message;
150 }
151
152 public String getETag()
153 {
154 return eTag;
155 }
156
157 public Collection<Link> getResourcesCreated()
158 {
159 return Collections.unmodifiableCollection(resourcesCreated);
160 }
161
162 public Collection<Link> getResourcesUpdated()
163 {
164 return Collections.unmodifiableCollection(resourcesUpdated);
165 }
166
167 @XmlRootElement
168 public static class Plugin
169 {
170 @XmlAttribute
171 private final String key;
172
173 @XmlAttribute
174 private final String version;
175
176
177 private Plugin()
178 {
179 this.key = null;
180 this.version = null;
181 }
182
183 public Plugin(String key, String version)
184 {
185 this.key = Preconditions.checkNotNull(key);
186 this.version = Preconditions.checkNotNull(version);
187 }
188
189 public String getKey()
190 {
191 return key;
192 }
193
194 public String getVersion()
195 {
196 return version;
197 }
198
199 @Override
200 public int hashCode()
201 {
202 return new HashCodeBuilder(3, 5).append(key).append(version).toHashCode();
203 }
204
205 @Override
206 public boolean equals(Object obj)
207 {
208 if (obj == null)
209 {
210 return false;
211 }
212 if (obj == this)
213 {
214 return true;
215 }
216 if (obj.getClass() != getClass())
217 {
218 return false;
219 }
220 final Plugin plugin = (Plugin) obj;
221 return new EqualsBuilder().append(key, plugin.key).append(version, plugin.version).isEquals();
222 }
223 }
224
225 public static class StatusResponseBuilder
226 {
227 private final CacheControl cacheControl;
228 private final Response.Status status;
229 private String eTag;
230 private Plugin plugin;
231 private String message;
232 private List<Link> created;
233 private List<Link> updated;
234
235 private StatusResponseBuilder(Response.Status status)
236 {
237 this(status, new CacheControl());
238 }
239
240 private StatusResponseBuilder(Response.Status status, CacheControl cacheControl)
241 {
242 this.status = Preconditions.checkNotNull(status);
243 this.cacheControl = Preconditions.checkNotNull(cacheControl);
244 }
245
246 public StatusResponseBuilder plugin(String key, String version)
247 {
248 plugin = new Plugin(key, version);
249 return this;
250 }
251
252 public StatusResponseBuilder message(String message)
253 {
254 this.message = message;
255 return this;
256 }
257
258 public StatusResponseBuilder tag(String eTag)
259 {
260 this.eTag = eTag;
261 return this;
262 }
263
264 public StatusResponseBuilder noCache()
265 {
266 cacheControl.setNoCache(true);
267 return this;
268 }
269
270 public StatusResponseBuilder noStore()
271 {
272 cacheControl.setNoStore(true);
273 return this;
274 }
275
276 public Status build()
277 {
278 return new Status(plugin, status.getStatusCode(), null, message, eTag, created, updated);
279 }
280
281 public Response response()
282 {
283 return responseBuilder().build();
284 }
285
286 public Response.ResponseBuilder responseBuilder()
287 {
288 final Response.ResponseBuilder builder =
289 Response.status(status).cacheControl(cacheControl).tag(eTag).entity(build()).type(APPLICATION_XML);
290
291 final List<Link> c = getCreated();
292 final List<Link> u = getUpdated();
293 if (c.size() == 1 && u.isEmpty())
294 {
295 builder.location(c.get(0).getHref());
296 }
297 else if (u.size() == 1 && c.isEmpty())
298 {
299 builder.location(u.get(0).getHref());
300 }
301 return builder;
302 }
303
304 public StatusResponseBuilder created(final Link link)
305 {
306 getCreated().add(link);
307 return this;
308 }
309
310 public StatusResponseBuilder updated(final Link link)
311 {
312 getUpdated().add(link);
313 return this;
314 }
315
316 private List<Link> getCreated()
317 {
318 if (created == null)
319 {
320 created = Lists.newLinkedList();
321 }
322 return created;
323 }
324
325 private List<Link> getUpdated()
326 {
327 if (updated == null)
328 {
329 updated = Lists.newLinkedList();
330 }
331 return updated;
332 }
333 }
334 }