Added server-side dispatchers for REST and procedural calls

Implemented the REST dispatcher.
This commit is contained in:
Inderjeet Singh 2010-11-11 17:21:32 +00:00
parent f1e278c4c0
commit 54ba11210f
6 changed files with 311 additions and 50 deletions

View File

@ -0,0 +1,52 @@
/*
* 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.example.service;
import com.google.gson.webservice.definition.CallPath;
/**
* An enum describing all paths for this service
*
* @author Inderjeet Singh
*/
public enum ServicePaths {
NULL_REQUEST(null),
CART("/rest/cart"),
ORDER("/rest/order");
private final CallPath path;
private ServicePaths(String pathInfo) {
this.path = new CallPath(pathInfo);
}
public CallPath getCallPath() {
return path;
}
public static CallPath getCallPath(CallPath invokedPath) {
for (ServicePaths path : values()) {
CallPath callPath = path.path;
String callPathInfo = callPath.get();
// A rest path can end with a resource-id too.
// For example, /rest/cart/1234 should match with /rest/cart
if (callPathInfo != null && invokedPath.matches(callPath)) {
return callPath;
}
}
return null;
}
}

View File

@ -15,29 +15,12 @@
*/
package com.google.gson.wsexample.server;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.example.model.Cart;
import com.google.gson.example.model.Order;
import com.google.gson.example.model.TypedKeys;
import com.google.gson.example.service.SampleJsonService;
import com.google.gson.webservice.definition.HeaderMap;
import com.google.gson.webservice.definition.procedural.RequestBody;
import com.google.gson.webservice.definition.procedural.RequestBodyGsonConverter;
import com.google.gson.webservice.definition.procedural.RequestSpec;
import com.google.gson.webservice.definition.procedural.ResponseBody;
import com.google.gson.webservice.definition.procedural.ResponseBodyGsonConverter;
import com.google.gson.webservice.definition.procedural.ResponseSpec;
import com.google.gson.webservice.definition.procedural.WebServiceCallSpec;
import com.google.gson.webservice.definition.procedural.WebServiceRequest;
import com.google.gson.webservice.definition.procedural.WebServiceResponse;
import com.google.gson.wsf.server.procedural.RequestReceiver;
import com.google.gson.wsf.server.procedural.ResponseSender;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.webservice.definition.CallPath;
/**
* An example servlet that receives JSON web-service requests
*
@ -45,37 +28,24 @@ import javax.servlet.http.HttpServletResponse;
*/
@SuppressWarnings("serial")
public class MainServlet extends HttpServlet {
private final RestDispatcher restDispatcher;
private final ProcedureDispatcher procedureDispatcher;
public MainServlet() {
this.restDispatcher = new RestDispatcher();
this.procedureDispatcher = new ProcedureDispatcher();
}
@Override
public void service(HttpServletRequest req, HttpServletResponse res) {
WebServiceCallSpec spec = SampleJsonService.PLACE_ORDER;
RequestSpec requestSpec = spec.getRequestSpec();
ResponseSpec responseSpec = spec.getResponseSpec();
Gson gson = new GsonBuilder()
.registerTypeAdapter(RequestBody.class,
new RequestBodyGsonConverter(requestSpec.getBodySpec()))
.registerTypeAdapter(ResponseBody.class,
new ResponseBodyGsonConverter(responseSpec.getBodySpec()))
.create();
RequestReceiver requestReceiver = new RequestReceiver(gson, requestSpec);
WebServiceRequest webServiceRequest = requestReceiver.receive(req);
Cart cart = webServiceRequest.getBody().get(TypedKeys.RequestBody.CART);
String authToken = webServiceRequest.getHeader(TypedKeys.Request.AUTH_TOKEN);
Order order = placeOrder(cart, authToken);
// Empty headers per the spec
HeaderMap responseHeaders = new HeaderMap.Builder(responseSpec.getHeadersSpec()).build();
ResponseBody responseBody = new ResponseBody.Builder(responseSpec.getBodySpec())
.put(TypedKeys.ResponseBody.ORDER, order)
.build();
WebServiceResponse response = new WebServiceResponse(responseHeaders, responseBody);
ResponseSender responseSender = new ResponseSender(gson);
responseSender.send(res, response);
}
private Order placeOrder(Cart cart, String authToken) {
// Create an order, in this case a dummy one.
return new Order(cart, "Order123");
String servletPath = req.getServletPath();
int index = "/wsexampleserver".length();
CallPath callPath = new CallPath(servletPath.substring(index));
String path = callPath.get();
if (path.startsWith("/rest")) {
restDispatcher.service(req, res, callPath);
} else if (path.startsWith("/procedure")) {
procedureDispatcher.service(req, res);
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.wsexample.server;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.example.model.Cart;
import com.google.gson.example.model.Order;
import com.google.gson.example.model.TypedKeys;
import com.google.gson.example.service.SampleJsonService;
import com.google.gson.webservice.definition.HeaderMap;
import com.google.gson.webservice.definition.procedural.RequestBody;
import com.google.gson.webservice.definition.procedural.RequestBodyGsonConverter;
import com.google.gson.webservice.definition.procedural.RequestSpec;
import com.google.gson.webservice.definition.procedural.ResponseBody;
import com.google.gson.webservice.definition.procedural.ResponseBodyGsonConverter;
import com.google.gson.webservice.definition.procedural.ResponseSpec;
import com.google.gson.webservice.definition.procedural.WebServiceCallSpec;
import com.google.gson.webservice.definition.procedural.WebServiceRequest;
import com.google.gson.webservice.definition.procedural.WebServiceResponse;
import com.google.gson.wsf.server.procedural.RequestReceiver;
import com.google.gson.wsf.server.procedural.ResponseSender;
/**
* A dispatcher for all the procedural calls
*
* @author Inderjeet Singh
*/
public final class ProcedureDispatcher {
public void service(HttpServletRequest req, HttpServletResponse res) {
WebServiceCallSpec spec = SampleJsonService.PLACE_ORDER;
RequestSpec requestSpec = spec.getRequestSpec();
ResponseSpec responseSpec = spec.getResponseSpec();
Gson gson = new GsonBuilder()
.registerTypeAdapter(RequestBody.class,
new RequestBodyGsonConverter(requestSpec.getBodySpec()))
.registerTypeAdapter(ResponseBody.class,
new ResponseBodyGsonConverter(responseSpec.getBodySpec()))
.create();
RequestReceiver requestReceiver = new RequestReceiver(gson, requestSpec);
WebServiceRequest webServiceRequest = requestReceiver.receive(req);
Cart cart = webServiceRequest.getBody().get(TypedKeys.RequestBody.CART);
String authToken = webServiceRequest.getHeader(TypedKeys.Request.AUTH_TOKEN);
Order order = placeOrder(cart, authToken);
// Empty headers per the spec
HeaderMap responseHeaders = new HeaderMap.Builder(responseSpec.getHeadersSpec()).build();
ResponseBody responseBody = new ResponseBody.Builder(responseSpec.getBodySpec())
.put(TypedKeys.ResponseBody.ORDER, order)
.build();
WebServiceResponse response = new WebServiceResponse(responseHeaders, responseBody);
ResponseSender responseSender = new ResponseSender(gson);
responseSender.send(res, response);
}
private Order placeOrder(Cart cart, String authToken) {
// Create an order, in this case a dummy one.
return new Order(cart, "Order123");
}
}

View File

@ -0,0 +1,104 @@
/*
* 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.wsexample.server;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.example.model.Cart;
import com.google.gson.example.model.Order;
import com.google.gson.example.service.ServicePaths;
import com.google.gson.rest.definition.IDFactory;
import com.google.gson.rest.definition.MetaData;
import com.google.gson.rest.definition.ResourceMap;
import com.google.gson.rest.definition.RestCallSpec;
import com.google.gson.rest.definition.RestRequest;
import com.google.gson.rest.definition.RestResponse;
import com.google.gson.rest.definition.ValueBasedId;
import com.google.gson.rest.server.Repository;
import com.google.gson.rest.server.RepositoryInMemory;
import com.google.gson.rest.server.ResponseBuilderMap;
import com.google.gson.rest.server.RestRequestReceiver;
import com.google.gson.rest.server.RestResponseBuilder;
import com.google.gson.rest.server.RestResponseSender;
import com.google.gson.webservice.definition.CallPath;
/**
* A dispatcher for all the REST requests
*
* @author Inderjeet Singh
*/
public final class RestDispatcher {
private static final double CURRENT_VERSION = 1D;
private final ResourceMap resourceMap;
private final ResponseBuilderMap responseBuilders;
private final RestCallSpec cartSpec;
private final RestCallSpec orderSpec;
private final Gson gson;
public RestDispatcher() {
this.cartSpec = new RestCallSpec.Builder(ServicePaths.CART.getCallPath(), Cart.class)
.setVersion(CURRENT_VERSION)
.build();
this.orderSpec = new RestCallSpec.Builder(ServicePaths.CART.getCallPath(), Cart.class)
.setVersion(CURRENT_VERSION)
.build();
this.resourceMap = new ResourceMap.Builder()
.set(ServicePaths.CART.getCallPath(), cartSpec)
.set(ServicePaths.ORDER.getCallPath(), orderSpec)
.build();
gson = new GsonBuilder()
.setVersion(CURRENT_VERSION)
.registerTypeAdapter(ValueBasedId.class, new ValueBasedId.GsonTypeAdapter())
.registerTypeAdapter(MetaData.class, new MetaData.GsonTypeAdapter())
.create();
Repository<ValueBasedId<Cart>, Cart> carts =
new RepositoryInMemory<ValueBasedId<Cart>, Cart>(ValueBasedId.class, Cart.class);
Repository<ValueBasedId<Order>, Order> orders =
new RepositoryInMemory<ValueBasedId<Order>, Order>(ValueBasedId.class, Order.class);
responseBuilders = new ResponseBuilderMap.Builder()
.set(cartSpec.getResourceType(), new RestResponseBuilder<ValueBasedId<Cart>, Cart>(carts))
.set(orderSpec.getResourceType(), new RestResponseBuilder<ValueBasedId<Order>, Order>(orders))
.build();
}
public IDFactory<ValueBasedId<?>> getIDFactory(RestCallSpec callSpec) {
return new IDFactory<ValueBasedId<?>>(ValueBasedId.class, callSpec.getResourceType());
}
@SuppressWarnings({"rawtypes", "unchecked"})
public RestRequest getRestRequest(Gson gson, RestCallSpec callSpec, CallPath callPath,
HttpServletRequest request, IDFactory<ValueBasedId<?>> idFactory) {
RestRequestReceiver requestReceiver = new RestRequestReceiver(gson, callSpec.getRequestSpec());
return requestReceiver.receive(request, idFactory.createId(callPath.getResourceId()));
}
public void service(HttpServletRequest req, HttpServletResponse res, CallPath callPath) {
RestCallSpec callSpec = resourceMap.get(callPath).createCopy(callPath);
@SuppressWarnings("rawtypes")
RestRequestReceiver requestReceiver = new RestRequestReceiver(gson, callSpec.getRequestSpec());
IDFactory<ValueBasedId<?>> idFactory = getIDFactory(callSpec);
RestRequest<?, ?> restRequest = getRestRequest(gson, callSpec, callPath, req, idFactory);
RestResponse.Builder response = new RestResponse.Builder(callSpec.getResponseSpec());
RestResponseBuilder responseBuilder = responseBuilders.get(callSpec.getResourceType());
responseBuilder.buildResponse(callSpec, restRequest, response);
RestResponse restResponse = response.build();
RestResponseSender responseSender = new RestResponseSender(gson);
responseSender.send(res, restResponse);
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.rest.server;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.rest.definition.ID;
import com.google.gson.rest.definition.RestCallSpec;
import com.google.gson.rest.definition.RestResource;
/**
* A map of {@link RestCallSpec}, {@link RestResponseBuilder} to help figure out which
* {@link RestResponseBuilder} to use for a {@link RestCallSpec}.
*
* @author Inderjeet Singh
*/
public final class ResponseBuilderMap {
public static final class Builder {
private final Map<Type, RestResponseBuilder<?, ?>> map =
new HashMap<Type, RestResponseBuilder<?, ?>>();
public <I extends ID, R extends RestResource<I, R>> Builder set(
Type resourceType, RestResponseBuilder<I, R> responseBuilder) {
map.put(resourceType, responseBuilder);
return this;
}
public ResponseBuilderMap build() {
return new ResponseBuilderMap(map);
}
}
private final Map<Type, RestResponseBuilder<?, ?>> map;
public ResponseBuilderMap(Map<Type, RestResponseBuilder<?, ?>> map) {
this.map = map;
}
public RestResponseBuilder<?, ?> get(Type resourceType) {
return (RestResponseBuilder<?, ?>)map.get(resourceType);
}
}

View File

@ -22,7 +22,7 @@ import com.google.gson.rest.definition.RestResource;
import com.google.gson.rest.definition.RestResponse;
import com.google.gson.webservice.definition.HttpMethod;
public abstract class RestResponseBuilder<I extends ID, R extends RestResource<I, R>> {
public class RestResponseBuilder<I extends ID, R extends RestResource<I, R>> {
protected final Repository<I, R> resources;
public RestResponseBuilder(Repository<I, R> resources) {