NatureServe Web Services

Code Sample 1 - Get Data (with Java crash course)

This code sample does nothing more than call a web service and get the raw results. The code for doing this is explained here line for line, for those new to Java. The other samples assume that the Java minutiae are understood.

Specification

This program will call the Global Comprehensive Species Service and retrieve data on the Golden Eagle.

Program Code

Download: Sample1.java
[Right-click and choose either 'Save Target As...' (IE) or 'Save Link As...' (Firefox)]

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
        
public class Sample1 {

    public static void main(String[] args) {
	
    try {
        String url = 
            "https://services.natureserve.org/" +
            "idd/rest/ns/v1.1/globalSpecies/comprehensive";
        String uid = "ELEMENT_GLOBAL.2.100925";
        String nsAccessKeyId = "72ddf45a-c751-44c7-9bca-8db3b4513347";
        
        String request = url;
        request = request + "?";
        request = request + "uid=" + uid;
        request = request + "&";
        request = request + "NSAccessKeyId=" + nsAccessKeyId;

        URL serviceURL = new URL(request);
        InputStream is = serviceURL.openStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        
        StringBuffer response = new StringBuffer();
        String nextLineFromService = br.readLine();
        while (nextLineFromService != null) {
            response.append(nextLineFromService);
            nextLineFromService = br.readLine();
        }
        
        System.out.println(response);
    }
    catch (Exception e) {
        System.out.println(e);
    }
        
    }
}
					

Download and run the code now, to see it working. For help on this, see Running the samples.

Code Breakdown
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
					

Java classes are arranged in 'packages'. java.io is one of these, which holds a set of classes useful for doing input/output operations. If a class isn't part of the defaults setup by Java, you have to tell Java where to look for it. You can do this by specifying the full name of the class each time, which is its package name + its own name, e.g. java.io.BufferedReader. This gets a little tiring to type, however, so the import statement let's you say 'Whenever I refer to BufferedReader, I mean java.io.BufferedReader'. Very few classes contain no imports.

public class Sample1 {
...
}
					

This declares that the class we are defining is called Sample1. Everything inside the braces ({}) is part of the class.

    try {
	...
    }
    catch (Exception e) {
        System.out.println(e);
    }
					

When something goes wrong in Java, an 'exception' is 'thrown'. For instance, if we were to try and tell Java we wanted to go to URL '!@#$@#$@#$@.com', Java would throw an exception which says 'That's not a valid URL!'. In our sample, we tell Java we want to try running the code in braces. If something goes wrong in there, we will catch the thrown exception, call it e and write it out to the screen with System.out.println(e). Exceptions handling is usually more fine grained than our example, but this would clutter the code too much for our purposes.

        String url = 
            "https://services.natureserve.org/" +
            "idd/rest/ns/v1.1/globalSpecies/comprehensive";
        String uid = "ELEMENT_GLOBAL.2.100925";
        String nsAccessKeyId = "72ddf45a-c751-44c7-9bca-8db3b4513347";
					

Here we are just defining some String (text) variables for the service URL and the parameters the service requires. We could have made the user enter these, but it would make the sample more complicated. The derivations are:

url - this is lifted straight from the service description page. It is split into 2 lines with the + because this formats better on screen.

uid - this is the UID for the Golden Eagle. We could have gotten this from NatureServe Explorer, or a lookup service.

nsAccessKeyId - this is the access key copied from the service description page. Please do not use this key for more than running these samples. You should register for your own free key. The example key will be changed at regular intervals, so your code will stop working if you rely on it.

        String request = url;
        request = request + "?";
        request = request + "uid=" + uid;
        request = request + "&";
        request = request + "NSAccessKeyId=" + nsAccessKeyId;
					

Here we build the 'request' that we will send to the web service. This is a standard 'URL + parameters' format, so we start with the URL, add the '?' that separates it from the list of parameters, add the uid parameter decalaration (uid=value), separate this from the next parameter with an '&' and finally add the NSAccessKeyId parameter declaration (NSAccessKeyId=value).

By the time we've finished, request contains the following, which is exactly what we would type into a browser address box (which we could use to test our logic):

https://services.natureserve.org/idd/rest/ns/v1.1/globalSpecies/comprehensive?
uid=ELEMENT_GLOBAL.2.100925&NSAccessKeyId=72ddf45a-c751-44c7-9bca-8db3b4513347

        URL serviceURL = new URL(request);
        InputStream is = serviceURL.openStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
					

Now we connect to the service. First, we tell java that the request we just put together is a URL. Then we 'open a stream' to the serviceURL, i.e., we connect to the service, passing our parameters. A 'stream' in Java is like a pipe connected to a source of data. Data flows down the pipe to our class.

The InputStream is speaks raw binary, so we 'wrap' it in an InputStreamReader, which turns it into characters. NOTE: The "UTF-8" parameter is vital. All NatureServe services encode characters in the 'UTF-8' encoding. If you do not supply this parameter to your InputStreamReader, odd things may happen to accented characters, etc. The services may deliver Spanish or French common names, for instance, which your code would end up misinterpreting.

Although we can now make sense of the flow of isr, we can only read it character by character. For efficiency's sake, we wrap isr in a BufferedReader, which packages the input into lines.

        StringBuffer response = new StringBuffer();
        String nextLineFromService = br.readLine();
        while (nextLineFromService != null) {
            response.append(nextLineFromService);
            nextLineFromService = br.readLine();
        }
        
        System.out.println(response);
					

Now we start to read the response from the service.

We first create a StringBuffer to hold the response. Why not just use a String and keep adding lines to that? A String cannot change once it is created. When we say s = s + "new string", Java makes a whole new string and sets s to it. It does not delete the previous contents of s as part of this operation, so whatever contents s had before we did this hang around in memory (until cleaned up at some point later). If we read thousands of lines of input, this is a LOT of wasted memory. A StringBuffer grows in place. When we append text to it, it just gets longer, so we only ever use as much memory as the contents take up.

The first line of input from the service is then read with br.readLine() and we begin looping to read all the lines from the input. While the line we read isn't null, we know that the input isn't finished, so we keep on appending to the response text.

Finally, once we come to the end of the input, we write the text we've collected to the screen, using System.out.println().

See also

The Technical Library has a list of Java learning resources.

Go to Sample 2 - Get Data and Reformat (with XSLT crash course)