Line data Source code
1 : // Copyright (C) 2012 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.extensions.restapi; 16 : 17 : import java.util.concurrent.TimeUnit; 18 : 19 : /** Special return value to mean specific HTTP status codes in a REST API. */ 20 149 : public abstract class Response<T> { 21 : @SuppressWarnings({"rawtypes"}) 22 149 : private static final Response NONE = new None(); 23 : 24 : /** HTTP 200 OK: pointless wrapper for type safety. */ 25 : public static <T> Response<T> ok(T value) { 26 123 : return new Impl<>(200, value); 27 : } 28 : 29 : /** HTTP 200 OK: with empty value. */ 30 : public static Response<String> ok() { 31 13 : return ok(""); 32 : } 33 : 34 : /** HTTP 200 OK: with forced revalidation of cache. */ 35 : public static <T> Response<T> withMustRevalidate(T value) { 36 68 : return ok(value).caching(CacheControl.PRIVATE(0, TimeUnit.SECONDS).setMustRevalidate()); 37 : } 38 : 39 : /** HTTP 201 Created: typically used when a new resource is made. */ 40 : public static <T> Response<T> created(T value) { 41 149 : return new Impl<>(201, value); 42 : } 43 : 44 : /** HTTP 201 Created: with empty value. */ 45 : public static Response<String> created() { 46 18 : return created(""); 47 : } 48 : 49 : /** HTTP 202 Accepted: accepted as background task. */ 50 : public static Accepted accepted(String location) { 51 3 : return new Accepted(location); 52 : } 53 : 54 : /** HTTP 204 No Content: typically used when the resource is deleted. */ 55 : @SuppressWarnings("unchecked") 56 : public static <T> Response<T> none() { 57 72 : return NONE; 58 : } 59 : 60 : /** HTTP 302 Found: temporary redirect to another URL. */ 61 : public static Redirect redirect(String location) { 62 0 : return new Redirect(location); 63 : } 64 : 65 : /** Arbitrary status code with wrapped result. */ 66 : public static <T> Response<T> withStatusCode(int statusCode, T value) { 67 2 : return new Impl<>(statusCode, value); 68 : } 69 : 70 : @SuppressWarnings({"unchecked", "rawtypes"}) 71 : public static <T> T unwrap(T obj) { 72 24 : while (obj instanceof Response) { 73 24 : obj = (T) ((Response) obj).value(); 74 : } 75 24 : return obj; 76 : } 77 : 78 : public abstract boolean isNone(); 79 : 80 : public abstract int statusCode(); 81 : 82 : public abstract T value(); 83 : 84 : public abstract CacheControl caching(); 85 : 86 : public abstract Response<T> caching(CacheControl c); 87 : 88 : @Override 89 : public abstract String toString(); 90 : 91 : private static final class Impl<T> extends Response<T> { 92 : private final int statusCode; 93 : private final T value; 94 149 : private CacheControl caching = CacheControl.NONE; 95 : 96 149 : private Impl(int sc, T val) { 97 149 : statusCode = sc; 98 149 : value = val; 99 149 : } 100 : 101 : @Override 102 : public boolean isNone() { 103 13 : return false; 104 : } 105 : 106 : @Override 107 : public int statusCode() { 108 26 : return statusCode; 109 : } 110 : 111 : @Override 112 : public T value() { 113 126 : return value; 114 : } 115 : 116 : @Override 117 : public CacheControl caching() { 118 24 : return caching; 119 : } 120 : 121 : @Override 122 : public Response<T> caching(CacheControl c) { 123 71 : caching = c; 124 71 : return this; 125 : } 126 : 127 : @Override 128 : public String toString() { 129 0 : return "[" + statusCode() + "] " + value(); 130 : } 131 : } 132 : 133 : private static final class None extends Response<Object> { 134 : private None() {} 135 : 136 : @Override 137 : public boolean isNone() { 138 6 : return true; 139 : } 140 : 141 : @Override 142 : public int statusCode() { 143 12 : return 204; 144 : } 145 : 146 : @Override 147 : public Object value() { 148 0 : throw new UnsupportedOperationException(); 149 : } 150 : 151 : @Override 152 : public CacheControl caching() { 153 10 : return CacheControl.NONE; 154 : } 155 : 156 : @Override 157 : public Response<Object> caching(CacheControl c) { 158 0 : throw new UnsupportedOperationException(); 159 : } 160 : 161 : @Override 162 : public String toString() { 163 0 : return "[204 No Content] None"; 164 : } 165 : } 166 : 167 : /** An HTTP redirect to another location. */ 168 : public static final class Redirect extends Response<Object> { 169 : private final String location; 170 : 171 0 : private Redirect(String url) { 172 0 : this.location = url; 173 0 : } 174 : 175 : @Override 176 : public boolean isNone() { 177 0 : return false; 178 : } 179 : 180 : @Override 181 : public int statusCode() { 182 0 : return 302; 183 : } 184 : 185 : @Override 186 : public Object value() { 187 0 : throw new UnsupportedOperationException(); 188 : } 189 : 190 : @Override 191 : public CacheControl caching() { 192 0 : return CacheControl.NONE; 193 : } 194 : 195 : @Override 196 : public Response<Object> caching(CacheControl c) { 197 0 : throw new UnsupportedOperationException(); 198 : } 199 : 200 : public String location() { 201 0 : return location; 202 : } 203 : 204 : @Override 205 : public int hashCode() { 206 0 : return location.hashCode(); 207 : } 208 : 209 : @Override 210 : public boolean equals(Object o) { 211 0 : return o instanceof Redirect && ((Redirect) o).location.equals(location); 212 : } 213 : 214 : @Override 215 : public String toString() { 216 0 : return String.format("[302 Redirect] %s", location); 217 : } 218 : } 219 : 220 : /** Accepted as task for asynchronous execution. */ 221 : public static final class Accepted extends Response<Object> { 222 : private final String location; 223 : 224 3 : private Accepted(String url) { 225 3 : this.location = url; 226 3 : } 227 : 228 : @Override 229 : public boolean isNone() { 230 0 : return false; 231 : } 232 : 233 : @Override 234 : public int statusCode() { 235 1 : return 202; 236 : } 237 : 238 : @Override 239 : public Object value() { 240 0 : throw new UnsupportedOperationException(); 241 : } 242 : 243 : @Override 244 : public CacheControl caching() { 245 0 : return CacheControl.NONE; 246 : } 247 : 248 : @Override 249 : public Response<Object> caching(CacheControl c) { 250 0 : throw new UnsupportedOperationException(); 251 : } 252 : 253 : public String location() { 254 1 : return location; 255 : } 256 : 257 : @Override 258 : public int hashCode() { 259 0 : return location.hashCode(); 260 : } 261 : 262 : @Override 263 : public boolean equals(Object o) { 264 0 : return o instanceof Accepted && ((Accepted) o).location.equals(location); 265 : } 266 : 267 : @Override 268 : public String toString() { 269 0 : return String.format("[202 Accepted] %s", location); 270 : } 271 : } 272 : }