Programming with JViews Maps > Introducing the Main Classes > Readers and Writers > The Oracle Spatial Reader and Writer

The class relationship for the Oracle spatial reader and writer is shown in Figure 1.7.

map_oraclespatial.png

Figure 1.7 Oracle Spatial Reader and Writer UML Diagram

Oracle SDO, or Oracle Spatial, is the spatial extension of Oracle in its version 7.3. This extension has been renamed to Spatial Cartridge in the version 8.0 and has been renamed again to Oracle Spatial in the version 8i.

The classes are based on the relational implementation of Oracle Spatial available since Oracle 7.3. It contains classes that facilitate the use of map data (stored in an Oracle database) in an ILOG JViews application. Oracle Spatial allows you to store georeferenced objects in an Oracle database and to perform spatial queries, such as getting the list of objects that intersect a specific polygon.

Oracle has written two implementations of Oracle Spatial:

The Oracle reader of JViews Maps supports reading and writing data in the relational and the object relational model of Oracle Spatial through two different packages:

The Oracle Spatial Reader and Writer comprises the following classes:

The complete source code for an Oracle Reader demonstration can be found at <installdir>/jviews-maps81/samples/oracle/index.html

Oracle SDO Data Source

The IlvSDODataSource class is a an IlvMapDataSource for reading georeferenced objects from an Oracle SDO (formerly Oracle Spatial) database. It relies on the Oracle SDO API that was introduced in former versions of the JViews Maps product, but wraps up all operations (connecting to database, reading features, rendering them to graphic objects) in a more convenient way.

Reading a Map

Here are the major steps to follow to read a map stored in an Oracle SDO database:

  1. Create a connection to the Oracle database:
String url = "jdbc:oracle:thin:@hostMachine:1529:mySID";	
String userName="login";
String password="pass";
IlvSDOConnection connection = new IlvSDOConnection(url,userName,password);
connection.createConnection();
  1. Create a data source with this connection as a parameter:
// Assume we want to read from an object model Oracle database (not relational)
boolean isObjectModel = true;
 
// we want to fetch layer "MY_LAYER_GEOMETRY"
IlvSDODataSource SDODataSource  = 
new IlvSDODataSource(connection, isObjectModel , "MY_LAYER_GEOMETRY");
To get a list of layers, see Getting a List of Layers.
  1. Set parameters on this data source to use load-on-demand:
boolean useTiling = true;
int rowCount = 5;
int columnCount = 5;
SDODataSource.setTilingParameters(useTiling, rowCount, columnCount);
  1. Connect this data source to the manager of the view:
SDODataSource.setManager(getView().getManager());
  1. Insert the data source into the data source tree. You first need to retrieve the data source model from the property of the manager:
IlvMapDataSourceModel dataSourceModel = IlvMapDataSourceProperty.GetMapDataSourceModel(manager);
dataSourceModel.insert(SDODataSource);
  1. Finally, start the Oracle SDO data source:
SDODataSource.start();
Using Tiling and Multithreading

To benefit from ILOG JViews Maps advanced image tiling capabilities and multithreading, use IlvTiledRasterDataSource in the place of IlvSDODataSource

Note
This assumes that you want to load an SDO layer containing raster objects, SDO_GEORASTER.

The following example shows how to do this:

  1. Instantiate a IlvRasterSDOReader object.
  2. This class extends IlvRasterAbstractReader and holds a list of raster elements. It fetches the following elements from the Oracle DB
IlvSDOConnection SDOConnection; // the connection to your Oracle DB
String layerName;  // the name of the oracle layer containing SDO_GEORASTER
... // Initialize your connection.
IlvRasterSDOReader sdoReader = new
IlvRasterSDOReader(SDOConnection,layerName);
  1. Create an IlvTiledRasterDataSource backed by the reader.
IlvTiledRasterDataSource tiledSource =
IlvRasterDataSourceFactory.buildTiledImageDataSource(
view.getManager(), sdoReader, true,true, null);
  1. Configure the raster datasource, and call the start() method to start data production.
tiledSource.setManager(view.getManager());
tiledSource.start();
Getting a List of Layers

To get a list of layers available in the Oracle database, you can do the following:

String[] layersList = IlvSDOUtil.GetAllLayers(connection.getConnection(),connection.getUser());
layersList = IlvObjectSDOUtil.GetAllLayers(connection.getConnection(),
connection.getUser(), true);

Relational Model Classes

This section covers the following topics:

Classes for Reading Data from an Oracle Spatial Relational Model Database

The reader classes for Oracle SDO relational model (package ilog.views.maps.format.oracle) are:

The IlvSDOFeatureIterator Class

The IlvSDOFeatureIterator class reads data from the result of an SQL query to a relational Oracle Spatial layer and converts them into IlvMapFeature objects. JViews Maps applications can handle Oracle Spatial data using this class in a transparent manner.

The following example of Java code performs a query, loading data from an Oracle Spatial layer named ROADS_SDOGEOM. It includes classes from the java.sql package:

String query = "SELECT * FROM ROADS_SDOGEOM ORDER BY 1, 2, 4 ";
Statement statement = getConnection().createStatement();
ResultSet resultSet = statement.executeQuery(query);
IlvSDOFeatureIterator iterator = new IlvSDOFeatureIterator(resultSet);

The connection variable is a java.sql.Connection object.

The query orders the result using the following three criteria, which must be given in the order indicated:

  1. GID (Geometric ID)
  2. ESEQ (Element Sequence)
  3. SEQ (Row Sequence)

Note
This ordering is necessary for the IlvSDOFeatureIterator to work correctly.

The ResultSet of any query to an Oracle Spatial layer can be used to initialize an IlvSDOFeatureIterator, but all the SDO columns must be in the resultSet (columns defining the GID, ESEQ, ETYPE, SEQ, and the coordinates).

The features returned by this iterator have no attributes. However, the GID of the Oracle Spatial geometry is used as the identifier of each feature and this identifier can be used to retrieve additional attributes from the database. See the method IlvMapFeature.getId().

The IlvSDOLayer Class

This class implements load-on-demand for a relational Oracle Spatial data source. The default implementation takes an Oracle Spatial layer for which a spatial indexation has been performed and reads its content with a tiling equivalent to the Oracle Spatial tiling.

The following example creates an IlvSDOLayer on an Oracle Spatial layer named ROADS:

IlvSDOConnection connection = new IlvSDOConnection(url, userName, password);
IlvSDOLayer layer = new IlvSDOLayer(connection, "ROADS");
manager.addLayer(layer,-1);

The IlvSDOTileLoader Class

This class offers additional possibilities when retrieving data from an Oracle Spatial database. These possibilities are meant as a supplement to the default behavior of IlvSDOLayer. For example, you may want to add filters to a layer or to have a tiling definition that is different than the Oracle tiling.

The example in the file <installdir>/jviews-maps81/samples/oracle/index.html shows how to implement a subclass IlvSDOTileLoader that uses spatial queries to retrieve data for a JViews Maps tile.

The IlvDefaultSDOTileLoader Class

This class is a subclass of IlvSDOTileLoader and is used by the IlvSDOLayer. It has some optimizations. For example, the setTileGroupingCount() method allows you to set the number of tiles that are grouped in one unique query to the database. In fact, each tile corresponds to a Spatial Query. If you have an average of n tiles to load each time you want to load on demand, you should use setTileGroupingCount(n), where all the n queries are grouped into one unique query that is sent to the database.

Note
If you want to handle special operations on each IlvMapFeature retrieved in Load-On-Demand with the IlvSDOLayer layer, you have to subclass the IlvDefaultSDOTileLoader in order to override the getFeatureIterator() method. In this method, you have to return an instance of a subclass of IlvSDOFeatureIterator where you have overridden the getNextFeature() method (inside which you can perform your specific operations on each IlvMapFeature returned by the layer). Finally, you have to set your subclass of IlvDefaultSDOTileLoader as the tile loader of the layer.

Class for Writing Data to an Oracle Spatial Relational Model Database

This section describes the IlvSDOWriter class, that allows you to write map features into a relational Oracle Spatial database.

The IlvSDOWriter Class

The IlvSDOWriter class can write any IlvMapFeatureIterator whose features have a geometry supported by the relational model of Oracle Spatial and write them to the database as in the following example:

IlvSDOWriter writer = 
   new IlvSDOWriter(connection.getConnection()
                   "MyLayer", 
                   16, 
                   new IlvCoordinate(-360d, 90d), 
                   new IlvCoordinate(360d, -90d));
 // Creating a source feature iterator.
 IlvShapeFileReader reader = new IlvShapeFileReader(...);
 // Dumping its content to the Oracle layer.
 writer.writeFeatureIterator(reader);

The write() method of the IlvSDOWriter does not write the attributes of the features. If you want to write the attributes of the features, you can subtype the writeFeature() method of the IlvSDOWriter, after calling super.writeFeature(feature).

The geometries supported by the Oracle Spatial writer are:

Object Relational Model Classes

This section covers the following topics:

Before describing the classes, note the following about coordinate systems.

Since version 8.1.7, Oracle Spatial allows spatial data to be georeferenced. Geometries can be georeferenced by associating a spatial reference ID (SRID) to each geometry. Coordinate systems associated to these SRIDs are defined in the table MDSYS.CS_SRS.

JViews Maps can import these reference systems using their OpenGIS WKT (Well Known Text) specifications, found in the MDSYS.CS_SRS table. If your data is not georeferenced, there is no need to change anything. The JViews Maps classes in the objectmodel package handle both georeferenced and nongeoreferenced data.

For more information, see the Oracle Spatial documentation (Coordinate Systems section) and Handling Spatial Reference Systems.

Classes for Reading Data from an Oracle Spatial Object Relational Model Database

The reader classes for Oracle Spatial Object Relational model included in the package ilog.views.maps.format.oracle.objectmodel are:

The IlvObjectSDOFeatureIterator Class

This class reads data from the result of an SQL query to a relational Oracle Spatial layer and converts the data into IlvMapFeature objects. The JViews Maps package applications can handle Oracle Spatial data using this class in a transparent way. The following example performs a query, loading data from an Oracle Spatial layer named ROADS:

IlvSDOConnection connection = new IlvSDOConnection(url,
                                                   userName,
                                                   password);
connection.createConnection();
IlvObjectSDOFeatureIterator iterator =
   new IlvObjectSDOFeatureIterator(connection.getConnection(),
                                   "select * from ROADS",
                                    // The name of the geometry column.
                                    "GEOMETRY",
                            // No key ID.
                                    null,
                                    // Name of the x-ordinates column.
                                    "X",
                                    // Name of the y-ordinates column.
                                    "Y");

The result set of any query to an Oracle Spatial layer can be used to initialize an IlvObjectSDOFeatureIterator, but the column containing the geometry must be in the result set.

The features returned by the iterator can have attributes and coordinate systems attached.

The IlvObjectSDOLayerMetaData and IlvObjectSDODimElement Classes

These two classes correspond to two data structures defined in Oracle Spatial.

The IlvObjectSDOLayerMetaData class corresponds to the data contained in each row of the (XXX_)SDO_GEOM_METADATA view. This view contains information, called metadata, about Spatial layers. Each Spatial user has the following views available in the schema associated with that user (in Oracle 8.1.6+):

Each metadata view has the following definition:

 TABLE_NAME    VARCHAR2(32),
 COLUMN_NAME   VARCHAR2(32),
 DIMINFO       MDSYS.SDO_DIM_ARRAY,
 SRID          NUMBER

In addition, the ALL_SDO_GEOM_METADATA and DBA_SDO_GEOM_METADATA views have an OWNER column identifying the schema that owns the table specified in TABLE_NAME.

You do not need to build metadata by hand: the IlvObjectSDOUtil.GetLayerMetaData method can help you retrieve the metadata directly from the database. For instance, if a Spatial layer is called ROADS, then you can retrieve its metadata as follows:

IlvObjectSDOLayerMetaData metadata =
 IlvObjectSDOUtil.GetLayerMetaData(connection.getConnection()
                                   "ROADS",
// You can pass the geometry column name as null: the first
// metadata row that matches the layer name "ROADS" is then
// returned.
                                   null,
// You can pass the metadata view name as null: the default
// is "(USER_)SDO_GEOM_METADATA".
                                   null,
// You can pass the owner name as null: the name of the 
// current user is then taken as the owner name.
                                   null);

The IlvObjectSDOLayerMetaData class is then composed of the following elements that match the (XXX_)SDO_GEOM_METADATA view: the table name (the name of the Spatial layer), the geometry column name (called COLUMN_NAME in the view, the name of the column of type MDSYS.SDO_GEOMETRY), the owner name, the optional SRID if the Spatial layer is georeferenced, and an array of IlvObjectSDODimElement (called DIMINFO in the view).

The IlvObjectSDODimElement corresponds to the MDSYS.SDO_DIM_ELEMENT data type. The MDSYS.SDO_DIM_ELEMENT data type is defined in Oracle as:

Create Type SDO_DIM_ELEMENT as OBJECT (
   SDO_DIMNAME  VARCHAR2(64),
   SDO_LB  NUMBER,
   SDO_UB  NUMBER,
   SDO_TOLERANCE  NUMBER);

The DIM element data type describes, for each Spatial Layer, its extent for each dimension. For instance, for typical two-dimensional geometries, the DIM element array of the metadata table has two entries. The first entry describes the first dimension (x, longitude), the second one describes the second dimension (y, latitude).

Note
In the DIM element array of the metadata table, the elements are supposed to be ordered. For example, the first element of the array is considered as the first dimension of the layer, and so on.

The IlvObjectSDOKeyExtractor and IlvDefaultObjectSDOKeyExtractor Classes

The IlvObjectSDOKeyExtractor class is an interface associated with feature iterators and tile loaders. Its main purpose is to associate an object with the map feature read by the iterator or the tile loader.

This object is supposed to be unique, so that the next time the feature iterator meets the object, it is not process the geometry in the corresponding row, considering that this geometry has already been loaded.

The goal is to avoid multiple loading of the same geometry. This interface extracts a key from a ResultSet using the extractKey(java.sql.ResultSet) method. The object returned can be extracted from one Table column or multiple columns as soon as it constitutes a unique object.

multitile.gif

Figure 1.8 Example of Multiple Loading in Load-On-demand

The red rectangle belongs to the tile (2, 2) and (2, 3). When the load method of the tile (2, 2) is called, it loads the rectangle. When the load method of the tile (2, 3) is called, the rectangle is loaded again as soon as it intersects with this tile too, and the tile loader has no way to know that this geometry has already been loaded. You can avoid this by using the IlvObjectSDOKeyExtractor class.

The IlvDefaultObjectSDOKeyExtractor is a default class that implements the key extraction behavior from one Table column. For example, given the previous schema let us suppose that the Spatial Layer is the following:

GEOMETRY  MDSYS.SDO_GEOMETRY,
ID        NUMBER
Note
The ID column does not need to be described in Oracle as a key, when it contains unique values.

The IlvDefaultObjectSDOKeyExtractor used with this layer can be easily obtained in the following way:

IlvDefaultObjectSDOKeyExtractor extractor = 
                  new IlvDefaultObjectSDOKeyExtractor("ID");

Then, this extractor can be associated with an IlvObjectSDOLayer, or an IlvDefaultObjectSDOTileLoader.

IlvObjectSDOLayer layer = 
   new IlvObjectSDOLayer(connection,
                         IlvObjectSDOUtil.GetLayerMetaData(...),
                         1000,
                         1000,
                         "X",
                         "Y",
                         extractor, // used here
                         null);

The IlvObjectSDOLayer Class

This class implements load-on-demand for an object Oracle Spatial data source. The default implementation takes an Oracle Spatial layer for which a spatial indexation has been performed and reads its content.

The following example creates an IlvObjectSDOLayer on an Oracle Spatial layer named ROADS:

IlvSDOConnection connection = new IlvSDOConnection(url,
                                                   userName,
                                                   password);
connection.createConnection();
IlvObjectSDOLayer layer = 
     new IlvObjectSDOLayer(connection,
                           // The name of the SDO layer.
                           "ROADS",
                           // Width of a tile in the database
                           // coordinate system.
                           1500,
                           // Height of a tile in the database
                           // coordinate system.
                           1500,
                                  // Special handling of ID.
                           null //Is not required.
                           );
manager.addLayer(layer,-1);

The IlvDefaultObjectSDOTileLoader Class

This class is a subclass of IlvSDOTileLoader and is used by the IlvObjectSDOLayer. It has some optimizations.

For example, the method setTileGroupingCount() allows you to set the number of tiles that are grouped in one unique query to the database. In fact, each tile corresponds to a Spatial Query, and if you have an average of n tiles to load each time you want to load on demand, you should use setTileGroupingCount(n), where all the n queries are grouped into one unique query that is sent to the database once.

Note
If you want to handle some special operations on each IlvMapFeature retrieved in load-on-demand with the IlvObjectSDOLayer layer, you have to subclass the IlvDefaultObjectSDOTileLoader in order to override the getFeatureIterator method. In this method, you have to return an instance of a subclass of IlvObjectSDOFeatureIterator where you have overridden the getNextFeature method (inside which you can perform your specific operations on each IlvMapFeature returned by the layer). Finally, you have to set your subclass of IlvDefaultObjectSDOTileLoader as the tile loader of the layer.

Another interesting method of this class is the setRequestParameters() method.

This method allows you, for instance, to set the spatial operator used to query the layer. The default operator is SDO_FILTER.

Figure 1.9 shows a Spatial layer using a fixed tiling of level 2. The red rectangle is the area queried by the tile loader. If the SDO_FILTER operator is used (default case), all the geometries belonging to the Oracle Spatial Tiles intersecting with the red rectangle fit the request. In the case of Figure 1.9, all the geometries belonging to the tiles (2,2), (2,3), (3,2), and (3,3), for example the line, the point, the triangle, the circle, and the rectangle are retrieved.

You may not want to retrieve the geometries that do not explicitly intersect with the red rectangle (for example, the circle and the rectangle geometries here). In this case, you have two choices.

Finally, note that the SDO_RELATE Spatial operator is slower than the SDO_FILTER operator.

tiles.gif

Figure 1.9 Tiles
Class for Writing Data to an Oracle Spatial Object Relational Model Database

This section presents the IlvObjectSDOWriter class, which allows you to write map features into an Object Oracle Spatial database.

The class IlvObjectSDOWriter can write any IlvMapFeature or any IlvMapFeatureIterator whose features have a geometry supported by Oracle Spatial 8i (vectorial geometries) and write them to the database as in the following example:

IlvSDOConnection connection = new IlvSDOConnection(url,
                                                   userName,
                                                   password);
connection.createConnection();
IlvObjectSDOWriter writer =
    new IlvObjectSDOWriter(connection.getConnection(),
                           "MyLayer",      // Layer name.
                           "GEOMETRY",     // Geometry column.
                           "X",            // X ordinate name.
                           "Y",            // Y ordinate name.
                           true            // Create table.
);
IlvShapeFileReader reader = new IlvShapeFileReader("foo.shp",null);
int saved_objects_count = writer.writeFeatureIterator(reader,
                                                false,   // No attributes
                                                null     );// No SRID
writer.close(0.0, // Tolerance
             null );// No SRID

Note
In the case of the Oracle Spatial Object Model, some auxiliary tables, like the (USER_)SDO_GEOM_METADATA view, need to be updated. It is very important to call the method IlvObjectSDOWriter.close() once the data has been written through the write() method, so that the database is kept up-to-date.

The writeFeature() method of the IlvObjectSDOWriter can also write the attributes of the feature.

The method writeFeature(IlvMapFeature feature, boolean saveAttributes) has a second argument that can be set to true to save the attributes of the specified map feature. This requires that the map feature has an IlvAttributeInfoProperty correctly set, describing the attributes that match the Oracle Spatial layer column names. This also requires that map feature has an IlvFeatureAttributeProperty that fits its IlvAttributeInfoProperty and has correct values.

For instance, if you have an Oracle Spatial layer called ROADS that has the following description in the database:

Name 
Null? 
Type 

 

 

 
GEOMETRY 

 
MDSYS.SDO_GEOMETRY 
TYPE_DESC 

 
VARCHAR2(512) 

The third argument of the writeFeature() method allows you to set the SDO_SRID value of the written SDO_GEOMETRY. The value of the SDO_SRID is exactly one of the SRID values of the MDSYS.CS_SRS table, and it represents the corresponding coordinate system for the written geometry.

The following code extract shows how to write features with a unique attribute into the database:

IlvSDOConnection connection = new IlvSDOConnection(url,
                                                   userName,
                                                   password);
connection.createConnection();
IlvObjectSDOWriter writer =
   new IlvObjectSDOWriter(connection.getConnection(),
                          "myLayer",
                          "GEOMETRY", "X", "Y", false);
java.lang.String[] names = new String[1];
names[0] = "ATTRIBUTE_NAME";
java.lang.Class[] classes = new Class[1];
classes[0] = java.lang.String.class;
boolean[] nullable = new boolean[1];
nullable[0] = true;
// Creates the attribute info.
IlvAttributeInfoProperty info =
   new IlvAttributeInfoProperty(names, classes, nullable);

// Sets the attribute to feature.
IlvFeatureAttribute[] attributes = new IlvFeatureAttribute[1];
attributes[0] = new IlvStringAttribute("MY FOO TYPE");
IlvFeatureAttributeProperty prop =
    new IlvFeatureAttributeProperty(info,attributes);
feature.setAttributeInfo(info);
feature.setAttributes(prop);

// Writes the feature.
try {
   writer.writeFeature(feature,true, null); // no SRID
} catch (java.sql.SQLException e) {
   // Error.
   e.printStackTrace();
}
writer.close(0.0, null); // no SRID

The writer can update rows in the SDO layer. This is based on a key mechanism, where the row(s) having the value of the given key are updated. The update is done through the following methods from the IlvObjectSDOWriter class:

Oracle SDO Export

In addition to the IlvSDOWriter and IlvObjectSDOWriter classes used to store georeferenced objects to an Oracle database (see The Oracle Spatial Reader and Writer), you can export part of a map to a SDO database using the map export API (see Map Export API). To do so, you just need to set a IlvSDOExporter as the vectorial exporter on the IlvMapExportManager.

IlvMapExportManager exportManager = new IlvMapExportManager();
IlvSDOExporter SDOExporter = new IlvSDOExporter();
exportManager.setVectorialExporter(SDOExporter);
 
// configure SDO export (connection parameters)
SDOExporter.showConfigurationDialog(null);
 
// Set the region of the map to export (here we assume that the map is 
// in IlvGeographicCoordinateSystem.KERNEL system, i.e. in radians)
exportManager.setExportRegion(-Math.PI,-Math.PI/2, Math.PI,Math.PI/2);
 
 
// Export selected map layers of the map (assuming that mapLayersToExport is an array of 
// IlvMapLayer instances)
exportManager.exportMapLayers(mapLayersToExport);