Added server-side dispatchers for REST and procedural calls
Implemented the REST dispatcher.
This commit is contained in:
parent
f1e278c4c0
commit
54ba11210f
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,29 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package com.google.gson.wsexample.server;
|
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.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.google.gson.webservice.definition.CallPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An example servlet that receives JSON web-service requests
|
* An example servlet that receives JSON web-service requests
|
||||||
*
|
*
|
||||||
|
@ -45,37 +28,24 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class MainServlet extends HttpServlet {
|
public class MainServlet extends HttpServlet {
|
||||||
|
private final RestDispatcher restDispatcher;
|
||||||
|
private final ProcedureDispatcher procedureDispatcher;
|
||||||
|
|
||||||
|
public MainServlet() {
|
||||||
|
this.restDispatcher = new RestDispatcher();
|
||||||
|
this.procedureDispatcher = new ProcedureDispatcher();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void service(HttpServletRequest req, HttpServletResponse res) {
|
public void service(HttpServletRequest req, HttpServletResponse res) {
|
||||||
WebServiceCallSpec spec = SampleJsonService.PLACE_ORDER;
|
String servletPath = req.getServletPath();
|
||||||
RequestSpec requestSpec = spec.getRequestSpec();
|
int index = "/wsexampleserver".length();
|
||||||
ResponseSpec responseSpec = spec.getResponseSpec();
|
CallPath callPath = new CallPath(servletPath.substring(index));
|
||||||
Gson gson = new GsonBuilder()
|
String path = callPath.get();
|
||||||
.registerTypeAdapter(RequestBody.class,
|
if (path.startsWith("/rest")) {
|
||||||
new RequestBodyGsonConverter(requestSpec.getBodySpec()))
|
restDispatcher.service(req, res, callPath);
|
||||||
.registerTypeAdapter(ResponseBody.class,
|
} else if (path.startsWith("/procedure")) {
|
||||||
new ResponseBodyGsonConverter(responseSpec.getBodySpec()))
|
procedureDispatcher.service(req, res);
|
||||||
.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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ import com.google.gson.rest.definition.RestResource;
|
||||||
import com.google.gson.rest.definition.RestResponse;
|
import com.google.gson.rest.definition.RestResponse;
|
||||||
import com.google.gson.webservice.definition.HttpMethod;
|
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;
|
protected final Repository<I, R> resources;
|
||||||
|
|
||||||
public RestResponseBuilder(Repository<I, R> resources) {
|
public RestResponseBuilder(Repository<I, R> resources) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user