GeoServer Manipulation

GeoServer is an open source GIS server that propagates geospatially enabled information. Data is ingested as shapefiles, GeoTIFFs, geospatially enabled databases etc. and then displayed using Open Geospatial Consortium standards, namely WMS and WFS. This allows any software product that has a WMS/WFS ingest to accept these served layers, i.e. Google Earth, OpenLayers, ESRI products.

Many users have run into the issue of updating their GeoServer installation with new data programmatically. There is a partial module for a RESTful configuration, but has not been fully implemented. There is also an excellent code sample here that is the basis for this tutorial. However, with 1.6.0, and the new integrated security subsystem, the code no longer functions properly.

This tutorial will encompass getting the code to work again, as well as going through the process of adding a new GeoServer layer programmatically. This code can be used directly, or adapted to other GeoServer maintenance.

1/2 Workflow:
1. Login.
2. Add CoverageStore.
3. Add Coverage.
4. Apply.
5. Save.
6. Logout.

2/2 Implementation:
This will be done using Java, URL, and URLConnection. I have Java code that runs every fifteen minutes, it pulls satellite raster data (GeoTIFFs) from an outside source, and creates a new GeoServer layer from the new GeoTIFF.

This code can be done with two functions, login() and geoserverAction(String address). Both functions are similar, with the login function catching a cookie which will be put in a global variable, and used during each of the following actions.

Public global variables: geoserverurl, cookieString, geoserverusername, and geoserverpassword.

    public static String login() throws MalformedURLException, IOException {
        String responseString = "";
        InputStream inStream;
        BufferedReader in;
        URLConnection conn;

        URL url = new URL(geoserverurl + "admin/login.do");

        conn = url.openConnection();
        inStream = conn.getInputStream();
        responseString = new String();
        in = new BufferedReader(new InputStreamReader(inStream));

        while (in.ready()) {
            responseString += in.readLine();
        }

        String cookie = conn.getHeaderField("Set-Cookie");
        cookie = cookie.substring(0, cookie.indexOf(";"));
        String cookieName = cookie.substring(0, cookie.indexOf("="));
        String cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
        cookieString = cookieName + "=" + cookieValue;

        return responseString;
    }

Just like in the tutorial from Geoserver, no problem. All println calls have been removed, and cookieString is a global variable that will be accessed by the next function. A cleaner implementation might involve actual passing of the cookie, but this will suffice for tutorial-purposes.

    public static String geoserverAction(String address) 
					throws MalformedURLException, IOException {
        URLConnection conn;
        String responseString = "";
        InputStream inStream;
        BufferedReader in;
        
        URL url = new URL(geoserverurl + address);

        conn = url.openConnection();
        conn.setRequestProperty("Cookie", cookieString);
        conn.connect();

        inStream = conn.getInputStream();
        in = new BufferedReader(new InputStreamReader(inStream));
        responseString = new String();
        while (in.ready()) {
            responseString += in.readLine();
        }
        
        return responseString;
    }

The above function is the “meat” of this code task. From any passed in address, we will be able to fully control GeoServer. The only thing left is to find what addresses are passed around using Firefox’s “Live HTTP headers”.

    private static void addLayer() throws MalformedURLException, IOException {
        login();
	//Creates new instance, catches cookie.

        geoserverAction("j_acegi_security_check?username=" + 
		geoserverusername + "&password=" + geoserverpassword + "&submit=Submit");
		//Actually logs user in.

        geoserverAction("config/data/formatNewSubmit.do?
		selectedDescription=Tagged+Image+File+Format+with+Geographic
		+information&dataFormatID=" + newlayername + "&submit=Submit");
		//New GeoTIFF CoverageStore.

        geoserverAction("config/data/formatSubmit.do?
		enabled=on&namespaceId=topp&type=GeoTIFF&url=file%3Acoverages%2Fhere%2F" 
		+ outfile + "&description=&submit=Submit");
		//Set New CoverageStore's information.

        geoserverAction("config/data/coverageNewSubmit.do?
		selectedNewCoverage=" + newlayername + "&submit=New");
		//New Coverage.

        String urls = coverageSubmitBuilder(newlayername);
	//Populate string.

        geoserverAction("config/data/coverageEditorSubmit.do?" + urls);
	//New Coverage with proper settings.

        geoserverAction("admin/saveToGeoServer.do");
	//Apply.

        geoserverAction("admin/saveToXML.do");
	//Save.

        geoserverAction("admin/logout.do");
	//Logout.
    }

The above code will complete our task. Making the url string for coverageEditorSubmit was highly unweildy, so I made a helper function: coverageSubmitBuilder(), and it can be viewed here.

Possible extensions:
Any task in GeoServer. Using “Live HTTP headers” and stepping through each task manually will give us the information needed to have full and automatic control of GeoServer.

Leave a Reply