Create Connections with URLConnection

ZIP file that contains Java code project for this example: JavaApplicationURLConnectionExample.zip

Topic that contains commented Java code for this example: JavaApplicationURLConnectionExample.java

So now we know that Infinity web services send HTTP messages that contain SOAP messages. We use these messages to get information from the application or to ask the application to perform actions. So how to we establish a connection to web services endpoints with Java?

To establish a connection we need to be able to send and receive messages to and from an HTTP or HTTPS URL endpoint. Java provides library that creates connections to URLs. Within the URLConnection class, a HttpURLConnection class contains an HttpsURLConnection class. These types of connection are good candidates.

For further information about URL connections in Java, see:

Are there alternatives? Yes. You could use sockets. These are lower-level TCP and UDP connections. But why go lower when there is a level targeted specifically to the type of endpoint that we want to connect to? You could also use technologies that rest on an implementation of URLConnection, such as Apache HttpClient within HttpComponents. On top of that, an Apache stack called Axis2 partially rests on an implementation of HttpClient. We'll explore those options, but for now, let's stick with a core Java technology.

Here is a Java class to create an HTTP URL connection to an Infinity application Business Operations Services endpoint hosted locally, send a request, and to receive a response:

package javaapplicationurlconnectionexample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class JavaApplicationURLConnectionExample {
     
    public static void main(String[] args) throws MalformedURLException, IOException {
        String urlString = 
"http://localhost/bbAppFx/vpp/bizops/db%5BBBINFINITY%5D/codetables/ADDRESSTYPECODE/soap.asmx";
        URL urlForInfWebSvc = new URL(urlString);
        URLConnection UrlConnInfWebSvc = urlForInfWebSvc.openConnection();
        HttpURLConnection httpUrlConnInfWebSvc = (HttpURLConnection) UrlConnInfWebSvc;
        httpUrlConnInfWebSvc.setDoOutput(true);
        httpUrlConnInfWebSvc.setDoInput(true);
        httpUrlConnInfWebSvc.setAllowUserInteraction(true);
        httpUrlConnInfWebSvc.setRequestMethod("POST");
        httpUrlConnInfWebSvc.setRequestProperty("Host", "localhost");
        httpUrlConnInfWebSvc.setRequestProperty("Content-Type","application/soap+xml; charset=utf-8");
        OutputStreamWriter infWebSvcReqWriter = new OutputStreamWriter(httpUrlConnInfWebSvc.getOutputStream());
        String infWebSvcRequestMessage = 
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
             "  xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
             "  xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">" +
"  <soap12:Body>" +
"    <GetTableEntryListRequest xmlns=\"blackbaud_appfx_server_bizops\">" +
"      <IncludeInactive>true</IncludeInactive>" +
"      <RefreshCache>true</RefreshCache>" +
"    </GetTableEntryListRequest>" +
"  </soap12:Body>" +
"</soap12:Envelope>";
        
        infWebSvcReqWriter.write(infWebSvcRequestMessage);
        infWebSvcReqWriter.flush();
        BufferedReader infWebSvcReplyReader = new BufferedReader(new InputStreamReader(httpUrlConnInfWebSvc.getInputStream()));
        String line;
        String infWebSvcReplyString = "";
        while ((line = infWebSvcReplyReader.readLine()) != null) {
            infWebSvcReplyString = infWebSvcReplyString.concat(line);
            }
        infWebSvcReqWriter.close();
        infWebSvcReplyReader.close();
        httpUrlConnInfWebSvc.disconnect();
        System.out.println(infWebSvcReplyString);
    }
}

Note: SOAP 1.2 message is hard-coded in this example. SOAPAction is not required in the HTTP header for SOAP 1.2 requests.

Tip: We use a Business Operations Service (BizOps) because BizOps handles some difficulties that we would otherwise encounter with Blackbaud AppFx Web Service. However, limitations to the Business Operations Services include the number of features available and the large number of endpoints to keep track of in your client application.

This example is not an effective client application. It only shows that it is possible for a Java application to communicate with an Infinity application through web services. Let's take a closer look.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

Form the package member imports, you can see that the class reads from a buffer, throws, or catches IOException and MalformedURLException, reads and writes to a stream, and uses URLConnection and HTTPConnection. This is a simplified client example. So everything happens in the main method.

Firstly, the program declares a String and assigns it the value of the endpoint URL string. Here are two things to note:

  1. When you look at the URL for that endpoint in the browser's URL field, it appears like this:

    http://localhost/bbAppFx/vpp/bizops/db[BBINFINITY]/codetables/ADDRESSTYPECODE/soap.asmx

    We have to encode the square brackets:

    http://localhost/bbAppFx/vpp/bizops/db%5BBBINFINITY%5D/codetables/ADDRESSTYPECODE/soap.asmx

    The Endpoint Reference does this in the HTTP request line for the generated samples:

    POST /bbAppFx/vpp/bizops/db%5BBBINFINITY%5D/codetables/ADDRESSTYPECODE/soap.asmx HTTP/1.1

    Tip: When you cut and paste the endpoint URL for Business Operations Services, make sure to change the square brackets around the database name to %5B and %5D respectively. This is called percent-encoding.

  2. The String for the BizOps endpoint does not have to contain port information. For example, :80 is not contained in the String.

With the next trio of lines, the program instantiates the objects for the connection using the URL String. This section creates a URLConnection and an HttpURLConnection, casting the URLConnectionto HttpURLConnection.

        URL urlForInfWebSvc = new URL(urlString);
        URLConnection UrlConnInfWebSvc = urlForInfWebSvc.openConnection();
        HttpURLConnection httpUrlConnInfWebSvc = (HttpURLConnection) UrlConnInfWebSvc;

Having created the HttpURLConnection, the program establishes properties for the connection object's input/output properties. The section also sets properties related to the requests the connection sends.

	httpUrlConnInfWebSvc.setDoOutput(true);
        httpUrlConnInfWebSvc.setDoInput(true);
        httpUrlConnInfWebSvc.setAllowUserInteraction(true);
        httpUrlConnInfWebSvc.setRequestMethod("POST");
        httpUrlConnInfWebSvc.setRequestProperty("Host", "localhost");
        httpUrlConnInfWebSvc.setRequestProperty("Content-Type","application/soap+xml; charset=utf-8");

To send the message, the program creates an OutputStreamWriter associated with the output stream for the connection. The writer writes a String to with the writer. The string contains the SOAP message. In this example program, the message is hard-coded. After writing the message, the program flushes the writer.

OutputStreamWriter infWebSvcReqWriter = new OutputStreamWriter(httpUrlConnInfWebSvc.getOutputStream());
        String infWebSvcRequestMessage = 
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
             "  xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
             "  xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">" +
"  <soap12:Body>" +
"    <GetTableEntryListRequest xmlns=\"blackbaud_appfx_server_bizops\">" +
"      <IncludeInactive>true</IncludeInactive>" +
"      <RefreshCache>true</RefreshCache>" +
"    </GetTableEntryListRequest>" +
"  </soap12:Body>" +
"</soap12:Envelope>";
        
        infWebSvcReqWriter.write(infWebSvcRequestMessage);
        infWebSvcReqWriter.flush();

To receive the message, the program creates a BufferedReader associated with the input stream for the connection. The program uses a while loop to iterate through reading each line of the message. The program appends each line to another String that holds the entire message after every line is read.

	BufferedReader infWebSvcReplyReader = new BufferedReader(new InputStreamReader(httpUrlConnInfWebSvc.getInputStream()));
        String line;
        String infWebSvcReplyString = "";
        while ((line = infWebSvcReplyReader.readLine()) != null) {
            infWebSvcReplyString = infWebSvcReplyString.concat(line);
            }

The program cleans up the reader, writer, and the connection.

        infWebSvcReqWriter.close();
        infWebSvcReplyReader.close();
        httpUrlConnInfWebSvc.disconnect();

The program prints the reply message to the output buffer.

System.out.println(infWebSvcReplyString);

Here is an example of the output in NetBeans:

Formatting the XML for the reply with a Visual Studio editor yields this:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <GetTableEntryListReply xmlns="blackbaud_appfx_server_bizops">
      <StatusOK>true</StatusOK>
      <StatusCode>200</StatusCode>
      <StatusMessage>OK</StatusMessage>
      <Rows>
        <TableEntryListRow>
          <ID>144f6283-b479-48fb-97fe-9444abb6d8a5</ID>
          <Description>Billing</Description>
          <Sequence>1</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>2e05bc62-2d51-47a5-b7a0-8ac0d4243caf</ID>
          <Description>Business</Description>
          <Sequence>2</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>578306f0-9b37-47d4-8185-05380b66cbc8</ID>
          <Description>Employment History</Description>
          <Sequence>3</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>46f09a15-665f-4517-b0d9-e5dee3db63ad</ID>
          <Description>Former Address</Description>
          <Sequence>4</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>e4906793-821f-49b9-b9b7-9bfefa6c6165</ID>
          <Description>Home</Description>
          <Sequence>5</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>b8b8d7a0-852c-4760-a25f-8eaeab6aba43</ID>
          <Description>Invalid</Description>
          <Sequence>6</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>3e495340-f4b7-488b-8669-53e742ebe30d</ID>
          <Description>Relationship</Description>
          <Sequence>7</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>8100ea3d-a5ea-48ef-bd01-f655464b5f1b</ID>
          <Description>Rental Property</Description>
          <Sequence>8</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>c0150cc4-b2ee-43d5-87fb-cfbd4738268a</ID>
          <Description>Retreat</Description>
          <Sequence>9</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>3fa6b4ca-7031-4ffd-9c84-5931c3d42abd</ID>
          <Description>School Residence</Description>
          <Sequence>10</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>de66c7fa-a24a-46b4-b4c0-9f863f4a1ac1</ID>
          <Description>Shipping</Description>
          <Sequence>11</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>22dd9406-5f74-472c-bb80-3c1e8ec527bc</ID>
          <Description>Spouse Business</Description>
          <Sequence>12</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>0701a2fc-9d35-4c55-96c8-5f18f7fa1b8c</ID>
          <Description>Summer Home</Description>
          <Sequence>13</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>06c30b72-d9f8-4590-92bf-f2e674c0cd30</ID>
          <Description>Time Share</Description>
          <Sequence>14</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>2d8e0e37-e93c-4e67-9080-55843c597f18</ID>
          <Description>Vacation Home</Description>
          <Sequence>15</Sequence>
        </TableEntryListRow>
        <TableEntryListRow>
          <ID>8f76cb82-9f01-45c0-bf09-1041d00ae052</ID>
          <Description>Winter Home</Description>
          <Sequence>16</Sequence>
        </TableEntryListRow>
      </Rows>
      <UserDefinedSort>true</UserDefinedSort>
    </GetTableEntryListReply>
  </soap:Body>
</soap:Envelope>