Java tutorial
/** * Copyright 2005-2008 Noelios Technologies. * * The contents of this file are subject to the terms of the following open * source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 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.gnu.org/licenses/lgpl-3.0.html * * You can obtain a copy of the LGPL 2.1 license at * http://www.gnu.org/licenses/lgpl-2.1.html * * You can obtain a copy of the CDDL 1.0 license at * http://www.sun.com/cddl/cddl.html * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royaltee 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 com.noelios.restlet.ext.httpclient; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.logging.Level; import org.apache.commons.httpclient.ConnectMethod; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.methods.OptionsMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.TraceMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.restlet.data.Method; import org.restlet.data.Parameter; import org.restlet.data.Protocol; import org.restlet.data.Request; import org.restlet.data.Status; import org.restlet.resource.Representation; import org.restlet.util.Engine; import org.restlet.util.Series; import com.noelios.restlet.http.HttpClientCall; /** * HTTP client connector call based on Apache HTTP Client's HttpMethod class. * * @author Jerome Louvel */ public class HttpMethodCall extends HttpClientCall { /** The associated HTTP client. */ private volatile HttpClientHelper clientHelper; /** The wrapped HTTP method. */ private volatile HttpMethod httpMethod; /** Indicates if the response headers were added. */ private volatile boolean responseHeadersAdded; /** * Constructor. * * @param helper * The parent HTTP client helper. * @param method * The method name. * @param requestUri * The request URI. * @param hasEntity * Indicates if the call will have an entity to send to the * server. * @throws IOException */ public HttpMethodCall(HttpClientHelper helper, final String method, String requestUri, boolean hasEntity) throws IOException { super(helper, method, requestUri); this.clientHelper = helper; if (requestUri.startsWith("http")) { if (method.equalsIgnoreCase(Method.GET.getName())) { this.httpMethod = new GetMethod(requestUri); } else if (method.equalsIgnoreCase(Method.POST.getName())) { this.httpMethod = new PostMethod(requestUri); } else if (method.equalsIgnoreCase(Method.PUT.getName())) { this.httpMethod = new PutMethod(requestUri); } else if (method.equalsIgnoreCase(Method.HEAD.getName())) { this.httpMethod = new HeadMethod(requestUri); } else if (method.equalsIgnoreCase(Method.DELETE.getName())) { this.httpMethod = new DeleteMethod(requestUri); } else if (method.equalsIgnoreCase(Method.CONNECT.getName())) { final HostConfiguration host = new HostConfiguration(); host.setHost(new URI(requestUri, false)); this.httpMethod = new ConnectMethod(host); } else if (method.equalsIgnoreCase(Method.OPTIONS.getName())) { this.httpMethod = new OptionsMethod(requestUri); } else if (method.equalsIgnoreCase(Method.TRACE.getName())) { this.httpMethod = new TraceMethod(requestUri); } else { this.httpMethod = new EntityEnclosingMethod(requestUri) { @Override public String getName() { return method; } }; } this.httpMethod.setFollowRedirects(this.clientHelper.isFollowRedirects()); this.httpMethod.setDoAuthentication(false); if (this.clientHelper.getRetryHandler() != null) { try { this.httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, Engine.loadClass(this.clientHelper.getRetryHandler()).newInstance()); } catch (Exception e) { this.clientHelper.getLogger().log(Level.WARNING, "An error occurred during the instantiation of the retry handler.", e); } } this.responseHeadersAdded = false; setConfidential(this.httpMethod.getURI().getScheme().equalsIgnoreCase(Protocol.HTTPS.getSchemeName())); } else { throw new IllegalArgumentException("Only HTTP or HTTPS resource URIs are allowed here"); } } /** * Returns the HTTP method. * * @return The HTTP method. */ public HttpMethod getHttpMethod() { return this.httpMethod; } /** * Returns the response reason phrase. * * @return The response reason phrase. */ @Override public String getReasonPhrase() { return getHttpMethod().getStatusText(); } @Override public WritableByteChannel getRequestEntityChannel() { return null; } @Override public OutputStream getRequestEntityStream() { return null; } @Override public OutputStream getRequestHeadStream() { return null; } @Override public ReadableByteChannel getResponseEntityChannel(long size) { return null; } @Override public InputStream getResponseEntityStream(long size) { InputStream result = null; try { // Return a wrapper filter that will release the connection when // needed final InputStream responseBodyAsStream = getHttpMethod().getResponseBodyAsStream(); if (responseBodyAsStream != null) { result = new FilterInputStream(responseBodyAsStream) { @Override public void close() throws IOException { super.close(); getHttpMethod().releaseConnection(); } }; } } catch (IOException ioe) { } return result; } /** * Returns the modifiable list of response headers. * * @return The modifiable list of response headers. */ @Override public Series<Parameter> getResponseHeaders() { final Series<Parameter> result = super.getResponseHeaders(); if (!this.responseHeadersAdded) { for (final Header header : getHttpMethod().getResponseHeaders()) { result.add(header.getName(), header.getValue()); } this.responseHeadersAdded = true; } return result; } /** * Returns the response address.<br> * Corresponds to the IP address of the responding server. * * @return The response address. */ @Override public String getServerAddress() { try { return getHttpMethod().getURI().getHost(); } catch (URIException e) { return null; } } /** * Returns the response status code. * * @return The response status code. */ @Override public int getStatusCode() { return getHttpMethod().getStatusCode(); } /** * Sends the request to the client. Commits the request line, headers and * optional entity and send them over the network. * * @param request * The high-level request. * @return The result status. */ @Override public Status sendRequest(Request request) { Status result = null; try { final Representation entity = request.getEntity(); // Set the request headers for (final Parameter header : getRequestHeaders()) { getHttpMethod().addRequestHeader(header.getName(), header.getValue()); } // For those method that accept enclosing entities, provide it if ((entity != null) && (getHttpMethod() instanceof EntityEnclosingMethod)) { final EntityEnclosingMethod eem = (EntityEnclosingMethod) getHttpMethod(); eem.setRequestEntity(new RequestEntity() { public long getContentLength() { return entity.getSize(); } public String getContentType() { return (entity.getMediaType() != null) ? entity.getMediaType().toString() : null; } public boolean isRepeatable() { return !entity.isTransient(); } public void writeRequest(OutputStream os) throws IOException { entity.write(os); } }); } // Ensure that the connection is active this.clientHelper.getHttpClient().executeMethod(getHttpMethod()); // Now we can access the status code, this MUST happen after closing // any open request stream. result = new Status(getStatusCode(), null, getReasonPhrase(), null); // If there is no response body, immediately release the connection if (getHttpMethod().getResponseBodyAsStream() == null) { getHttpMethod().releaseConnection(); } } catch (IOException ioe) { this.clientHelper.getLogger().log(Level.WARNING, "An error occurred during the communication with the remote HTTP server.", ioe); result = new Status(Status.CONNECTOR_ERROR_COMMUNICATION, ioe); // Release the connection getHttpMethod().releaseConnection(); } return result; } }