Using the Connection API

Use the Connection API to send a request to a remote resource using the connection infrastructure and obtain a response.

Overview

The Connection API is used to send a request to a remote resource using any protocol supported by the connection infrastructure. The API is included in the zero.core module and has two main classes:

  • zero.core.connection.Connection
  • zero.core.connection.Connection.Response

For an overview of the connection infrastructure and associated topics, see Using the connection infrastructure.

An application uses the Connection class to build and send a request to the named resource. The application is then given a reference to a Connection.Response instance, which it can use to wait for and examine the status and contents of the response.

The Connection class provides the application with two alternative approaches when initiating a request:

  • A collection of static methods, each of which set up, initiate, and send a request in a single method call.
  • A more flexible API in which an application creates a Connection object, sets up the request, and sends it to the target resource in a series of method calls.

Using the static methods is equivalent to sending a simple request that uses the full Connection API. The way in which the application interacts with the Connection.Response object does not depend on the approach taken when sending the request.

Sending requests using the static Connection API

The static methods of the Connection class provide a simple way to send REST-style requests to resources. The following list contains the four basic forms:

  • Connection.Response doGET(String resource, Map<String, List<Object>> headers)
  • Connection.Response doPUT(String resource, Map<String, List<Object>> headers, Object body)
  • Connection.Response doPOST(String resource, Map<String, List<Object>> headers, Object body)
  • Connection.Response doDELETE(String resource, Map<String, List<Object>> headers)

See the API reference for zero.core for more information about these methods.

In addition to the basic forms, the Connection class has overloaded forms that differ in the way the request headers are supplied.

resource
The URL or destination name of the resource to be invoked.
headers
The headers to be sent with the request expressed as a Map of header names and List of associated values. If no request headers are required, the application can supply an empty Map, a null value, or use the overloaded methods that have no headers argument.
body
The body of the request. The supported body types depend on the protocol being used but typically include:
  • String
  • byte[]
  • InputStream
  • Reader

The following code extract shows a simple example in which doGET() is used send an HTTP request to retrieve a resource:

try {
    Connection.Response response = Connection.doGET("http://www.projectzero.org/");
    // work with response headers and body
} catch (Exception e) {
    // handle exceptions
}

The meaning of request headers and the object types supported for the request body depend upon the protocol being used. See Protocol reference for more information.

Sending requests using the full Connection API

The static methods of the Connection class offer a simple way to issue requests and obtain a Connection.Response object. These methods simplify the full Connection API, which can be used by applications in more advanced scenarios. Applications using full Connection API typically follow a common pattern:

  1. Create a new Connection object, specifying a target resource and operation.
  2. Set up any programmatic protocol configuration required by the application.
  3. Set up any request headers that are required.
  4. Set the request body, if applicable to the operation.
  5. Send the request and obtain a reference to a Connection.Response object.

In the example below, the single doGET() call has been replaced with separate statements to create a new Connection object and get the associated Connection.Response object.

try {
    Connection conn = new Connection("http://www.projectzero.org/");
    Connection.Response response = conn.send();
    // work with response headers and body
} catch (Exception e) {
    // handle exceptions
}

The following example uses more methods of the full Connection API to POST a string to a REST service:

try {
    Connection conn = new Connection("http://someHost.projectzero.org/myService",
                                     Connection.Operation.POST);
    conn.addRequestHeader("Content-Type", "text/json; charset=\"UTF-8\"");
    conn.setRequestBody("{\"name\" : \"value\"}");
    Connection.Response resp = conn.send();
    // work with response headers and body
} catch (Exception e) {
    // handle exceptions
}

The meaning of request headers and the object types supported for the request body depend upon the protocol being use. See the Protocol reference for more information.

Creating a Connection object

The Connection class provides two public constructors:

  • Connection(String resource)
  • Connection(String resource, Connection.Operation operation)

See the API reference for zero.core for more information about these methods.

By default, the first form prepares a GET request, but the second allows the operation to be selected from the following values:

  • Connection.Operation.GET
  • Connection.Operation.HEAD
  • Connection.Operation.POST
  • Connection.Operation.PUT
  • Connection.Operation.DELETE

Specifying protocol configuration

Many protocols support configuration parameters that can be applied to a connection request, such as time out values or authentication credentials. An application can supply these protocol configuration values for an individual request using the following method:

  • void setProtocolConfiguration(String protocol, Map<String, Object> parameters)

See the API reference for zero.core for more information about this method.

In the following code extract, the application specifies the http protocol and a value for the associated readTimeout configuration parameter.

    Connection conn = new Connection("http://www.projectzero.org/");
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("readTimeout", 120);
    conn.setProtocolConfiguration("http", parameters);
    Connection.Response resp = conn.send();

The next example is similar to the previous one but a null value is given for the protocol name. Here, the application allows the connection request processing to select the protocol for the request. The readTimeout configuration parameter is applied to the protocol that is selected.

    Connection conn = new Connection("http://www.projectzero.org/");
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("readTimeout", 120);
    conn.setProtocolConfiguration(null, parameters);
    Connection.Response resp = conn.send();

In this third example, the application specifies the event protocol and an empty set of protocol configuration parameters.

    Connection conn = new Connection("myDestination");
    conn.setProtocolConfiguration("event", null);
    Connection.Response resp = conn.send();

Both the protocol name and configuration parameters can be changed during connection request processing by connection handlers and destination configuration, overriding any values specified using setProtocolConfiguration(). For more information about the mechanisms available for protocol configuration, see Configuring protocols. Information about the protocols supplied for use with the Connection API and their configuration parameters can be found in the Protocol reference.

Setting request headers

A Connection object has a number of methods by which request headers can be set:

  • void setRequestHeader(String key, List<Object> values)
  • List<Object> removeRequestHeader(String key)
  • void addRequestHeader(String key, Object value)
  • void addRequestHeaders(Map<String, List<Object>> headers)

See the API reference for zero.core for more information about these methods.

Each header consists of a name, of type String, and a list of associated values, of type List<Object>. The setRequestHeader() and removeRequestHeader() methods replace, or remove, all the values for the named header. However, the addRequestHeader() and addRequestHeaders() methods do not replace any existing header values. If the named headers are already set, these methods append the new values to the end of the list.

The application can only call these methods before the request body has been set. Any subsequent attempts to call one of these methods results in an IllegalStateException being thrown.

Setting the request body

When using the POST or PUT operation, the request body is specified using one of two methods:

  • void setRequestBody(Object body)
  • OutputStream getRequestBodyOutputStream()

See the API reference for zero.core for more information about these methods.

The application uses the setRequestBody() method to supply the message body in a similar way to static form of the Connection API. The supported body types depend on the protocol being used but typically include:

  • String
  • byte[]
  • InputStream
  • Reader

Alternatively, the getRequestBodyOutputStream() method can be used to request an OutputStream in which to write the request body. If this method is used to supply the request body, the application must flush() and close() the request body stream before calling send() to send the request.

The application can only call one of the methods to set the request body for an individual Connection object. Any subsequent attempts to call one of these methods results in an IllegalStateException being thrown.

Sending the request and preparing for the response

The application uses the send() method to cause the request to be sent to the target resource and obtain a reference to the Connection.Response object. The send() method can only be called once.

  • Connection.Response send()
  • See the API reference for zero.core for more information about this method.
  • An application can also use the getResponse() method obtain a reference to the associated Connection.Response object. If the send() has not already been called, the first invocation of getResponse() will automatically call send before returning the Connection.Response object. Subsequent invocations of getResponse() return the same response object instance.

Working with Connection.Response

After using Connection to send a request to a resource, the application is given a reference to a Connection.Response object. For protocols that supply a response to a request, an application can use the methods supplied by Connection.Response to complete the following actions:

  • Examine any protocol-specific status code associated with the response.
  • Examine any response headers.
  • Obtain any response body.

The application is given the Connection.Response reference after the request is sent. Depending on the protocol in use, a response might not have been received from the resource at this time. If the response is still in-flight when the application eventually uses the methods of Connection.Response to examine it, the method call blocks until the required information is available.

Getting the response status

Some connection protocols include a status code with the response. The application can obtain the status code using getResponseStatus(). The result is a string representing the protocol specific status code, or null if none was supplied.

  • String getResponseStatus()

See the API reference for zero.core for more information about this method.

Working with response headers

The following methods of Connection.Response allow an application to examine the headers supplied with the response:

  • Set<String> getResponseHeaderKeys()
  • List<Object> getResponseHeader(String key)

See the API reference for zero.core for more information about these methods.

Response header values are always represented as List objects, regardless of the protocol that has been used. The following code extract extends the doGET() example to display the first value of the response Content-Type header, if the header is present:

try {
    Connection.Response response = Connection.doGET("http://www.projectzero.org/repo");
    List<Object> contentType = resp.getResponseHeader("Content-Type");
    if (contentType != null) {
        System.out.println(contentType.get(0).toString());
    }
    // work with response body
} catch (Exception e) {
    // handle exceptions
}

Obtaining the response body

Connection.Response provides several methods by which the application can obtain the response body, which are summarized in the following list:

  • String getResponseBodyAsString()
  • String getResponseBodyAsString(String charset)
  • byte[] getResponseBodyAsBytes()
  • byte[] getResponseBodyAsBytes(String charset)
  • Reader getResponseBodyReader()
  • Reader getResponseBodyReader(String charset)
  • InputStream getResponseBodyInputStream()
  • InputStream getResponseBodyInputStream(String charset)
  • Object getResponseBody()

See the API reference for zero.core for more information about these methods.

The application can call only one of the preceding methods for an individual Connection.Response object. Any subsequent attempts to call one of these methods results in an IllegalStateException being thrown.

The getResponseBody() method gives access to the response body object returned by the protocol implementation or any configured connection handlers. It is intended for use in advanced applications where such specific access is required. For general scenarios, use the method that converts the body into the form most suitable for the application. This both simplifies the logic and protects the application from implementation or configuration changes that might change the type of the body returned by getResponseBody().

The following extension of the doGET() example uses getResponseBodyAsString() to obtain the response body and writes it to System.out:

try {
    Connection.Response response = Connection.doGET("http://www.projectzero.org/repo");
    List<Object> contentType = response.getResponseHeader("Content-Type");
    if (contentType != null) {
        System.out.println(contentType.get(0).toString());
    }
    System.out.println(response.getResponseBodyAsString());
} catch (Exception e) {
    // handle exceptions
}

Releasing network resources

Any network resources needed to make the connection are automatically released when the application has finished processing the response. It is not normally necessary to call the explicit close() method of the Connection API.

The point at which any network resources are released depends on the application behavior and the protocol being used. Some protocols perform all their processing and release network resources before returning the Connection.Response to the application. For example, the smtp and event protocols behave in this way.

The protocols which inherently provide the response body as an InputStream often retain network resources until the response body has been read fully. An application which obtains the response body as an InputStream or Reader can release any network resources by calling close() on the response body. If the application calls getResponseBodyAsString() or getResponseBodyAsBytes() the stream is automatically closed and any network resources released. For example, the http and ftp protocols behave in this way.

If the application or any configured connection handler fails to close a response body stream, the connection infrastructure automatically releases any remaining network resources when the current application request ends; during requestEnd event processing.

An application can force a connection to be closed immediately by calling the close() method of either the Connection or Connection.Response object. For example, an application that establishes a large number of outbound HTTP connections within a single request can use close() to avoid holding so many outbound network resources.

Sending requests using the PHP API

The zero.php.connection module offers PHP functions to send a request to a remote resource:

  • array connection_get(string url, array headers)
  • array connection_post(string url, array headers, string body)
  • See article Zero specific PHP Function Reference for more information about these functions.
  • These two PHP functions are not fully optimized for other protocols except HTTP and HTTPS, developer should use PHP Java™ bridge on Connection API in PHP.

The following code example uses the connection_get() function to make a HTTP GET method for a resource with a Cache-Control header:

<?php
$response = connection_get('http://acme.com/resources/employees', array('Cache-Control' => 'no-cache'));

// the return value is null if the request failed
if ($response != null && $response['status'] = 200) {
    $content_type = $response['headers']['Content-Type'];
    $response_body = $response['body'];
    // ...
}
?>

Version 1.1.30763