Persistence of Spatial Data
Background

DataNucleus-Spatial allows the use of DataNucleus as persistence layer for geospatial applications in an environment that supports the OGC SFA specification. It allows the persistence of the Java geometry types from the JTS topology suite as well as those from the PostGIS project.

In this tutorial, we perform the basic persistence operations over spatial types using Postgres and Postgis products.

  1. Step 1 : Install the database server and spatial extensions.
  2. Step 2 : Download DataNucleus and PostGis libraries.
  3. Step 3 : Design and implement the persistent data model.
  4. Step 4 : Design and implement the persistent code.
  5. Step 5 : Run your application.


Step 1 : Install the database server and spatial extensions

Download Postgresql database and Postgis. Install Postgress and PostGis. During PostGis installation, you will be asked to select the database schema where the spatial extensions will be enabled. You will use this schema to run the tutorial application.



Step 2 : Download DataNucleus and PostGis libraries

Download the DataNucleus Core, RDBMS and Spatial libraries and any dependencies. Configure your development environment by adding the PostGis and JDO2/JPA1 jars to the classpath.

Step 3 : Design and implement the persistent data model

package org.datanucleus.samples.spatial.tutorial;

import org.postgis.Point;

public class Position
{
    private String name;

    private Point point;

    public Position(String name, Point point)
    {
        this.name = name;
        this.point = point;
    }

    public String getName()
    {
        return name;
    }
    
    public Point getPoint()
    {
        return point;
    }
    
    public String toString()
    {
        return "[name] "+ name + " [point] "+point;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jdo SYSTEM "file:/javax/jdo/jdo.dtd">
<jdo>
	<package name="org.datanucleus.samples.spatial.tutorial">

		<extension vendor-name="datanucleus" key="spatial-dimension" value="2"/>
		<extension vendor-name="datanucleus" key="spatial-srid" value="4326"/>
	
		<class name="Position" table="spatialpostut" detachable="true">
			<field name="name"/>
			<field name="point" persistence-modifier="persistent"/>
		</class>
	</package>
</jdo>

The above JDO metadata has two extensions spatial-dimension and spatial-srid . These settings specifies the format of the spatial data. SRID stands for spatial referencing system identifier and Dimension the number of coordinates.



Step 4 : Design and implement the persistent code

In this tutorial, we query for all locations where the distance is lower than 12 to the home position.

package org.datanucleus.samples.spatial.tutorial;

import java.sql.SQLException;
import java.util.List;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.postgis.Point;

public class Main
{
    public static void main(String args[]) throws SQLException
    {
        // Create a PersistenceManagerFactory for this datastore
        PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("datanucleus.properties");

        System.out.println("DataNucleus Spatial Tutorial");
        System.out.println("=====================");

        // Persistence of a Product and a Book.
        PersistenceManager pm = pmf.getPersistenceManager();
        Transaction tx=pm.currentTransaction();
        try
        {
            //create objects
            tx.begin();

            Position[] sps = new Position[3];
            Point[] points = new Point[3];
            points[0] = new Point("SRID=4326;POINT(5 0)");
            points[1] = new Point("SRID=4326;POINT(10 0)");
            points[2] = new Point("SRID=4326;POINT(20 0)");
            sps[0] = new Position("market",points[0]);
            sps[1] = new Position("rent-a-car",points[1]);
            sps[2] = new Position("pizza shop",points[2]);
            Point homepoint = new Point("SRID=4326;POINT(0 0)");
            Position home = new Position("home",homepoint);

            System.out.println("Persisting spatial data...");
            System.out.println(home);
            System.out.println(sps[0]);
            System.out.println(sps[1]);
            System.out.println(sps[2]);
            System.out.println("");

            pm.makePersistentAll(sps);
            pm.makePersistent(home);

            tx.commit();
            
            //query for the distance
            tx.begin();

            Double distance = new Double(12.0);
            System.out.println("Retriving position where distance to home is less than "+distance+" ... Found:");
            
            Query query = pm.newQuery(Position.class, "name != 'home' && Spatial.distance(this.point, :homepoint) < :distance");
            List list = (List) query.execute(homepoint, distance);
            for( int i=0; i<list.size(); i++)
            {
                System.out.println(list.get(i));
            }
            //clean up database.. just for fun :)
            pm.newQuery(Position.class).deletePersistentAll();

            tx.commit();
        }
        finally
        {
            if (tx.isActive())
            {
                tx.rollback();
            }
            pm.close();
        }

        System.out.println("");
        System.out.println("End of Tutorial");
    }
}

We define the file with connection properties to Postgresql:

#database host / ip / database
javax.jdo.option.ConnectionDriverName=org.postgresql.Driver
javax.jdo.option.ConnectionURL=jdbc:postgresql://localhost:5432/postgis
javax.jdo.option.ConnectionURL2=jdbc:postgresql://localhost:5432/postgis
javax.jdo.option.ConnectionUserName=postgres
javax.jdo.option.ConnectionPassword=postgres

javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.jdo.JDOPersistenceManagerFactory
javax.jdo.option.Optimistic=false
javax.jdo.option.IgnoreCache=false
datanucleus.autoCreateTables=true
datanucleus.validateTables=true
datanucleus.autoCreateColumns=true
datanucleus.autoCreateConstraints=true
datanucleus.validateConstraints=true
datanucleus.autoCreateSchema=true


Step 5 : Run your application

Before running the application, you must enhancethe persistent classes. Finally, configure the application classpath with the DataNucleus Core, DataNucleus RDBMS, DataNucleus Spatial, JDO2, Postgres and PostGis libraries and run the application as any other java application.

The output for the application is:

Output :

DataNucleus Spatial Tutorial
=====================
Persisting spatial data...
[name] home [point] SRID=4326;POINT(0 0)
[name] market [point] SRID=4326;POINT(5 0)
[name] rent-a-car [point] SRID=4326;POINT(10 0)
[name] pizza shop [point] SRID=4326;POINT(20 0)

Retriving position where distance to home is less than 12.0 ... Found:
[name] market [point] SRID=4326;POINT(5 0)
[name] rent-a-car [point] SRID=4326;POINT(10 0)

End of Tutorial