Defined an interface RestResource that all resources need to extend from. Defined an Id class for a resource.
Changed a rest body spec to take a type instead of a class. This allows parameterized resource types. Defined a repository interface with an in-memory implementation for server-side storage of rest resource instances.
This commit is contained in:
parent
6825477d75
commit
5adfa4bc04
@ -27,6 +27,7 @@ import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.webservice.definition.WebServiceSystemException;
|
||||
import com.google.gson.webservice.definition.rest.RestCallSpec;
|
||||
import com.google.gson.webservice.definition.rest.RestRequest;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
import com.google.gson.webservice.definition.rest.RestResponse;
|
||||
|
||||
/**
|
||||
@ -49,7 +50,7 @@ public class RestClient {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
private URL getWebServiceUrl(RestCallSpec<?> callSpec) {
|
||||
private URL getWebServiceUrl(RestCallSpec callSpec) {
|
||||
String url = config.getServiceBaseUrl() + callSpec.getPath().get();
|
||||
try {
|
||||
return new URL(url);
|
||||
@ -58,13 +59,14 @@ public class RestClient {
|
||||
}
|
||||
}
|
||||
|
||||
public <R> RestResponse<R> getResponse(RestCallSpec<R> callSpec, RestRequest<R> request) {
|
||||
public <R extends RestResource<R>> RestResponse<R> getResponse(
|
||||
RestCallSpec callSpec, RestRequest<R> request) {
|
||||
Gson gson = new GsonBuilder().create();
|
||||
return getResponse(callSpec, request, gson);
|
||||
}
|
||||
|
||||
public <R> RestResponse<R> getResponse(
|
||||
RestCallSpec<R> callSpec, RestRequest<R> request, Gson gson) {
|
||||
public <R extends RestResource<R>> RestResponse<R> getResponse(
|
||||
RestCallSpec callSpec, RestRequest<R> request, Gson gson) {
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
URL webServiceUrl = getWebServiceUrl(callSpec);
|
||||
@ -84,8 +86,8 @@ public class RestClient {
|
||||
* Use this method if you want to mange the HTTP Connection yourself. This is useful when you
|
||||
* want to use HTTP pipelining.
|
||||
*/
|
||||
public <R> RestResponse<R> getResponse(
|
||||
RestCallSpec<R> callSpec, RestRequest<R> request, Gson gson, HttpURLConnection conn) {
|
||||
public <R extends RestResource<R>> RestResponse<R> getResponse(
|
||||
RestCallSpec callSpec, RestRequest<R> request, Gson gson, HttpURLConnection conn) {
|
||||
try {
|
||||
if (logger != null) {
|
||||
URL webServiceUrl = getWebServiceUrl(callSpec);
|
||||
|
@ -27,6 +27,7 @@ import com.google.gson.webservice.definition.HeaderMap;
|
||||
import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
import com.google.gson.webservice.definition.WebServiceSystemException;
|
||||
import com.google.gson.webservice.definition.rest.RestRequest;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
|
||||
/**
|
||||
* Class to send Web service requests on a {@link HttpURLConnection}.
|
||||
@ -48,7 +49,7 @@ public final class RestRequestSender {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
public <R> void send(HttpURLConnection conn, RestRequest<R> request) {
|
||||
public <R extends RestResource<R>> void send(HttpURLConnection conn, RestRequest<R> request) {
|
||||
try {
|
||||
conn.setRequestMethod(request.getHttpMethod().toString());
|
||||
setHeader(conn, "Content-Type", request.getContentType(), true);
|
||||
@ -63,7 +64,7 @@ public final class RestRequestSender {
|
||||
// Android Java VM ignore Content-Length if setDoOutput is not set
|
||||
conn.setDoOutput(true);
|
||||
if (requestBody != null) {
|
||||
requestBodyContents = gson.toJson(requestBody);
|
||||
requestBodyContents = gson.toJson(requestBody, request.getSpec().getResourceType());
|
||||
}
|
||||
String contentLength = String.valueOf(requestBodyContents.length());
|
||||
setHeader(conn, "Content-Length", contentLength, true);
|
||||
|
@ -30,6 +30,7 @@ import com.google.gson.webservice.definition.ContentBodySpec;
|
||||
import com.google.gson.webservice.definition.HeaderMap;
|
||||
import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
import com.google.gson.webservice.definition.WebServiceSystemException;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
import com.google.gson.webservice.definition.rest.RestResponse;
|
||||
import com.google.gson.webservice.definition.rest.RestResponseSpec;
|
||||
|
||||
@ -38,16 +39,16 @@ import com.google.gson.webservice.definition.rest.RestResponseSpec;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestResponseReceiver<R> {
|
||||
public final class RestResponseReceiver<R extends RestResource<R>> {
|
||||
private final Gson gson;
|
||||
private final RestResponseSpec<R> spec;
|
||||
private final RestResponseSpec spec;
|
||||
private final Logger logger;
|
||||
private final Level logLevel;
|
||||
|
||||
public RestResponseReceiver(Gson gson, RestResponseSpec<R> spec) {
|
||||
public RestResponseReceiver(Gson gson, RestResponseSpec spec) {
|
||||
this(gson, spec, null);
|
||||
}
|
||||
public RestResponseReceiver(Gson gson, RestResponseSpec<R> spec, Level logLevel) {
|
||||
public RestResponseReceiver(Gson gson, RestResponseSpec spec, Level logLevel) {
|
||||
this.gson = gson;
|
||||
this.spec = spec;
|
||||
this.logger = logLevel == null ? null : Logger.getLogger(RestResponseReceiver.class.getName());
|
||||
@ -57,11 +58,11 @@ public final class RestResponseReceiver<R> {
|
||||
public RestResponse<R> receive(HttpURLConnection conn) {
|
||||
try {
|
||||
HeaderMapSpec paramSpec = spec.getHeadersSpec();
|
||||
Class<R> bodySpec = spec.getResourceClass();
|
||||
Type bodyType = spec.getResourceType();
|
||||
// read response
|
||||
HeaderMap responseParams = readResponseHeaders(conn, paramSpec);
|
||||
R responseBody = readResponseBody(conn, bodySpec);
|
||||
return new RestResponse<R>(responseParams, responseBody);
|
||||
R responseBody = readResponseBody(conn, bodyType);
|
||||
return new RestResponse<R>(responseParams, responseBody, bodyType);
|
||||
} catch (IOException e) {
|
||||
throw new WebServiceSystemException(e);
|
||||
}
|
||||
@ -84,11 +85,13 @@ public final class RestResponseReceiver<R> {
|
||||
return paramsBuilder.build();
|
||||
}
|
||||
|
||||
private R readResponseBody(HttpURLConnection conn, Class<R> resourceClass) throws IOException {
|
||||
@SuppressWarnings("unchecked")
|
||||
private R readResponseBody(
|
||||
HttpURLConnection conn, Type resourceType) throws IOException {
|
||||
String connContentType = conn.getContentType();
|
||||
Preconditions.checkArgument(connContentType.contains(ContentBodySpec.JSON_CONTENT_TYPE), conn);
|
||||
Reader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
R body = gson.fromJson(reader, resourceClass);
|
||||
R body = (R) gson.fromJson(reader, resourceType);
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
/**
|
||||
* An interface to indicate that an object has an Id
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <T> type of object
|
||||
*/
|
||||
public interface HasId<R> {
|
||||
public Id<R> getId();
|
||||
public void setId(Id<R> id);
|
||||
public boolean hasId();
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* An id for a rest resource
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <R> type variable for the rest resource
|
||||
*/
|
||||
public final class Id<R> {
|
||||
private final long value;
|
||||
private final Type typeOfId;
|
||||
|
||||
private Id(long value, Type typeOfId) {
|
||||
this.value = value;
|
||||
this.typeOfId = typeOfId;
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Type getTypeOfId() {
|
||||
return typeOfId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((typeOfId == null) ? 0 : typeOfId.hashCode());
|
||||
result = prime * result + (int)(value ^ (value >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
@SuppressWarnings("unchecked")
|
||||
Id<R> other = (Id<R>)obj;
|
||||
if (typeOfId == null) {
|
||||
if (other.typeOfId != null) return false;
|
||||
} else if (!typeOfId.equals(other.typeOfId)) return false;
|
||||
if (value != other.value) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static <RS> Id<RS> get(long value, Type typeOfId) {
|
||||
return new Id<RS>(value, typeOfId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{value:%s,type:%s}", value, typeOfId);
|
||||
}
|
||||
}
|
@ -28,10 +28,11 @@ import com.google.gson.webservice.definition.CallPath;
|
||||
public final class ResourceMap {
|
||||
|
||||
public static final class Builder {
|
||||
private final Map<CallPath, RestCallSpec<?>> resources =
|
||||
new HashMap<CallPath, RestCallSpec<?>>();
|
||||
private final Map<CallPath, RestCallSpec> resources =
|
||||
new HashMap<CallPath, RestCallSpec>();
|
||||
|
||||
public <R> Builder set(CallPath callPath, RestCallSpec<R> spec) {
|
||||
public Builder set(CallPath callPath, RestCallSpec spec) {
|
||||
Preconditions.checkArgument(resources.get(callPath) == null);
|
||||
resources.put(callPath, spec);
|
||||
return this;
|
||||
}
|
||||
@ -41,15 +42,13 @@ public final class ResourceMap {
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<CallPath, RestCallSpec<?>> resources;
|
||||
private final Map<CallPath, RestCallSpec> resources;
|
||||
|
||||
public ResourceMap(Map<CallPath, RestCallSpec<?>> resources) {
|
||||
public ResourceMap(Map<CallPath, RestCallSpec> resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
public <T> RestCallSpec<T> get(CallPath callPath) {
|
||||
@SuppressWarnings("unchecked")
|
||||
RestCallSpec<T> restCallSpec = (RestCallSpec<T>)resources.get(callPath);
|
||||
return restCallSpec;
|
||||
public RestCallSpec get(CallPath callPath) {
|
||||
return (RestCallSpec)resources.get(callPath);
|
||||
}
|
||||
}
|
||||
|
@ -21,19 +21,19 @@ package com.google.gson.webservice.definition.rest;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestCall<R> {
|
||||
public final class RestCall<R extends RestResource<R>> {
|
||||
|
||||
private final RestCallSpec<R> callSpec;
|
||||
private final RestCallSpec callSpec;
|
||||
private final RestRequest<R> request;
|
||||
private final RestResponse<R> response;
|
||||
|
||||
public RestCall(RestCallSpec<R> callSpec, RestRequest<R> request, RestResponse<R> response) {
|
||||
public RestCall(RestCallSpec callSpec, RestRequest<R> request, RestResponse<R> response) {
|
||||
this.callSpec = callSpec;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public RestCallSpec<R> getSpec() {
|
||||
public RestCallSpec getSpec() {
|
||||
return callSpec;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
@ -29,61 +30,64 @@ import com.google.gson.webservice.definition.TypedKey;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestCallSpec<R> {
|
||||
public static class Builder<R> {
|
||||
public final class RestCallSpec {
|
||||
public static class Builder {
|
||||
private final CallPath callPath;
|
||||
private final Set<HttpMethod> supportedHttpMethods = new LinkedHashSet<HttpMethod>();
|
||||
private final HeaderMapSpec.Builder reqParamsSpecBuilder = new HeaderMapSpec.Builder();
|
||||
private final HeaderMapSpec.Builder resParamsSpecBuilder = new HeaderMapSpec.Builder();
|
||||
private final Class<R> resourceClass;
|
||||
private final Type resourceType;
|
||||
|
||||
public Builder(CallPath callPath, Class<R> resourceClass) {
|
||||
public Builder(CallPath callPath, Type resourceType) {
|
||||
this.callPath = callPath;
|
||||
supportedHttpMethods.addAll(HttpMethod.ALL_METHODS);
|
||||
this.resourceClass = resourceClass;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public Builder<R> disableHttpMethod(HttpMethod httpMethod) {
|
||||
public Builder disableHttpMethod(HttpMethod httpMethod) {
|
||||
supportedHttpMethods.remove(httpMethod);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder<R> addRequestParam(TypedKey<T> param) {
|
||||
public <T> Builder addRequestParam(TypedKey<T> param) {
|
||||
reqParamsSpecBuilder.put(param.getName(), param.getClassOfT());
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder<R> addResponseParam(TypedKey<T> param) {
|
||||
public <T> Builder addResponseParam(TypedKey<T> param) {
|
||||
resParamsSpecBuilder.put(param.getName(), param.getClassOfT());
|
||||
return this;
|
||||
}
|
||||
|
||||
public RestCallSpec<R> build() {
|
||||
public RestCallSpec build() {
|
||||
if (supportedHttpMethods.isEmpty()) {
|
||||
supportedHttpMethods.addAll(Arrays.asList(HttpMethod.values()));
|
||||
}
|
||||
RestRequestSpec<R> requestSpec =
|
||||
new RestRequestSpec<R>(reqParamsSpecBuilder.build(), resourceClass);
|
||||
RestResponseSpec<R> responseSpec =
|
||||
new RestResponseSpec<R>(resParamsSpecBuilder.build(), resourceClass);
|
||||
return new RestCallSpec<R>(supportedHttpMethods, callPath,
|
||||
requestSpec, responseSpec);
|
||||
RestRequestSpec requestSpec =
|
||||
new RestRequestSpec(reqParamsSpecBuilder.build(), resourceType);
|
||||
RestResponseSpec responseSpec =
|
||||
new RestResponseSpec(resParamsSpecBuilder.build(), resourceType);
|
||||
return new RestCallSpec(supportedHttpMethods, callPath,
|
||||
requestSpec, responseSpec, resourceType);
|
||||
}
|
||||
}
|
||||
|
||||
private final Set<HttpMethod> supportedHttpMethods;
|
||||
private final CallPath path;
|
||||
private final RestRequestSpec<R> requestSpec;
|
||||
private final RestResponseSpec<R> responseSpec;
|
||||
private final RestRequestSpec requestSpec;
|
||||
private final RestResponseSpec responseSpec;
|
||||
private final Type resourceType;
|
||||
|
||||
private RestCallSpec(Set<HttpMethod> supportedHttpMethods, CallPath path,
|
||||
RestRequestSpec<R> requestSpec, RestResponseSpec<R> responseSpec) {
|
||||
RestRequestSpec requestSpec, RestResponseSpec responseSpec,
|
||||
Type resourceType) {
|
||||
Preconditions.checkArgument(!supportedHttpMethods.isEmpty());
|
||||
Preconditions.checkNotNull(path);
|
||||
this.supportedHttpMethods = supportedHttpMethods;
|
||||
this.path = path;
|
||||
this.requestSpec = requestSpec;
|
||||
this.responseSpec = responseSpec;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public CallPath getPath() {
|
||||
@ -94,11 +98,15 @@ public final class RestCallSpec<R> {
|
||||
return supportedHttpMethods;
|
||||
}
|
||||
|
||||
public RestResponseSpec<R> getResponseSpec() {
|
||||
public RestResponseSpec getResponseSpec() {
|
||||
return responseSpec;
|
||||
}
|
||||
|
||||
public RestRequestSpec<R> getRequestSpec() {
|
||||
public RestRequestSpec getRequestSpec() {
|
||||
return requestSpec;
|
||||
}
|
||||
|
||||
public Type getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.webservice.definition.ContentBodySpec;
|
||||
import com.google.gson.webservice.definition.HeaderMap;
|
||||
import com.google.gson.webservice.definition.HttpMethod;
|
||||
@ -27,25 +29,29 @@ import com.google.gson.webservice.definition.TypedKey;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestRequest<R> {
|
||||
public final class RestRequest<R extends RestResource<R>> {
|
||||
private final HttpMethod method;
|
||||
private final HeaderMap headers;
|
||||
private final R body;
|
||||
private final RestRequestSpec<R> spec;
|
||||
private final RestRequestSpec spec;
|
||||
|
||||
public RestRequest(HttpMethod method, HeaderMap requestHeaders,
|
||||
R requestBody, Class<R> resourceClass) {
|
||||
R requestBody, Type resourceType) {
|
||||
this.method = method;
|
||||
this.body = requestBody;
|
||||
this.headers = requestHeaders;
|
||||
this.spec = new RestRequestSpec<R>(requestHeaders.getSpec(), resourceClass);
|
||||
this.spec = new RestRequestSpec(requestHeaders.getSpec(), resourceType);
|
||||
}
|
||||
|
||||
public Id<R> getId() {
|
||||
return body.getId();
|
||||
}
|
||||
|
||||
public HttpMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public RestRequestSpec<R> getSpec() {
|
||||
public RestRequestSpec getSpec() {
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
|
||||
/**
|
||||
@ -22,17 +24,17 @@ import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestRequestSpec<R> {
|
||||
public final class RestRequestSpec {
|
||||
private final HeaderMapSpec headersSpec;
|
||||
private final Class<R> resourceClass;
|
||||
private final Type resourceType;
|
||||
|
||||
public RestRequestSpec(HeaderMapSpec headersSpec, Class<R> resourceClass) {
|
||||
public RestRequestSpec(HeaderMapSpec headersSpec, Type resourceClass) {
|
||||
this.headersSpec = headersSpec;
|
||||
this.resourceClass = resourceClass;
|
||||
this.resourceType = resourceClass;
|
||||
}
|
||||
|
||||
public Class<R> getResourceClass() {
|
||||
return resourceClass;
|
||||
public Type getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public HeaderMapSpec getHeadersSpec() {
|
||||
@ -41,6 +43,6 @@ public final class RestRequestSpec<R> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{headersSpec:%s,resourceClass:%s}", headersSpec, resourceClass);
|
||||
return String.format("{headersSpec:%s,resourceType:%s}", headersSpec, resourceType);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
/**
|
||||
* An interface implemented by an object that is intended to be a rest resource
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <R> the rest resource type
|
||||
*/
|
||||
public interface RestResource<R> extends HasId<R> {
|
||||
|
||||
}
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.webservice.definition.HeaderMap;
|
||||
import com.google.gson.webservice.definition.TypedKey;
|
||||
|
||||
@ -24,52 +26,50 @@ import com.google.gson.webservice.definition.TypedKey;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestResponse<R> {
|
||||
public final class RestResponse<R extends RestResource<R>> {
|
||||
|
||||
private final HeaderMap headers;
|
||||
private final R body;
|
||||
private final RestResponseSpec<R> spec;
|
||||
private final RestResponseSpec spec;
|
||||
|
||||
public static class Builder<R> {
|
||||
public static class Builder<RS extends RestResource<RS>> {
|
||||
private final HeaderMap.Builder headers;
|
||||
private R body;
|
||||
private final RestResponseSpec<R> spec;
|
||||
private RS body;
|
||||
private final RestResponseSpec spec;
|
||||
|
||||
public Builder(RestResponseSpec<R> spec) {
|
||||
public Builder(RestResponseSpec spec) {
|
||||
this.spec = spec;
|
||||
headers = new HeaderMap.Builder(spec.getHeadersSpec());
|
||||
}
|
||||
|
||||
public <T> Builder<R> putHeader(TypedKey<T> paramName, T content) {
|
||||
public <T> Builder<RS> putHeader(TypedKey<T> paramName, T content) {
|
||||
headers.put(paramName.getName(), content, paramName.getClassOfT());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<R> setBody(R body) {
|
||||
public Builder<RS> setBody(RS body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RestResponse<R> build() {
|
||||
return new RestResponse<R>(spec, headers.build(), body);
|
||||
public RestResponse<RS> build() {
|
||||
return new RestResponse<RS>(spec, headers.build(), body);
|
||||
}
|
||||
}
|
||||
|
||||
private RestResponse(RestResponseSpec<R> spec, HeaderMap headers, R body) {
|
||||
private RestResponse(RestResponseSpec spec, HeaderMap headers, R body) {
|
||||
this.spec = spec;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public RestResponse(HeaderMap responseHeaders, R responseBody) {
|
||||
this.spec = new RestResponseSpec<R>(responseHeaders.getSpec(),
|
||||
(Class<R>)responseBody.getClass());
|
||||
public RestResponse(HeaderMap responseHeaders, R responseBody, Type responseBodyType) {
|
||||
this.spec = new RestResponseSpec(responseHeaders.getSpec(), responseBodyType);
|
||||
this.headers = responseHeaders;
|
||||
this.body = responseBody;
|
||||
}
|
||||
|
||||
public RestResponseSpec<R> getSpec() {
|
||||
public RestResponseSpec getSpec() {
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.gson.webservice.definition.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
|
||||
/**
|
||||
@ -22,17 +24,17 @@ import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestResponseSpec<R> {
|
||||
public final class RestResponseSpec {
|
||||
private final HeaderMapSpec headersSpec;
|
||||
private final Class<R> resourceClass;
|
||||
private final Type resourceType;
|
||||
|
||||
public RestResponseSpec(HeaderMapSpec headersSpec, Class<R> resourceClass) {
|
||||
public RestResponseSpec(HeaderMapSpec headersSpec, Type resourceType) {
|
||||
this.headersSpec = headersSpec;
|
||||
this.resourceClass = resourceClass;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public Class<R> getResourceClass() {
|
||||
return resourceClass;
|
||||
public Type getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public HeaderMapSpec getHeadersSpec() {
|
||||
@ -41,6 +43,6 @@ public final class RestResponseSpec<R> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{headersSpec:%s,resourceClass:%s}", headersSpec, resourceClass);
|
||||
return String.format("{headersSpec:%s,resourceType:%s}", headersSpec, resourceType);
|
||||
}
|
||||
}
|
||||
|
@ -69,12 +69,6 @@
|
||||
<version>0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>wsclient</artifactId>
|
||||
<version>0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Guice: Dependency injection -->
|
||||
<dependency>
|
||||
|
77
wsf/src/main/java/com/google/gson/wsf/server/rest/IdMap.java
Normal file
77
wsf/src/main/java/com/google/gson/wsf/server/rest/IdMap.java
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.wsf.server.rest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gson.webservice.definition.rest.HasId;
|
||||
import com.google.gson.webservice.definition.rest.Id;
|
||||
|
||||
/**
|
||||
* This class provides a type-safe map to access values associated with Ids
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <T> the type of the objects being kept in the map
|
||||
*/
|
||||
public class IdMap<T extends HasId<T>> {
|
||||
public static final Logger LOG = Logger.getLogger(IdMap.class.getName());
|
||||
protected final Map<Id<T>, T> map;
|
||||
private volatile long nextAvailableId;
|
||||
private final Type typeOfId;
|
||||
|
||||
/**
|
||||
* Use {@link #create(Class)} instead of constructor
|
||||
*/
|
||||
protected IdMap(Type typeOfId) {
|
||||
this.typeOfId = typeOfId;
|
||||
map = new ConcurrentHashMap<Id<T>, T>();
|
||||
nextAvailableId = 0;
|
||||
}
|
||||
|
||||
public T get(Id<T> id) {
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
public T put(T obj) {
|
||||
map.put(obj.getId(), obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public void delete(Id<T> id) {
|
||||
T removed = map.remove(id);
|
||||
if (removed == null) {
|
||||
LOG.log(Level.WARNING, "Attempted to delete non-existent id: {0}", id);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exists(Id<T> id) {
|
||||
return map.containsKey(id);
|
||||
}
|
||||
|
||||
public synchronized Id<T> getNextId() {
|
||||
long id = nextAvailableId++;
|
||||
return Id.get(id, typeOfId);
|
||||
}
|
||||
|
||||
public static <S extends HasId<S>> IdMap<S> create(Type typeOfId) {
|
||||
return new IdMap<S>(typeOfId);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.wsf.server.rest;
|
||||
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
|
||||
/**
|
||||
* Metadata associated with a repository for a rest resource
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <R> The resource
|
||||
*/
|
||||
public final class MetaData<R extends RestResource<R>> {
|
||||
|
||||
final boolean freshlyAssignedId;
|
||||
|
||||
public MetaData(boolean freshlyAssignedId) {
|
||||
this.freshlyAssignedId = freshlyAssignedId;
|
||||
}
|
||||
|
||||
public boolean isFreshlyAssignedId() {
|
||||
return freshlyAssignedId;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.wsf.server.rest;
|
||||
|
||||
import com.google.gson.webservice.definition.rest.HasId;
|
||||
import com.google.gson.webservice.definition.rest.Id;
|
||||
|
||||
/**
|
||||
* An interface for a repository of rest resources. Meant for abstracting the server-side
|
||||
* storage of rest resources.
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <R> the type of rest resource
|
||||
*/
|
||||
public interface Repository<R extends HasId<R>> {
|
||||
public R get(Id<R> resourceId);
|
||||
|
||||
/**
|
||||
* if resource.getId() == null, inserts the resource after assigning it a new id.
|
||||
* Otherwise, updates the resource ensuring that it pre-exists.
|
||||
*/
|
||||
public R put(R resource);
|
||||
|
||||
public void delete(Id<R> resourceId);
|
||||
|
||||
public boolean exists(Id<R> resourceId);
|
||||
|
||||
/**
|
||||
* Ensures that the specified resource has a valid id that will be used when it is saved
|
||||
*/
|
||||
public Id<R> assignId(R resource);
|
||||
|
||||
public Id<R> getNextId();
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.wsf.server.rest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.webservice.definition.rest.Id;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
import com.google.inject.internal.Maps;
|
||||
import com.google.inject.internal.Preconditions;
|
||||
|
||||
/**
|
||||
* An in-memory map of rest resources
|
||||
*
|
||||
* @author inder
|
||||
*
|
||||
* @param <R> Type variable for the resource
|
||||
*/
|
||||
public class RepositoryInMemory<R extends RestResource<R>> implements Repository<R> {
|
||||
private final IdMap<R> resources;
|
||||
private final Map<Id<R>, MetaData<R>> metaDataMap;
|
||||
|
||||
public RepositoryInMemory(Class<? super R> classOfResource) {
|
||||
this.resources = IdMap.create(classOfResource);
|
||||
this.metaDataMap = Maps.newHashMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R get(Id<R> resourceId) {
|
||||
return resources.get(resourceId);
|
||||
}
|
||||
|
||||
public boolean isFreshlyAssignedId(Id<R> resourceId) {
|
||||
MetaData<R> metaData = metaDataMap.get(resourceId);
|
||||
if (metaData == null) {
|
||||
return false;
|
||||
}
|
||||
return metaData.isFreshlyAssignedId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R put(R resource) {
|
||||
if (!resource.hasId()) {
|
||||
// insert semantics
|
||||
assignId(resource);
|
||||
} else {
|
||||
Id<R> id = resource.getId();
|
||||
if (!isFreshlyAssignedId(id)) {
|
||||
// update semantics
|
||||
Preconditions.checkState(resources.exists(resource.getId()));
|
||||
}
|
||||
}
|
||||
resource = resources.put(resource);
|
||||
metaDataMap.remove(resource.getId());
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Id<R> resourceId) {
|
||||
resources.delete(resourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Id<R> resourceId) {
|
||||
return resources.exists(resourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id<R> getNextId() {
|
||||
return resources.getNextId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id<R> assignId(R resource) {
|
||||
if (resource.getId() == null) {
|
||||
Id<R> id = resources.getNextId();
|
||||
resource.setId(id);
|
||||
metaDataMap.put(id, new MetaData<R>(true));
|
||||
}
|
||||
return resource.getId();
|
||||
}
|
||||
}
|
@ -32,18 +32,19 @@ import com.google.gson.webservice.definition.HttpMethod;
|
||||
import com.google.gson.webservice.definition.WebServiceSystemException;
|
||||
import com.google.gson.webservice.definition.rest.RestRequest;
|
||||
import com.google.gson.webservice.definition.rest.RestRequestSpec;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
|
||||
/**
|
||||
* Receives and parses a request at the server side on a {@link HttpServletRequest}.
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestRequestReceiver<R> {
|
||||
public final class RestRequestReceiver<R extends RestResource<R>> {
|
||||
|
||||
private final Gson gson;
|
||||
private final RestRequestSpec<R> spec;
|
||||
private final RestRequestSpec spec;
|
||||
|
||||
public RestRequestReceiver(Gson gson, RestRequestSpec<R> spec) {
|
||||
public RestRequestReceiver(Gson gson, RestRequestSpec spec) {
|
||||
this.gson = gson;
|
||||
this.spec = spec;
|
||||
}
|
||||
@ -54,7 +55,7 @@ public final class RestRequestReceiver<R> {
|
||||
R requestBody = buildRequestBody(request);
|
||||
|
||||
HttpMethod method = HttpMethod.getMethod(request.getMethod());
|
||||
return new RestRequest<R>(method, requestParams, requestBody, spec.getResourceClass());
|
||||
return new RestRequest<R>(method, requestParams, requestBody, spec.getResourceType());
|
||||
} catch (IOException e) {
|
||||
throw new WebServiceSystemException(e);
|
||||
} catch (JsonParseException e) {
|
||||
@ -83,9 +84,8 @@ public final class RestRequestReceiver<R> {
|
||||
}
|
||||
|
||||
private R buildRequestBody(HttpServletRequest request) throws IOException {
|
||||
Class<R> resourceClass = spec.getResourceClass();
|
||||
Reader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
|
||||
R requestBody = gson.fromJson(reader, resourceClass);
|
||||
R requestBody = gson.fromJson(reader, spec.getResourceType());
|
||||
return requestBody;
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,54 @@
|
||||
*/
|
||||
package com.google.gson.wsf.server.rest;
|
||||
|
||||
import com.google.gson.webservice.definition.rest.RestRequest;
|
||||
import com.google.gson.webservice.definition.rest.RestResponse;
|
||||
import com.google.gson.webservice.definition.HttpMethod;
|
||||
import com.google.gson.webservice.definition.rest.Id;
|
||||
import com.google.gson.webservice.definition.rest.RestCallSpec;
|
||||
import com.google.gson.webservice.definition.rest.RestRequest;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
import com.google.gson.webservice.definition.rest.RestResponse;
|
||||
|
||||
public interface RestResponseBuilder<R> {
|
||||
public void buildResponse(RestCallSpec<R> callSpec, RestRequest<R> request,
|
||||
RestResponse.Builder<R> responseBuilder);
|
||||
public abstract class RestResponseBuilder<R extends RestResource<R>> {
|
||||
protected final Repository<R> resources;
|
||||
|
||||
public RestResponseBuilder(Repository<R> resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
public void buildResponse(RestCallSpec callSpec, RestRequest<R> request,
|
||||
RestResponse.Builder<R> responseBuilder) {
|
||||
HttpMethod method = request.getMethod();
|
||||
R responseBody = null;
|
||||
switch (method) {
|
||||
case GET:
|
||||
responseBody = get(request.getId());
|
||||
break;
|
||||
case POST:
|
||||
responseBody = post(request.getBody());
|
||||
break;
|
||||
case DELETE:
|
||||
delete(request.getId());
|
||||
break;
|
||||
case PUT:
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected method: " + method);
|
||||
}
|
||||
responseBuilder.setBody(responseBody);
|
||||
}
|
||||
|
||||
public R get(Id<R> resourceId) {
|
||||
return resources.get(resourceId);
|
||||
}
|
||||
|
||||
public R post(R resource) {
|
||||
return resources.put(resource);
|
||||
}
|
||||
|
||||
public void delete(Id<R> resourceId) {
|
||||
resources.delete(resourceId);
|
||||
}
|
||||
|
||||
public R put(R resource) {
|
||||
return resources.put(resource);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.webservice.definition.ContentBodySpec;
|
||||
import com.google.gson.webservice.definition.HeaderMap;
|
||||
import com.google.gson.webservice.definition.HeaderMapSpec;
|
||||
import com.google.gson.webservice.definition.rest.RestResource;
|
||||
import com.google.gson.webservice.definition.rest.RestResponse;
|
||||
|
||||
/**
|
||||
@ -33,7 +34,7 @@ import com.google.gson.webservice.definition.rest.RestResponse;
|
||||
*
|
||||
* @author inder
|
||||
*/
|
||||
public final class RestResponseSender<R> {
|
||||
public final class RestResponseSender<R extends RestResource<R>> {
|
||||
private static final Logger logger = Logger.getLogger(RestResponseSender.class.getCanonicalName());
|
||||
|
||||
private Gson gson;
|
||||
|
Loading…
Reference in New Issue
Block a user