Thursday, May 24, 2012

Running GDAL Java

The GDAL Java bindings work very well, but the documentation is very very limited.
The API documentation is much better that the one in python, but it's quite difficult to find how to run a simple example.

Installation (Ubuntu)

In the Ubuntu distribution, there is a GDAL package, but the java bindings are not included. So it's necessary to compile the libraries to have it. 
If you have the gdal libraries already installed from the packages, is not necessary to remove them, since you can use just the compiled jar with the old libraries.
Before compiling, make sure that swig, libgeos-dev and proj4 packages are installed.
The, just run:
./configure --with-java --with-static-proj4=[path_to_libproj.la]
make
 
Go to  the /path_to_gdal/swig/java directory and edit the file java.opt to set the correct JAVA_HOME variable, which is set to a Windows installation by default.
Then type make.
The gdal.jar file will be in the /path_to_gdal/swig/java directory.
The official docs to install the GDAL Java bindings are here: http://trac.osgeo.org/gdal/wiki/GdalOgrInJavaBuildInstructionsUnix

Running the classes

GDAL java bindings use the native GDAL installation, so they make use of JNI. The Java Virtual Machine must find the GDAL binaries. To do so, an environment variable must be set. Froma the command line in linux, the order would be:
 export LD_LIBRARY_PATH=/path_to/gdal-1.9.0/swig/java
where the path is the one you have compiled.
If any coordinate transformation is used in the code, GDAL must find a file named gcs.csv. To find where is this file, just run:
gdal-config --datadir
Then, set the environment variable:
export GDAL_DATA= /path_to_gdal_data
or, even better, execute directly:
export GDAL_DATA=`gdal-config --datadir`
Don't forget to include the file gdal.jar in the classpath, and the class will run properly.
Anyway, is much easier to use an IDE to code in JAVA. Next two sections explain how.

 Running in Eclipse

Using the Eclipse IDE, is possible to configure the environment variables from the configuration window. To do it, click the small arrow next to the play button, and choose Run Configurations...
Once there, choose the Environment tab and add both GDAL_DATA and LD_LIBRARY_PATH using the new button.


Running in Netbeans

I haven't found a graphical solution for configuring both LD_LIBRARY_PATH and GDAL_DATA with Netbeans.
To set these environment variables, locate and open the file netbeans.conf. In my case (ubuntu 12.04), it was located at the path: /usr/local/netbeans-7.0.1/etc/
Add at the end of the file, the lines

export GDAL_DATA=/path_to/gdal/1.9
export LD_LIBRARY_PATH=/path_to/gdal-1.9.0/swig/java

Running in Apache Tomcat

If you are using Apache Tomcat to serve web pages, reading GIS files with GDAL can be a good idea. As in the other cases,  the environment variables must be set.
Edit /path_to_tomcat/bin/catalina.sh (the path may change depending of your installation), and, as in NetBeans, add the lines:

export GDAL_DATA=/path_to/gdal/1.9
export LD_LIBRARY_PATH=/path_to/gdal-1.9.0/swig/java

The libraries must be installed as shared libraries, or the loading will crash if two instances are generated (a java.lang.UnsatisfiedLinkError will be launched).   So:
  • Create the directory: $CATALINA_HOME/shared/lib
  • Put into this directory the contents of  gdal_home/swig/java, which includes the gdal.jar file
  • Edit catalina.properties (in my case was the one under the conf directory) and change the shared.loader variable as:
    shared.loader=${catalina.home}/shared/lib/gdal.jar

Using Maven

gdal.jar is not in the maven repositories (as far as I know), so it must be added manually. Besides, if gdal has to be used in Tomcat in a specific directory, different from the one in maven.
So the pom.xml file has to be edited in the gdal section like this:
<properties>
   <path.shared.gdal>/path/to/apache-tomcat/shared/lib</path.shared.gdal>
</properties>
     
<dependency>
    <groupid>com.osgeo</groupid>
    <artifactid>gdal</artifactid>
    <version>1.9.0</version>
    <scope>system</scope>
    <systempath>${path.shared.gdal}/gdal.jar</systempath>
</dependency>

  Example class

If you want to check how to run a GDAL java class, you can use this example. The class prints the number of bands of the GIS file passed as a parameter:
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;

/**
 * Test class for GDAL java bindings 
 */
public class Test {
 Dataset hDataset;
 int numBands;
 public Test(String filename){
  gdal.AllRegister();
  hDataset = gdal.Open(filename, gdalconstConstants.GA_ReadOnly);
  this.numBands = hDataset.getRasterCount();
 }
 /**
  * @param args
  */
 public static void main(String[] args) {
  if(args.length == 0){
   System.out.println("You must pass the file name as an argument");
  } else {
  Test instance = new Test(args[0]);
  System.out.println(instance.numBands);
  }
 }
}

9 comments:

  1. Thank you very much for this tutorial but I have one question:

    I still have some errors after following your instructions (GDAL_DATA & LD_LIBRARY_PATH). I include ogr2ogr.java in Eclipse and it tells me that he can't find ogr.DontUseExceptions() or ogr.GeneralCmdLineProcessor() whereas it finds ogr.RegisterAll() for example.

    I work with Ubuntu 10.04 LTS & Eclipse Indigo & Gdal 1.9.0

    Thank you for your help!

    ReplyDelete
  2. Sorry for the delay, I'll try to reproduce your problem.

    ReplyDelete
  3. Well, after looking a little, I've found that:
    *In my Ubuntu 12.04 and gdal 1.9.0, it works ok.
    *The code in the class ogr2ogr.java works without calling ogr.DontUseExceptions() (maybe it changes the behaviour when something goes wrong)
    *I've never understood why is good to use the ogr.GeneralCmdLineProcessor() method, since it only reads the command file arguments, which can be read from String[] args in the main method (I guess I'm missing something, but it would work)

    The methods missing should be located in the file
    gdal-1.9.0/swig/java/org/gdal/ogr/ogr.java
    Have you got them there?

    ReplyDelete
  4. HI ...Am Using eclipse cdt and using GDAL but am getting build error as undefined reference to `GDALAllRegister' Please help me....

    ReplyDelete
  5. I'm sorry Hema, I don't know what can it be, and I can't test it right now. Are you sure you are calling

    gdal.AllRegister(); ?
    This is necessary to load any file (which I find is a bit strange)

    ReplyDelete
  6. hi i am using eclipse neon and using GDAL. After configuring all thing,when running above code i am getting error
    Native library load failed.
    java.lang.UnsatisfiedLinkError: no gdalalljni in java.library.path
    Exception in thread "main" java.lang.UnsatisfiedLinkError: org.gdal.gdal.gdalJNI.AllRegister()V
    at org.gdal.gdal.gdalJNI.AllRegister(Native Method)
    at org.gdal.gdal.gdal.AllRegister(gdal.java:551)
    at abs.my.util.Test.(Test.java:17)
    at abs.my.util.Test.main(Test.java:28)

    ReplyDelete
    Replies
    1. gdalalljni was introduced in Version 2.3, so you need to be sure you have installed that version in your system. I still cannot manage to get it to work, but that Problem was corrected as I installed java 2.2.0 Version (just be sure gdal and gdal java bindings are of the same version).

      Delete
  7. Hi, thanks for taking your time to help other with this.

    I tried to follow your instructions to run GDAL along with Tomcat web server. For my particular case I'm using a Tomcat embedded version (8.0.15). I was not able to find a way to specify the shared libraries either modify the default values of the shipped catalina.properties that are inside the tomcat embedded jar file. My solution was to add the gdal location to the LD_LIBRARY_PATH environment variable and add the gdal jar to the classpath of the command to run the Server launcher code, finally call this method for every StandarContext of the web applications you will deploy: ctx.setDelegate(true);

    Hope that this help some other.

    ReplyDelete