/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/
package org.restlet.engine.adapter;
import java.io.IOException;
import java.util.logging.Level;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Uniform;
import org.restlet.data.Method;
import org.restlet.data.Parameter;
import org.restlet.data.Status;
import org.restlet.engine.Edition;
import org.restlet.engine.header.HeaderConstants;
import org.restlet.engine.header.HeaderUtils;
import org.restlet.util.Series;
/**
* Converter of high-level uniform calls into low-level HTTP client calls.
*
* @author Jerome Louvel
*/
public class ClientAdapter extends Adapter {
/**
* Constructor.
*
* @param context
* The context to use.
*/
public ClientAdapter(Context context) {
super(context);
}
/**
* Commits the changes to a handled HTTP client call back into the original
* uniform call. The default implementation first invokes the
* "addResponseHeaders" then asks the "htppCall" to send the response back
* to the client.
*
* @param httpCall
* The original HTTP call.
* @param request
* The high-level request.
* @param response
* The high-level response.
* @throws Exception
*/
public void commit(final ClientCall httpCall, Request request,
Response response) throws Exception {
if (httpCall != null) {
// Check if the call is asynchronous
if (request.getOnResponse() != null) {
final Uniform userCallback = request.getOnResponse();
// Send the request to the client
httpCall.sendRequest(request, response, new Uniform() {
public void handle(Request request, Response response) {
try {
updateResponse(response,
new Status(httpCall.getStatusCode(), null,
httpCall.getReasonPhrase(), null),
httpCall);
userCallback.handle(request, response);
} catch (Exception e) {
// Unexpected exception occurred
if ((response.getStatus() == null)
|| !response.getStatus().isError()) {
response.setStatus(
Status.CONNECTOR_ERROR_INTERNAL, e);
userCallback.handle(request, response);
}
}
}
});
} else {
if (Edition.CURRENT == Edition.GWT) {
System.err
.println("HTTP client calls must have a callback in the GWT edition");
} else {
updateResponse(response, httpCall.sendRequest(request),
httpCall);
}
}
}
}
/**
* Reads the response headers of a handled HTTP client call to update the
* original uniform call.
*
* @param httpCall
* The handled HTTP client call.
* @param response
* The high-level response to update.
*/
protected void readResponseHeaders(ClientCall httpCall, Response response) {
try {
Series<Parameter> responseHeaders = httpCall.getResponseHeaders();
// Put the response headers in the call's attributes map
response.getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS,
responseHeaders);
HeaderUtils.copyResponseTransportHeaders(responseHeaders, response);
} catch (Exception e) {
e.printStackTrace();
getLogger()
.log(Level.FINE,
"An error occured during the processing of the HTTP response.",
e);
response.setStatus(Status.CONNECTOR_ERROR_INTERNAL, e);
}
}
/**
* Converts a low-level HTTP call into a high-level uniform call.
*
* @param client
* The HTTP client that will handle the call.
* @param request
* The high-level request.
* @return A new high-level uniform call.
*/
public ClientCall toSpecific(HttpClientHelper client, Request request) {
// Create the low-level HTTP client call
ClientCall result = client.create(request);
// Add the headers
if (result != null) {
HeaderUtils.addGeneralHeaders(request, result.getRequestHeaders());
if (request.getEntity() != null) {
HeaderUtils.addEntityHeaders(request.getEntity(),
result.getRequestHeaders());
}
// NOTE: This must stay at the end because the AWS challenge
// scheme requires access to all HTTP headers
HeaderUtils.addRequestHeaders(request, result.getRequestHeaders());
}
return result;
}
/**
* Updates the response with information from the lower-level HTTP client
* call.
*
* @param response
* The response to update.
* @param status
* The response status to apply.
* @param httpCall
* The source HTTP client call.
* @throws IOException
*/
public void updateResponse(Response response, Status status,
ClientCall httpCall) {
// Send the request to the client
response.setStatus(status);
// Get the server address
response.getServerInfo().setAddress(httpCall.getServerAddress());
response.getServerInfo().setPort(httpCall.getServerPort());
// Read the response headers
readResponseHeaders(httpCall, response);
// Set the entity
response.setEntity(httpCall.getResponseEntity(response));
// Release the representation's content for some obvious cases
if (response.getEntity() != null) {
if (response.getEntity().getSize() == 0) {
response.getEntity().release();
} else if (response.getRequest().getMethod().equals(Method.HEAD)) {
response.getEntity().release();
} else if (response.getStatus().equals(Status.SUCCESS_NO_CONTENT)) {
response.getEntity().release();
} else if (response.getStatus()
.equals(Status.SUCCESS_RESET_CONTENT)) {
response.getEntity().release();
response.setEntity(null);
} else if (response.getStatus().equals(
Status.REDIRECTION_NOT_MODIFIED)) {
response.getEntity().release();
} else if (response.getStatus().isInformational()) {
response.getEntity().release();
response.setEntity(null);
}
}
}
}