moved contents of wsclient into greaze-client

This commit is contained in:
Inderjeet Singh 2010-11-14 07:44:26 +00:00
parent 520259fefa
commit 0fa317045b
20 changed files with 7 additions and 1301 deletions

View File

@ -1,101 +0,0 @@
/*
* 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.client;
import java.lang.reflect.Type;
import com.google.greaze.definition.CallPath;
import com.google.greaze.definition.HeaderMap;
import com.google.greaze.definition.HttpMethod;
import com.google.greaze.definition.rest.ID;
import com.google.greaze.definition.rest.ResourceDepot;
import com.google.greaze.definition.rest.RestCallSpec;
import com.google.greaze.definition.rest.RestRequest;
import com.google.greaze.definition.rest.RestResource;
import com.google.greaze.definition.rest.RestResponse;
import com.google.gson.Gson;
/**
* A client class to access a rest resource
*
* @author Inderjeet Singh
*/
public class ResourceDepotClient<I extends ID, R extends RestResource<I, R>>
implements ResourceDepot<I, R> {
private final RestClientStub stub;
private final RestCallSpec callSpec;
private final Type resourceType;
private final Gson gson;
/**
* @param stub stub containing server info to access the rest client
* @param callPath relative path to the resource
* @param resourceType Class for the resource. Such as Cart.class
*/
public ResourceDepotClient(RestClientStub stub, CallPath callPath, Type resourceType, Gson gson) {
this(stub, resourceType, generateRestCallSpec(callPath, resourceType), gson);
}
protected ResourceDepotClient(RestClientStub stub, Type resourceType, RestCallSpec callSpec, Gson gson) {
this.stub = stub;
this.callSpec = callSpec;
this.resourceType = resourceType;
this.gson = gson;
}
private static <T> RestCallSpec generateRestCallSpec(CallPath callPath, Type resourceType) {
return new RestCallSpec.Builder(callPath, resourceType).build();
}
@Override
public R get(I resourceId) {
HeaderMap requestHeaders =
new HeaderMap.Builder(callSpec.getRequestSpec().getHeadersSpec()).build();
RestRequest<I, R> request =
new RestRequest<I, R>(HttpMethod.GET, requestHeaders, resourceId, null, resourceType);
RestResponse<I, R> response = stub.getResponse(callSpec, request, gson);
return response.getBody();
}
@Override
public R post(R resource) {
HeaderMap requestHeaders =
new HeaderMap.Builder(callSpec.getRequestSpec().getHeadersSpec()).build();
RestRequest<I, R> request =
new RestRequest<I, R>(HttpMethod.POST, requestHeaders, resource.getId(), resource, resourceType);
RestResponse<I, R> response = stub.getResponse(callSpec, request, gson);
return response.getBody();
}
@Override
public R put(R resource) {
HeaderMap requestHeaders =
new HeaderMap.Builder(callSpec.getRequestSpec().getHeadersSpec()).build();
RestRequest<I, R> request =
new RestRequest<I, R>(HttpMethod.PUT, requestHeaders, resource.getId(), resource, resourceType);
RestResponse<I, R> response = stub.getResponse(callSpec, request, gson);
return response.getBody();
}
@Override
public void delete(I resourceId) {
HeaderMap requestHeaders =
new HeaderMap.Builder(callSpec.getRequestSpec().getHeadersSpec()).build();
RestRequest<I, R> request =
new RestRequest<I, R>(HttpMethod.DELETE, requestHeaders, resourceId, null, resourceType);
stub.getResponse(callSpec, request, gson);
}
}

View File

@ -1,125 +0,0 @@
/*
* 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.client;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.rest.ID;
import com.google.greaze.definition.rest.RestCallSpec;
import com.google.greaze.definition.rest.RestRequest;
import com.google.greaze.definition.rest.RestResource;
import com.google.greaze.definition.rest.RestResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.webservice.client.ServerConfig;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A stub to access the rest service
*
* @author inder
*/
public class RestClientStub {
private final ServerConfig config;
private final Logger logger;
private final Level logLevel;
public RestClientStub(ServerConfig serverConfig) {
this(serverConfig, null);
}
public RestClientStub(ServerConfig serverConfig, Level logLevel) {
this.config = serverConfig;
this.logger = logLevel == null ? null : Logger.getLogger(RestClientStub.class.getName());
this.logLevel = logLevel;
}
private <I extends ID> URL getWebServiceUrl(
RestCallSpec callSpec, ID id) {
double version = callSpec.getVersion();
StringBuilder url = new StringBuilder(config.getServiceBaseUrl());
if (version != -1D) {
url.append('/').append(version);
}
url.append(callSpec.getPath().get());
if (id != null) {
url.append('/').append(id.getValue());
}
try {
return new URL(url.toString());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public <I extends ID, R extends RestResource<I, R>> RestResponse<I, R> getResponse(
RestCallSpec callSpec, RestRequest<I, R> request) {
Gson gson = new GsonBuilder().setVersion(callSpec.getVersion()).create();
return getResponse(callSpec, request, gson);
}
public <I extends ID, R extends RestResource<I, R>> RestResponse<I, R> getResponse(
RestCallSpec callSpec, RestRequest<I, R> request, Gson gson) {
HttpURLConnection conn = null;
try {
URL webServiceUrl = getWebServiceUrl(callSpec, request.getId());
conn = (HttpURLConnection) webServiceUrl.openConnection();
return getResponse(callSpec, request, gson, conn);
} catch (IOException e) {
throw new WebServiceSystemException(e);
} finally {
closeIgnoringErrors(conn);
}
}
/**
* Use this method if you want to mange the HTTP Connection yourself. This is useful when you
* want to use HTTP pipelining.
*/
public <I extends ID, R extends RestResource<I, R>> RestResponse<I, R> getResponse(
RestCallSpec callSpec, RestRequest<I, R> request, Gson gson,
HttpURLConnection conn) {
try {
if (logger != null) {
URL webServiceUrl = getWebServiceUrl(callSpec, request.getId());
logger.log(logLevel, "Opening connection to " + webServiceUrl);
}
RestRequestSender requestSender = new RestRequestSender(gson, logLevel);
requestSender.send(conn, request);
RestResponseReceiver<I, R> responseReceiver =
new RestResponseReceiver<I, R>(gson, callSpec.getResponseSpec(), logLevel);
return responseReceiver.receive(conn);
} catch (IllegalArgumentException e) {
throw new WebServiceSystemException(e);
}
}
private static void closeIgnoringErrors(HttpURLConnection conn) {
if (conn != null) {
conn.disconnect();
}
}
@Override
public String toString() {
return String.format("config:%s", config);
}
}

View File

@ -1,119 +0,0 @@
/*
* 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.client;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.greaze.definition.HeaderMap;
import com.google.greaze.definition.HeaderMapSpec;
import com.google.greaze.definition.HttpMethod;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.rest.ID;
import com.google.greaze.definition.rest.RestRequest;
import com.google.greaze.definition.rest.RestResource;
import com.google.gson.Gson;
import com.google.gson.wsclient.internal.utils.Streams;
/**
* Class to send Web service requests on a {@link HttpURLConnection}.
*
* @author inder
*/
public final class RestRequestSender {
private static final boolean SIMULATE_GET_WITH_POST = true;
private static final boolean SIMULATE_PUT_WITH_POST = true;
private final Gson gson;
private final Logger logger;
private final Level logLevel;
public RestRequestSender(Gson gson) {
this(gson, null);
}
public RestRequestSender(Gson gson, Level logLevel) {
this.gson = gson;
logger = logLevel == null ? null : Logger.getLogger(RestRequestSender.class.getName());
this.logLevel = logLevel;
}
public <I extends ID, R extends RestResource<I, R>> void send(
HttpURLConnection conn, RestRequest<I, R> request) {
try {
HttpMethod method = request.getHttpMethod();
if (SIMULATE_PUT_WITH_POST && method == HttpMethod.PUT) {
method = HttpMethod.POST;
setHeader(conn, HttpMethod.SIMULATED_METHOD_HEADER, HttpMethod.PUT.toString(), true);
} else if (SIMULATE_GET_WITH_POST && method == HttpMethod.GET) {
method = HttpMethod.POST;
setHeader(conn, HttpMethod.SIMULATED_METHOD_HEADER, HttpMethod.GET.toString(), true);
}
conn.setRequestMethod(method.toString());
setHeader(conn, "Content-Type", request.getContentType(), true);
// Assume conservatively that the response will need to be read.
// This is done here instead of in the response receiver because this property must be set
// before sending any data on the connection.
conn.setDoInput(true);
R requestBody = request.getBody();
String requestBodyContents = "";
if (method == HttpMethod.POST || method == HttpMethod.PUT) {
// Android Java VM ignore Content-Length if setDoOutput is not set
conn.setDoOutput(true);
}
if (requestBody != null) {
requestBodyContents = gson.toJson(requestBody, request.getSpec().getResourceType());
}
String contentLength = String.valueOf(requestBodyContents.length());
setHeader(conn, "Content-Length", contentLength, true);
addRequestParams(conn, request.getHeaders());
Streams.copy(requestBodyContents, conn.getOutputStream(), false);
// Initiate the sending of the request.
conn.connect();
} catch (IOException e) {
throw new WebServiceSystemException(e);
}
}
private void addRequestParams(HttpURLConnection conn, HeaderMap requestParams) {
HeaderMapSpec spec = requestParams.getSpec();
for (Map.Entry<String, Object> entry : requestParams.entrySet()) {
String paramName = entry.getKey();
Type type = spec.getTypeFor(paramName);
Object value = entry.getValue();
String json = gson.toJson(value, type);
setHeader(conn, paramName, json, false);
}
}
private void setHeader(HttpURLConnection conn, String name, String value, boolean overwrite) {
if (logger != null) {
logger.log(logLevel, String.format("Request param: %s:%s", name, value));
}
if (overwrite) {
conn.setRequestProperty(name, value);
} else {
conn.addRequestProperty(name, value);
}
}
}

View File

@ -1,100 +0,0 @@
/*
* 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.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.greaze.definition.ContentBodySpec;
import com.google.greaze.definition.HeaderMap;
import com.google.greaze.definition.HeaderMapSpec;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.rest.ID;
import com.google.greaze.definition.rest.RestResource;
import com.google.greaze.definition.rest.RestResponse;
import com.google.greaze.definition.rest.RestResponseSpec;
import com.google.gson.Gson;
import com.google.gson.wsclient.internal.utils.ConnectionPreconditions;
/**
* Receives a response coming on an {@link HttpURLConnection}.
*
* @author inder
*/
public final class RestResponseReceiver<I extends ID, R extends RestResource<I, R>> {
private final Gson gson;
private final RestResponseSpec spec;
private final Logger logger;
private final Level logLevel;
public RestResponseReceiver(Gson gson, RestResponseSpec spec) {
this(gson, spec, null);
}
public RestResponseReceiver(Gson gson, RestResponseSpec spec, Level logLevel) {
this.gson = gson;
this.spec = spec;
this.logger = logLevel == null ? null : Logger.getLogger(RestResponseReceiver.class.getName());
this.logLevel = logLevel;
}
public RestResponse<I, R> receive(HttpURLConnection conn) {
try {
HeaderMapSpec paramSpec = spec.getHeadersSpec();
Type bodyType = spec.getResourceType();
// read response
HeaderMap responseParams = readResponseHeaders(conn, paramSpec);
R responseBody = readResponseBody(conn, bodyType);
return new RestResponse<I, R>(responseParams, responseBody, bodyType);
} catch (IOException e) {
throw new WebServiceSystemException(e);
}
}
private HeaderMap readResponseHeaders(HttpURLConnection conn, HeaderMapSpec paramsSpec) {
HeaderMap.Builder paramsBuilder = new HeaderMap.Builder(paramsSpec);
for (Map.Entry<String, Type> entry : paramsSpec.entrySet()) {
String paramName = entry.getKey();
String json = conn.getHeaderField(paramName);
if (json != null) {
if (logger != null) {
logger.log(logLevel, String.format("Response Header: %s:%s\n", paramName, json));
}
Type typeOfT = paramsSpec.getTypeFor(paramName);
Object value = gson.fromJson(json, typeOfT);
paramsBuilder.put(paramName, value, typeOfT);
}
}
return paramsBuilder.build();
}
@SuppressWarnings("unchecked")
private R readResponseBody(
HttpURLConnection conn, Type resourceType) throws IOException {
String connContentType = conn.getContentType();
ConnectionPreconditions.checkArgument(
connContentType.contains(ContentBodySpec.JSON_CONTENT_TYPE), conn);
Reader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
R body = (R) gson.fromJson(reader, resourceType);
return body;
}
}

View File

@ -1,86 +0,0 @@
/*
* 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.query.client;
import java.util.List;
import com.google.greaze.definition.CallPath;
import com.google.greaze.definition.HeaderMap;
import com.google.greaze.definition.HttpMethod;
import com.google.greaze.definition.rest.ID;
import com.google.greaze.definition.rest.RestResource;
import com.google.greaze.definition.rest.query.ResourceQuery;
import com.google.greaze.definition.rest.query.TypedKeysQuery;
import com.google.greaze.definition.webservice.RequestBody;
import com.google.greaze.definition.webservice.ResponseBody;
import com.google.greaze.definition.webservice.WebServiceCallSpec;
import com.google.greaze.definition.webservice.WebServiceRequest;
import com.google.greaze.definition.webservice.WebServiceResponse;
import com.google.gson.Gson;
import com.google.gson.webservice.client.WebServiceClient;
/**
* A client to invoke {@link ResourceQuery}s associated with a REST resource
*
* @author Inderjeet Singh
*
* @param <I> ID type of the REST resource
* @param <R> type of the REST resource
* @param <Q> Query parameters
*/
public class ResourceQueryClient<I extends ID, R extends RestResource<I, R>, Q>
implements ResourceQuery<I, R, Q> {
private final WebServiceClient stub;
private final WebServiceCallSpec callSpec;
private final Gson gson;
/**
* @param stub stub containing server info to access the rest client
* @param callPath relative path to the resource
*/
public ResourceQueryClient(WebServiceClient stub, CallPath callPath, Gson gson) {
this(stub, generateCallSpec(callPath), gson);
}
protected ResourceQueryClient(WebServiceClient stub, WebServiceCallSpec callSpec, Gson gson) {
this.stub = stub;
this.callSpec = callSpec;
this.gson = gson;
}
private static <T> WebServiceCallSpec generateCallSpec(CallPath callPath) {
return new WebServiceCallSpec.Builder(callPath)
.supportsHttpMethod(HttpMethod.GET)
.addResponseBodyParam(TypedKeysQuery.RESOURCE_LIST)
.build();
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public List<R> query(Q query) {
HeaderMap requestHeaders =
new HeaderMap.Builder(callSpec.getRequestSpec().getHeadersSpec()).build();
RequestBody requestBody =
new RequestBody.Builder(callSpec.getRequestSpec().getBodySpec())
.build();
WebServiceRequest request = new WebServiceRequest(HttpMethod.GET, requestHeaders, requestBody);
WebServiceResponse response = stub.getResponse(callSpec, request, gson);
ResponseBody body = response.getBody();
List list = body.get(TypedKeysQuery.RESOURCE_LIST);
return list;
}
}

View File

@ -1,59 +0,0 @@
/*
* 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.client;
import java.util.concurrent.BlockingQueue;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.webservice.WebServiceCall;
import com.google.greaze.definition.webservice.WebServiceResponse;
/**
* A consumer that executes in its own thread consuming queue entries and invoking web-service calls
*
* @author inder
*/
final class QueueConsumer implements Runnable {
private final BlockingQueue<QueueEntry> queue;
private WebServiceClient client;
QueueConsumer(BlockingQueue<QueueEntry> queue, WebServiceClient client) {
this.queue = queue;
this.client = client;
}
@Override
public void run() {
try {
while(true) {
consume(queue.take());
}
} catch (InterruptedException e) {
// exit
}
}
private void consume(QueueEntry entry) {
try {
WebServiceResponse response = client.getResponse(entry.callSpec, entry.request);
WebServiceCall call = new WebServiceCall(entry.callSpec, entry.request, response);
entry.responseCallback.handleResponse(call);
} catch (WebServiceSystemException e) {
entry.responseCallback.handleError(e, entry.request, entry.callSpec);
}
}
}

View File

@ -1,38 +0,0 @@
/*
* 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.client;
import com.google.greaze.definition.webservice.WebServiceCallSpec;
import com.google.greaze.definition.webservice.WebServiceRequest;
/**
* A holder class for an entry stored in queue. It contains references to the request, callspec,
* and the client-supplied callback to provide sufficient information to execute a web-service call.
*
* @author inder
*/
final class QueueEntry {
final WebServiceCallSpec callSpec;
final WebServiceRequest request;
final ResponseCallback responseCallback;
QueueEntry(WebServiceCallSpec callSpec, WebServiceRequest request,
ResponseCallback responseCallback) {
this.callSpec = callSpec;
this.request = request;
this.responseCallback = responseCallback;
}
}

View File

@ -1,103 +0,0 @@
/*
* Copyright (C) 2008 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.client;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.greaze.definition.HeaderMap;
import com.google.greaze.definition.HeaderMapSpec;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.webservice.RequestBody;
import com.google.greaze.definition.webservice.WebServiceRequest;
import com.google.gson.Gson;
import com.google.gson.wsclient.internal.utils.Streams;
/**
* Class to send Web service requests on a {@link HttpURLConnection}.
*
* @author inder
*/
public final class RequestSender {
private final Gson gson;
private final Logger logger;
private final Level logLevel;
public RequestSender(Gson gson) {
this(gson, null);
}
public RequestSender(Gson gson, Level logLevel) {
this.gson = gson;
logger = logLevel == null ? null : Logger.getLogger(RequestSender.class.getName());
this.logLevel = logLevel;
}
public void send(HttpURLConnection conn, WebServiceRequest request) {
try {
conn.setRequestMethod(request.getHttpMethod().toString());
setHeader(conn, "Content-Type", request.getContentType(), true);
// Assume conservatively that the response will need to be read.
// This is done here instead of in the response receiver because this property must be set
// before sending any data on the connection.
conn.setDoInput(true);
RequestBody requestBody = request.getBody();
String requestBodyContents = "";
// Android Java VM ignore Content-Length if setDoOutput is not set
conn.setDoOutput(true);
if (requestBody.getSpec().size() > 0) {
requestBodyContents = gson.toJson(requestBody);
}
String contentLength = String.valueOf(requestBodyContents.length());
setHeader(conn, "Content-Length", contentLength, true);
addRequestParams(conn, request.getHeaders());
Streams.copy(requestBodyContents, conn.getOutputStream(), false);
// Initiate the sending of the request.
conn.connect();
} catch (IOException e) {
throw new WebServiceSystemException(e);
}
}
private void addRequestParams(HttpURLConnection conn, HeaderMap requestParams) {
HeaderMapSpec spec = requestParams.getSpec();
for (Map.Entry<String, Object> entry : requestParams.entrySet()) {
String paramName = entry.getKey();
Type type = spec.getTypeFor(paramName);
Object value = entry.getValue();
String json = gson.toJson(value, type);
setHeader(conn, paramName, json, false);
}
}
private void setHeader(HttpURLConnection conn, String name, String value, boolean overwrite) {
if (logger != null) {
logger.log(logLevel, String.format("Request param: %s:%s", name, value));
}
if (overwrite) {
conn.setRequestProperty(name, value);
} else {
conn.addRequestProperty(name, value);
}
}
}

View File

@ -1,33 +0,0 @@
/*
* 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.client;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.webservice.WebServiceCall;
import com.google.greaze.definition.webservice.WebServiceCallSpec;
import com.google.greaze.definition.webservice.WebServiceRequest;
/**
* A client-supplied callback to be used with {@link WebServiceClientAsync}. When a web-service
* call is executed asynchronously, this callback is invoked with the results.
*
* @author inder
*/
public interface ResponseCallback {
public void handleResponse(WebServiceCall call);
public void handleError(WebServiceSystemException e, WebServiceRequest request,
WebServiceCallSpec callSpec);
}

View File

@ -1,100 +0,0 @@
/*
* Copyright (C) 2008 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.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.greaze.definition.HeaderMap;
import com.google.greaze.definition.HeaderMapSpec;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.webservice.ResponseBody;
import com.google.greaze.definition.webservice.ResponseBodySpec;
import com.google.greaze.definition.webservice.ResponseSpec;
import com.google.greaze.definition.webservice.WebServiceResponse;
import com.google.gson.Gson;
import com.google.gson.wsclient.internal.utils.ConnectionPreconditions;
/**
* Receives a response coming on an {@link HttpURLConnection}.
*
* @author inder
*/
public final class ResponseReceiver {
private final Gson gson;
private final ResponseSpec spec;
private final Logger logger;
private final Level logLevel;
public ResponseReceiver(Gson gson, ResponseSpec spec) {
this(gson, spec, null);
}
public ResponseReceiver(Gson gson, ResponseSpec spec, Level logLevel) {
this.gson = gson;
this.spec = spec;
this.logger = logLevel == null ? null : Logger.getLogger(ResponseReceiver.class.getName());
this.logLevel = logLevel;
}
public WebServiceResponse receive(HttpURLConnection conn) {
try {
HeaderMapSpec paramSpec = spec.getHeadersSpec();
ResponseBodySpec bodySpec = spec.getBodySpec();
// read response
HeaderMap responseParams = readResponseHeaders(conn, paramSpec);
ResponseBody responseBody = readResponseBody(conn, bodySpec);
return new WebServiceResponse(responseParams, responseBody);
} catch (IOException e) {
throw new WebServiceSystemException(e);
}
}
private HeaderMap readResponseHeaders(HttpURLConnection conn, HeaderMapSpec paramsSpec) {
HeaderMap.Builder paramsBuilder = new HeaderMap.Builder(paramsSpec);
for (Map.Entry<String, Type> entry : paramsSpec.entrySet()) {
String paramName = entry.getKey();
String json = conn.getHeaderField(paramName);
if (json != null) {
if (logger != null) {
logger.log(logLevel, String.format("Response Header: %s:%s\n", paramName, json));
}
Type typeOfT = paramsSpec.getTypeFor(paramName);
Object value = gson.fromJson(json, typeOfT);
paramsBuilder.put(paramName, value, typeOfT);
}
}
return paramsBuilder.build();
}
private ResponseBody readResponseBody(HttpURLConnection conn, ResponseBodySpec bodySpec)
throws IOException {
if (bodySpec.size() == 0) {
return new ResponseBody.Builder(bodySpec).build();
}
String connContentType = conn.getContentType();
ConnectionPreconditions.checkArgument(connContentType.contains(bodySpec.getContentType()), conn);
Reader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
ResponseBody body = gson.fromJson(reader, ResponseBody.class);
return body;
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2008 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.client;
/**
* Configuration needed to access a Gson web service.
*
* @author inder
*/
public final class ServerConfig {
private final String serviceBaseUrl;
public ServerConfig(String serviceBaseUrl) {
this.serviceBaseUrl = serviceBaseUrl;
}
public String getServiceBaseUrl() {
return serviceBaseUrl;
}
@Override
public String toString() {
return serviceBaseUrl;
}
}

View File

@ -1,39 +0,0 @@
/*
* 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.client;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* An executor that uses a single thread to execute all calls
*
* @author inder
*/
final class SingleThreadExecutor implements TaskExecutor {
private ExecutorService executor;
@Override
public void execute(Runnable r) {
executor = Executors.newSingleThreadExecutor();
executor.execute(r);
}
@Override
public void shutdownNow() {
executor.shutdownNow();
}
}

View File

@ -1,29 +0,0 @@
/*
* 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.client;
import java.util.concurrent.Executor;
/**
* An {@link Executor} with an additional method for shutdown. We could have just used
* {@link java.util.concurrent.ExecutorService}, however, that requires too many methods to be
* implemented.
*
* @author inder
*/
interface TaskExecutor extends Executor {
public void shutdownNow();
}

View File

@ -1,38 +0,0 @@
/*
* 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.client;
/**
* An executor that uses a new thread to execute each call
*
* @author inder
*/
final class ThreadPerTaskExecutor implements TaskExecutor {
private Thread thread;
@Override
public void execute(Runnable r) {
thread = new Thread(r);
thread.start();
}
@Override
public void shutdownNow() {
if (thread != null) {
thread.interrupt();
}
}
}

View File

@ -1,95 +0,0 @@
/*
* Copyright (C) 2008 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.client;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.webservice.ResponseBody;
import com.google.greaze.definition.webservice.ResponseBodyGsonConverter;
import com.google.greaze.definition.webservice.WebServiceCallSpec;
import com.google.greaze.definition.webservice.WebServiceRequest;
import com.google.greaze.definition.webservice.WebServiceResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Main class used by clients to access a Gson Web service.
*
* @author inder
*/
public class WebServiceClient {
private final ServerConfig config;
private final Logger logger;
private final Level logLevel;
public WebServiceClient(ServerConfig serverConfig) {
this(serverConfig, null);
}
public WebServiceClient(ServerConfig serverConfig, Level logLevel) {
this.config = serverConfig;
this.logger = logLevel == null ? null : Logger.getLogger(WebServiceClient.class.getName());
this.logLevel = logLevel;
}
private URL getWebServiceUrl(WebServiceCallSpec callSpec) {
String url = config.getServiceBaseUrl() + callSpec.getPath().get();
try {
return new URL(url);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public WebServiceResponse getResponse(WebServiceCallSpec callSpec, WebServiceRequest request) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(ResponseBody.class,
new ResponseBodyGsonConverter(callSpec.getResponseSpec().getBodySpec()))
.create();
return getResponse(callSpec, request, gson);
}
public WebServiceResponse getResponse(
WebServiceCallSpec callSpec, WebServiceRequest request, Gson gson) {
try {
URL webServiceUrl = getWebServiceUrl(callSpec);
if (logger != null) {
logger.log(logLevel, "Opening connection to " + webServiceUrl);
}
HttpURLConnection conn = (HttpURLConnection) webServiceUrl.openConnection();
RequestSender requestSender = new RequestSender(gson, logLevel);
requestSender.send(conn, request);
ResponseReceiver responseReceiver =
new ResponseReceiver(gson, callSpec.getResponseSpec(), logLevel);
return responseReceiver.receive(conn);
} catch (IOException e) {
throw new WebServiceSystemException(e);
} catch (IllegalArgumentException e) {
throw new WebServiceSystemException(e);
}
}
@Override
public String toString() {
return String.format("config:%s", config);
}
}

View File

@ -1,70 +0,0 @@
/*
* 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.client;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import com.google.greaze.definition.WebServiceSystemException;
import com.google.greaze.definition.webservice.WebServiceCallSpec;
import com.google.greaze.definition.webservice.WebServiceRequest;
/**
* A client for invoking a JSON-based Web-service in an asynchronous manner. The call is queued,
* and control returns to the caller. A separate thread executes the call, and invokes the
* client-supplied callback with results.
*
* @author inder
*/
public class WebServiceClientAsync {
private final BlockingQueue<QueueEntry> queue;
private final boolean threadPerTask;
private final TaskExecutor executor;
public WebServiceClientAsync(ServerConfig serverConfig) {
this(serverConfig, null);
}
public WebServiceClientAsync(ServerConfig serverConfig, Level logLevel) {
this(new WebServiceClient(serverConfig, logLevel));
}
public WebServiceClientAsync(WebServiceClient client) {
queue = new LinkedBlockingQueue<QueueEntry>();
this.threadPerTask = true;
QueueConsumer consumer = new QueueConsumer(queue, client);
executor = getExecutor();
executor.execute(consumer);
}
private TaskExecutor getExecutor() {
return threadPerTask ? new ThreadPerTaskExecutor() : new SingleThreadExecutor();
}
public void callAsync(WebServiceCallSpec callSpec, WebServiceRequest request,
ResponseCallback responseCallback) {
try {
queue.put(new QueueEntry(callSpec, request, responseCallback));
} catch (InterruptedException e) {
throw new WebServiceSystemException(e);
}
}
public void shutdownNow() {
executor.shutdownNow();
}
}

View File

@ -1,71 +0,0 @@
/*
* 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.wsclient.internal.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public final class ConnectionPreconditions {
public static void checkArgument(boolean condition, HttpURLConnection conn) {
if (!condition) {
StringBuilder sb = new StringBuilder();
try {
sb.append("HttpURLConnection Details\n");
sb.append("ResponseCode:" + conn.getResponseCode());
sb.append(", ContentType: " + conn.getContentType() + "\n");
Map<String, List<String>> headerFields = conn.getHeaderFields();
for (Entry<String, List<String>> header : headerFields.entrySet()) {
sb.append(header.getKey()).append(":");
boolean first = true;
for (String value : header.getValue()) {
if (first) {
first = false;
} else {
sb.append(",");
}
sb.append(value);
}
sb.append("\n");
}
byte[] data = readInByteArray(conn.getInputStream());
sb.append(new String(data));
} catch (IOException e) {
// ignore
}
throw new IllegalArgumentException(sb.toString());
}
}
private static byte[] readInByteArray(InputStream src) {
ByteArrayOutputStream dst = new ByteArrayOutputStream();
try {
Streams.copy(src, dst, true, true);
} catch (IOException e) {
// ignore
}
return dst.toByteArray();
}
private ConnectionPreconditions() {
// prevent instantiation
}
}

View File

@ -1,50 +0,0 @@
/*
* 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.wsclient.internal.utils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public final class Streams {
public static void copy(String str, OutputStream dst, boolean closeOutput) throws IOException {
byte[] bytes = str.getBytes("UTF-8");
copy(new ByteArrayInputStream(bytes), dst, true, closeOutput);
}
/**
* Copy contents of src to dst. Exhausts src completely, and closes both streams.
*/
public static void copy(InputStream src, OutputStream dst, boolean closeInput,
boolean closeOutput) throws IOException {
try {
final byte[] buf = new byte[2048];
int count;
while ((count = src.read(buf)) != -1) {
dst.write(buf, 0, count);
}
} finally {
if (closeInput) src.close();
if (closeOutput) dst.close();
}
}
private Streams() {
// Prevent instantiation
}
}

View File

@ -21,13 +21,13 @@ import com.google.greaze.definition.webservice.RequestBody;
import com.google.greaze.definition.webservice.WebServiceCallSpec;
import com.google.greaze.definition.webservice.WebServiceRequest;
import com.google.greaze.definition.webservice.WebServiceResponse;
import com.google.greaze.webservice.client.ServerConfig;
import com.google.greaze.webservice.client.WebServiceClient;
import com.google.gson.example.model.Cart;
import com.google.gson.example.model.LineItem;
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.client.ServerConfig;
import com.google.gson.webservice.client.WebServiceClient;
import java.util.ArrayList;
import java.util.List;

View File

@ -16,16 +16,16 @@
import com.google.greaze.definition.CallPath;
import com.google.greaze.definition.rest.ValueBasedId;
import com.google.greaze.rest.client.ResourceDepotClient;
import com.google.greaze.rest.client.RestClientStub;
import com.google.greaze.rest.query.client.ResourceQueryClient;
import com.google.greaze.webservice.client.ServerConfig;
import com.google.greaze.webservice.client.WebServiceClient;
import com.google.gson.Gson;
import com.google.gson.example.model.Cart;
import com.google.gson.example.model.LineItem;
import com.google.gson.example.model.Order;
import com.google.gson.example.model.QueryOrdersByItemName;
import com.google.gson.rest.client.ResourceDepotClient;
import com.google.gson.rest.client.RestClientStub;
import com.google.gson.rest.query.client.ResourceQueryClient;
import com.google.gson.webservice.client.ServerConfig;
import com.google.gson.webservice.client.WebServiceClient;
import java.util.ArrayList;
import java.util.List;