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:
Inderjeet Singh 2010-10-17 16:01:36 +00:00
parent 6825477d75
commit 5adfa4bc04
21 changed files with 553 additions and 103 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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> {
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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>

View 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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;