From 2737e5f0665c90cee44d7fffbdca41c990152362 Mon Sep 17 00:00:00 2001 From: Oleg Kalnichevski Date: Sat, 4 Feb 2012 16:30:30 +0000 Subject: [PATCH] Updated HttpClient tutorial with 4.2 API changes git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1240534 13f79535-47bb-0310-9956-ffa450edef68 --- src/docbkx/authentication.xml | 56 ++++------- src/docbkx/connmgmt.xml | 84 +++++++---------- src/docbkx/fluent.xml | 169 ++++++++++++++++++++++++++++++++++ src/docbkx/fundamentals.xml | 103 ++++++--------------- src/docbkx/index.xml | 1 + 5 files changed, 248 insertions(+), 165 deletions(-) create mode 100644 src/docbkx/fluent.xml diff --git a/src/docbkx/authentication.xml b/src/docbkx/authentication.xml index 7a59f1a48..29e8f2351 100644 --- a/src/docbkx/authentication.xml +++ b/src/docbkx/authentication.xml @@ -113,7 +113,7 @@ pwd - SPNEGO/Kerberos: + SPNEGO: SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) is a GSSAPI @@ -124,6 +124,12 @@ pwd At present HttpClient only supports the Kerberos sub-mechanism. + + + Kerberos: + Kerberos authentication implementation. + +
@@ -209,7 +215,13 @@ httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref); AuthPolicy.SPNEGO: - SPNEGO/Kerberos authentication + SPNEGO authentication + + + + + AuthPolicy.KERBEROS: + Kerberos authentication @@ -327,12 +339,12 @@ HttpResponse response = httpclient.execute(httpget, localContext); AuthState proxyAuthState = (AuthState) localContext.getAttribute( ClientContext.PROXY_AUTH_STATE); -System.out.println("Proxy auth scope: " + proxyAuthState.getAuthScope()); +System.out.println("Proxy auth state: " + proxyAuthState.getState()); System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme()); System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials()); AuthState targetAuthState = (AuthState) localContext.getAttribute( ClientContext.TARGET_AUTH_STATE); -System.out.println("Target auth scope: " + targetAuthState.getAuthScope()); +System.out.println("Target auth state: " + targetAuthState.getState()); System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme()); System.out.println("Target auth credentials: " + targetAuthState.getCredentials()); ]]> @@ -490,7 +502,7 @@ EntityUtils.consume(entity2); supports SPNEGO authentication more completely. The Sun JRE provides the supporting classes to do nearly all the Kerberos and SPNEGO token handling. This means that a lot of the setup is - for the GSS classes. The NegotiateScheme is a simple class to + for the GSS classes. The SPNegoScheme is a simple class to handle marshalling the tokens and reading and writing the correct headers. The best way to start is to grab the KerberosHttpClient.java file in examples and try and get it to work. There are a lot of issues that can @@ -583,40 +595,6 @@ Value: 0x01 ]]>
-
- Customizing <literal>SPNEGO</literal> authentication scheme - In order to customize SPNEGO support a new instance of - the NegotiateSchemeFactory class must be created and - registered with the authentication scheme registry of HttpClient. - - - There are several options that can be used to customize the behaviour of - NegotiateSchemeFactory. -
- Strip port - Strips the port off service names e.g. - HTTP/webserver.ad.example.net:8080 -> - HTTP/webserver.ad.example.net - Found it useful when authenticating against JBoss Negotiation. -
-
- Custom <literal>SPNEGO</literal> token generator - Use this method to inject a custom - SpnegoTokenGenerator class to do the Kerberos - to SPNEGO token wrapping. - The BouncySpnegoTokenGenerator implementation is provided - as an unsupported contribution from the contrib package. This requires the - BouncyCastle libraries "http://www.bouncycastle.org/java.html". Found especially useful - when using Java 1.5, which is known to provide only a limited support for - SPNEGO authentication. - -
-
diff --git a/src/docbkx/connmgmt.xml b/src/docbkx/connmgmt.xml index c596307a7..839666d24 100644 --- a/src/docbkx/connmgmt.xml +++ b/src/docbkx/connmgmt.xml @@ -270,37 +270,14 @@ sf.connectSocket(socket, address, null, params); javax.net.ssl.SSLContext as a parameter and use it to create custom configured SSL connections.
Simple connection manager - SingleClientConnManager is a simple connection manager that - maintains only one connection at a time. Even though this class is thread-safe it - ought to be used by one execution thread only. - SingleClientConnManager will make an effort to reuse the - connection for subsequent requests with the same route. It will, however, close the - existing connection and re-open it for the given route, if the route of the persistent - connection does not match that of the connection request. If the connection has been - already been allocated, then - java.lang.IllegalStateException is thrown. - SingleClientConnManager is used by HttpClient per + BasicClientConnectionManager is a simple connection manager + that maintains only one connection at a time. Even though this class is thread-safe + it ought to be used by one execution thread only. + BasicClientConnectionManager will make an effort to reuse + the connection for subsequent requests with the same route. It will, however, close + the existing connection and re-open it for the given route, if the route of the + persistent connection does not match that of the connection request. + If the connection has been already been allocated, then + java.lang.IllegalStateException is thrown. + BasicClientConnectionManager is used by HttpClient per default.
Pooling connection manager - ThreadSafeClientConnManager is a more complex + PoolingClientConnectionManager is a more complex implementation that manages a pool of client connections and is able to service connection requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route for which the manager already has a persistent connection available in the pool will be serviced by leasing a connection from the pool rather than creating a brand new connection. - ThreadSafeClientConnManager maintains a maximum limit of + PoolingClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total. For many real-world applications these limits may prove too @@ -573,14 +550,14 @@ schemeRegistry.register( schemeRegistry.register( new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); -ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(schemeRegistry); +PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry); // Increase max total connection to 200 -cm.setMaxTotalConnections(200); +cm.setMaxTotal(200); // Increase default max connection per route to 20 cm.setDefaultMaxPerRoute(20); // Increase max connections for localhost:80 to 50 HttpHost localhost = new HttpHost("locahost", 80); -cm.setMaxForRoute(new HttpRoute(localhost), 50); +cm.setMaxPerRoute(new HttpRoute(localhost), 50); HttpClient httpClient = new DefaultHttpClient(cm); ]]> @@ -604,22 +581,23 @@ httpclient.getConnectionManager().shutdown();
Multithreaded request execution - When equipped with a pooling connection manager such as ThreadSafeClientConnManager, - HttpClient can be used to execute multiple requests simultaneously using multiple - threads of execution. - The ThreadSafeClientConnManager will allocate connections based on - its configuration. If all connections for a given route have already been leased, a - request for a connection will block until a connection is released back to the pool. One - can ensure the connection manager does not block indefinitely in the connection request - operation by setting 'http.conn-manager.timeout' to a positive value. - If the connection request cannot be serviced within the given time period - ConnectionPoolTimeoutException will be thrown. + When equipped with a pooling connection manager such as + PoolingClientConnectionManager, HttpClient can be used to execute multiple + requests simultaneously using multiple threads of execution. + The PoolingClientConnectionManager will allocate connections + based on its configuration. If all connections for a given route have already been + leased, a request for a connection will block until a connection is released back to + the pool. One can ensure the connection manager does not block indefinitely in the + connection request operation by setting 'http.conn-manager.timeout' + to a positive value. If the connection request cannot be serviced within the given time + period ConnectionPoolTimeoutException will be thrown. + + + + + Fluent API +
+ Easy to use facade API + + As of version of 4.2 HttpClient comes with an easy to use facade API based on the concept + of a fluent interface. Fluent facade API exposes only the most fundamental functions of + HttpClient and is intended for simple use cases that do not require the full flexibility of + HttpClient. For instance, fluent facade API relieves the users from having to deal with + connection management and resource deallocation. + + Here are several examples of HTTP requests executed through the HC fluent API + + + + + + + One can also use Executor directly in order to execute requests in + a specific security context whereby authentication details are cached and re-used for + subsequent requests. + + + +
+ Response handling + The fluent facade API generally relieves the users from having to deal with + connection management and resource deallocation. In most cases, though, this comes at + a price of having to buffer content of response messages in memory. It is highly + recommended to use ResponseHandler for HTTP response + processing in order to avoid having to buffer content in memory. + () { + + public Document handleResponse(final HttpResponse response) throws IOException { + StatusLine statusLine = response.getStatusLine(); + HttpEntity entity = response.getEntity(); + if (statusLine.getStatusCode() >= 300) { + throw new HttpResponseException( + statusLine.getStatusCode(), + statusLine.getReasonPhrase()); + } + if (entity == null) { + throw new ClientProtocolException("Response contains no content"); + } + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + ContentType contentType = ContentType.getOrDefault(entity); + if (!contentType.equals(ContentType.APPLICATION_XML)) { + throw new ClientProtocolException("Unexpected content type:" + contentType); + } + String charset = contentType.getCharset(); + if (charset == null) { + charset = HTTP.DEFAULT_CONTENT_CHARSET; + } + return docBuilder.parse(entity.getContent(), charset); + } catch (ParserConfigurationException ex) { + throw new IllegalStateException(ex); + } catch (SAXException ex) { + throw new ClientProtocolException("Malformed XML document", ex); + } + } + + }); +]]> + +
+
+ Asynchronous execution + The fluent facade API can be used to execute multiple requests asynchronously using + background threads. + + > queue = new LinkedList>(); +for (final Request request: requests) { + Future future = async.execute(request, new FutureCallback() { + + public void failed(final Exception ex) { + System.out.println(ex.getMessage() + ": " + request); + } + + public void completed(final Content content) { + System.out.println("Request completed: " + request); + } + + public void cancelled() { + } + + }); + queue.add(future); +} + +// Process the queue +]]> + +
+
+
diff --git a/src/docbkx/fundamentals.xml b/src/docbkx/fundamentals.xml index 15df4c4a5..3135592af 100644 --- a/src/docbkx/fundamentals.xml +++ b/src/docbkx/fundamentals.xml @@ -40,9 +40,10 @@ HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); - int l; - byte[] tmp = new byte[2048]; - while ((l = instream.read(tmp)) != -1) { + try { + // do something useful + } finally { + instream.close(); } } ]]>
@@ -65,28 +66,16 @@ if (entity != null) { HttpGet httpget = new HttpGet( "http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq="); ]]> - HttpClient provides a number of utility methods to simplify creation and - modification of request URIs. - URI can be assembled programmatically: + HttpClient provides URIBuilder utility class to simplify + creation and modification of request URIs. - stdout > - - Query string can also be generated from individual parameters: - qparams = new ArrayList(); -qparams.add(new BasicNameValuePair("q", "httpclient")); -qparams.add(new BasicNameValuePair("btnG", "Google Search")); -qparams.add(new BasicNameValuePair("aq", "f")); -qparams.add(new BasicNameValuePair("oq", null)); -URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search", - URLEncodedUtils.format(qparams, "UTF-8"), null); +URIBuilder builder = new URIBuilder(); +builder.setScheme("http").setHost("www.google.com").setPath("/search") + .setParameter("q", "httpclient") + .setParameter("btnG", "Google Search") + .setParameter("aq", "f") + .setParameter("oq", ""); +URI uri = builder.build(); HttpGet httpget = new HttpGet(uri); System.out.println(httpget.getURI()); ]]> @@ -276,19 +265,16 @@ domain=localhost supplied by the creator of the entity. +System.out.println(EntityUtils.toByteArray(myEntity).length);]]> stdout > @@ -394,7 +380,7 @@ if (entity != null) { FileEntity. HttpEntity class which is self-contained instead of using the generic InputStreamEntity. FileEntity can be a good starting point. -
- Dynamic content entities - Often HTTP entities need to be generated dynamically based a particular - execution context. HttpClient provides support for dynamic entities by using - the EntityTemplate entity class and - ContentProducer interface. Content producers - are objects which produce their content on demand, by writing it out to an - output stream. They are expected to be able produce their content every time - they are requested to do so. So entities created with - EntityTemplate are generally self-contained and - repeatable. - "); - writer.write(" "); - writer.write(" important stuff"); - writer.write(" "); - writer.write(""); - writer.flush(); - } -}; -HttpEntity entity = new EntityTemplate(cp); -HttpPost httppost = new HttpPost("http://localhost/handler.do"); -httppost.setEntity(entity); -]]> -
HTML forms Many applications need to simulate the process of submitting an @@ -659,15 +617,6 @@ Final target: http://www.google.ch target server (i.e. the request has not been fully transmitted to the server). - - HttpClient will automatically retry those methods that have been fully - transmitted to the server, but the server failed to respond with an HTTP - status code (the server simply drops the connection without sending anything - back). In this case it is assumed that the request has not been processed by - the server and the application state has not changed. If this assumption may - not hold true for the web server your application is targeting it is highly - recommended to provide a custom exception handler. -
@@ -688,12 +637,20 @@ HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() { // Do not retry if over max retry count return false; } - if (exception instanceof NoHttpResponseException) { - // Retry if the server dropped connection on us - return true; + if (exception instanceof InterruptedIOException) { + // Timeout + return false; } - if (exception instanceof SSLHandshakeException) { - // Do not retry on SSL handshake exception + if (exception instanceof UnknownHostException) { + // Unknown host + return false; + } + if (exception instanceof ConnectException) { + // Connection refused + return false; + } + if (exception instanceof SSLException) { + // SSL handshake exception return false; } HttpRequest request = (HttpRequest) context.getAttribute( diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml index 7759da143..677f7bc4f 100644 --- a/src/docbkx/index.xml +++ b/src/docbkx/index.xml @@ -66,6 +66,7 @@ +