9. Java Developers Guide

9.1. Preface

9.1.1. Overview

This guide provides information about how to use the rasdaman database management system. The booklet explains usage of rasj, the rasdaman Java API.

Follow the instructions in this guide as you develop your application which makes use of rasdaman services. Explanations detail how, from within a Java program, to create databases, collections, and instances; how to retrieve from databases; how to manipulate and delete instances within databases; how to influence physical storage parameters; how to do transaction handling and other administrative tasks.

9.1.2. Audience

The information in this manual is intended for application developers.

9.1.3. Rasdaman Documentation Set

This manual should be read in conjunction with the complete rasdaman documentation set which this guide is part of. The documentation set in its completeness covers all important infor­mat­ion needed to work with the rasdaman system, such as programming and query access to databases, guidance to utilities such as raswct, release notes, and additional information on the rasdaman wiki.

The rasdaman Documentation Set consists of the following docu­ments:

  • Installation and Administration Guide

  • Query Language Guide

  • C++ Developer’s Guide

  • Java Developer’s Guide

  • raswct Developer’s Guide

  • the rasdaman wiki, accessible at www.rasdaman.org

9.2. Introduction

See the corresponding Introduction Section in the rasdaman Query Language Guide.

9.3. Terminology

See the corresponding Terminology Section in the rasdaman Query Language Guide.

9.4. Application Examples

9.4.1. Overview

This section contains an example of using the rasdaman Java API. The intention is, for the advanced programmer, to quickly get an overview on the programming style to be observed.

The source code can be found (slightly extended) in subdirectory $RMANHOME/share/rasdaman/examples/java of the rasdaman distribution directory.

For details on the operational semantics of the rasdaman data model the reader is strongly encouraged to study the rasdaman Query Language Guide.

9.4.2. Application Program Example Code

import rasj.*;
import rasj.odmg.*;
import org.odmg.*;
import java.util.*;

/** Example Java program for computing the avg cell value
 * for each n-D 8-bit grey image in a given collection.
 * set the server name with -server, the database name with -database,
 * the collection name with -collection,
 * the port number with -port, the user login with -user,
 * the password with -passwd
 */
public class AvgCell {
    public static void main(String[] args) {
        String server = "localhost";
        String base = "RASBASE";
        String coll = "mr";
        String port = "7001";
        String user = "rasguest";
        String passwd = "rasguest";

        double sum;

        for (int i = args.length - 1; i >= 0; i--) {
            //System.out.println(args[i]);
            if (args[i].equals("-server")) {
                server = args[i + 1];
            }
            if (args[i].equals("-database")) {
                base = args[i + 1];
            }
            if (args[i].equals("-collection")) {
                coll = args[i + 1];
            }
            if (args[i].equals("-port")) {
                port = args[i + 1];
            }
            if (args[i].equals("-user")) {
                user = args[i + 1];
            }
            if (args[i].equals("-passwd")) {
                passwd = args[i + 1];
            }
        }
        //System.out.println(server+base+coll+port+user+passwd);

        DBag resultBag = null;
        RasGMArray result = null;
        Transaction myTa = null;
        Database myDb = null;
        OQLQuery myQu = null;

        try {
            Implementation myApp = new RasImplementation(
                                        "http://" + server + ":" + port);
            ((RasImplementation)myApp).setUserIdentification(user, passwd);
            myDb = myApp.newDatabase();

            System.out.println("Opening database ...");
            myDb.open(base, Database.OPEN_READ_ONLY);

            System.out.println("Starting transaction ...");
            myTa = myApp.newTransaction();
            myTa.begin();

            System.out.println("Retrieving MDDs ...");
            myQu = myApp.newOQLQuery();
            myQu.create("select img from " + coll + " as img");
            resultBag = (DBag)myQu.execute();
            if (resultBag != null) {
                Iterator iter = resultBag.iterator();
                while (iter.hasNext()) {
                    result = (RasGMArray)iter.next();
                    System.out.println(result);
                    if (result.getTypeLength() != 1) {
                        System.out.println("skipping image because"
                                + " of non-int cell type");
                    } else {
                        byte[] pixelfield = result.getArray();
                        sum = 0.0;
                        long size = result.getArraySize();
                        for (int i = 0; i < size; i++) {
                            sum += pixelfield[i];
                        }
                        System.out.println("Avarage over " + size + " pixels is "
                                + ((sum / size) + 128));
                    }

                }
                System.out.println("All results");
            }

            System.out.println("Committing transaction ...");
            myTa.commit();

            System.out.println("Closing database ...");
            myDb.close();

        } catch (org.odmg.ODMGException e) {
            System.out.println("An exception has occurred: " + e.getMessage());
            System.out.println("Try to abort the transaction ...");
            if (myTa != null) {
                myTa.abort();
            }

            try {
                System.out.println("Try to close the database ...");
                if (myDb != null) {
                    myDb.close();
                }
            } catch (org.odmg.ODMGException exp) {
                System.err.println("Could not close the database: "
                        + exp.getMessage());
            }
        }
        System.out.println("Done.");
    }
}

Note

This sample program makes use of the mr collection provided with the rasdaman distribution package. See the rasdaman Installation and Administration Guide to learn on how to create this collection as part of the demonstration database.

9.5. rasj

9.5.1. Overview

The rasj package contains the API for Java-based access to the rasdaman database system. It relies on the ODMG standard which it implements to the extent that is necessary for raster data management.

The overall rasj package is subdivided into two packages, rasj and org.odmg. The org.odmg sub-package (see ODMG) implements the general ODMG specifications while the rasj sub-package implements rasdaman specific features.

9.5.2. Class Hierarchy

Note

All class hierarchies are generated from the rasj javadoc, which can be built in the java/ directory with

mvn javadoc:javadoc

This generates a javadoc folder in the build directory (build/java/target/site/apidocs/rasj). Then, a commandline tool named w3m is used to dump the tree structure in HTML format of a package to text in console, example:

w3m -dump build/java/target/site/apidocs/rasj/package-tree.html

The rasj class hierarchy has the following structure.

* java.lang.Object
    * rasj.RasFastScale (implements rasj.global.RasGlobalDefs)
    * rasj.RasImplementation (implements org.odmg.Implementation)
    * rasj.RasMInterval
    * rasj.odmg.RasObject (implements rasj.global.RasGlobalDefs)
        * rasj.RasGMArray (implements rasj.global.RasGlobalDefs)
            * rasj.RasMArrayByte
            * rasj.RasMArrayDouble
            * rasj.RasMArrayFloat
            * rasj.RasMArrayInteger
            * rasj.RasMArrayLong
            * rasj.RasMArrayShort
    * rasj.RasPoint
    * rasj.RasSInterval
    * rasj.RasStorageLayout
    * rasj.RasStructure
    * rasj.RasType
        * rasj.RasBaseType
            * rasj.RasPrimitiveType (implements rasj.global.RasGlobalDefs)
            * rasj.RasStructureType
        * rasj.RasCollectionType
        * rasj.RasMArrayType
        * rasj.RasMIntervalType
        * rasj.RasOIDType
        * rasj.RasPointType
        * rasj.RasSIntervalType
    * java.lang.Throwable (implements java.io.Serializable)
        * java.lang.Exception
            * org.odmg.ODMGException
                * org.odmg.QueryException
                    * org.odmg.QueryInvalidException
                        * rasj.RasQueryExecutionFailedException
            * rasj.RasException
                * rasj.RasDimensionMismatchException
                * rasj.RasIndexOutOfBoundsException
                * rasj.RasResultIsNoCellException
                * rasj.RasResultIsNoIntervalException
                * rasj.RasStreamInputOverflowException
                * rasj.RasTypeInvalidException
            * java.lang.RuntimeException
                * org.odmg.ODMGRuntimeException
                    * rasj.RasConnectionFailedException
                * rasj.RasRuntimeException
                    * rasj.RasClientInternalException
                    * rasj.RasIllegalULongValueException
                    * rasj.RasIllegalUShortValueException
                    * rasj.RasInvalidNameException
                    * rasj.RasTypeNotSupportedException
                    * rasj.RasTypeUnknownException

9.5.3. Interface Hierarchy

The complete rasj interface hierarchy has the following structure.

* org.odmg.Implementation
    * rasj.RasImplementationInterface

9.6. ODMG

9.6.1. Overview

The ODMG classes implement classes defined in the ODMG standard providing functionality such as database open and close, transactions, querying, and unique identifiers, i.e., OIDs.

Don’t Use DArray!

ODMG defines an interface DArray which also is part of the ODMG sub-package provided with the rasdaman distribution. These implement only 1-D arrays; most important, however, DArray is *not compatible* with rasdaman arrays. Therefore, *do not use* class DArray as a rasdaman array, but use class RasGMArray (and its subclasses) instead.

...But Do Use Dbag!

Queries return multi-sets as results. A bag or multi-set contains an arbitrary number of elements; like a set (and unlike a list), no particular sequence is defined, and like a list (and unlike a set), the same elements can occur multiply. The query result type, therefore, is DBag. See also Storage Layout.

9.6.2. Class Hierarchy

The complete org.odmg class hierarchy has the following structure.

* java.lang.Object
    * java.lang.Throwable (implements java.io.Serializable)
        * java.lang.Exception
            * org.odmg.ODMGException
                * org.odmg.DatabaseNotFoundException
                * org.odmg.DatabaseOpenException
                * org.odmg.ObjectNameNotFoundException
                * org.odmg.ObjectNameNotUniqueException
                * org.odmg.QueryException
                    * org.odmg.QueryInvalidException
                    * org.odmg.QueryParameterCountInvalidException
                    * org.odmg.QueryParameterTypeInvalidException
            * java.lang.RuntimeException
                * org.odmg.ODMGRuntimeException
                    * org.odmg.ClassNotPersistenceCapableException
                    * org.odmg.DatabaseClosedException
                    * org.odmg.DatabaseIsReadOnlyException
                    * org.odmg.LockNotGrantedException
                    * org.odmg.NotImplementedException
                    * org.odmg.ObjectDeletedException
                    * org.odmg.ObjectNotPersistentException
                    * org.odmg.TransactionAbortedException
                    * org.odmg.TransactionInProgressException
                    * org.odmg.TransactionNotInProgressException

9.6.3. Interface Hierarchy

This is the org.odmg interface hierarchy:

* org.odmg.Database
* org.odmg.Implementation
* java.lang.Iterable<T>
    * java.util.Collection<E>
        * org.odmg.DCollection
            * org.odmg.DArray (also extends java.util.List<E>)
            * org.odmg.DBag
            * org.odmg.DList (also extends java.util.List<E>)
            * org.odmg.DSet (also extends java.util.Set<E>)
        * java.util.List<E>
            * org.odmg.DArray (also extends org.odmg.DCollection)
            * org.odmg.DList (also extends org.odmg.DCollection)
        * java.util.Set<E>
            * org.odmg.DSet (also extends org.odmg.DCollection)
* java.util.Map<K,V>
    * org.odmg.DMap
* org.odmg.OQLQuery
* org.odmg.Transaction

9.6.4. How To Use

The following code piece demonstrates a typical retrieval situation: a database is opened with username and password, a transaction is started, and then a query is executed against that database.

Transaction myTa = null;
Database myDb = null;
OQLQuery myQu = null;
DBag resultSet = null;
RasGMArray result = null;

Implementation myApp = new RasImplementation("http://" + server + port );
((RasImplementation)myApp).setUserIdentification(user, passwd);
myDb = myApp.newDatabase();
myDb.open( database, Database.OPEN_READ_ONLY );

myTa = myApp.newTransaction();
myTa.begin();

myQu = myApp.newOQLQuery();
myQu.create( "select mr from mr" );
resultSet = (DBag) myQu.execute();

// ...result set processing...

myTa.commit();
myDb.close();

Database Login

The database name and the address of a running server manager must be indicated. Further optional parameters and their defaults are:

  • login (default: "rasguest")

  • password (default: "rasguest")

Multiple ODMG Implementations

It is well possible to use several implementations - for example, from different vendors - of the ODMG classes simultaneously. Like rasj, other ODMG packages will provide an Implementation class in their org.odmg package. Instantiating one Implementation for each pack­age is the only prerequisite to be done. The resulting code might look like the following (incomplete) example fragment where two different implementation classes are assumed, RasImplementation and Implementation2; note that transactions for different implement­ations are independent from each other.

Transaction myTa1 = null;
Database myDb1 = null;

Transaction myTa2 = null;
Database myDb2 = null;

Implementation rasApp1 = new RasImplementation( "http://" + server1 + ":" + port1 );
((RasImplementation)rasApp1).setUserIdentification(user, passwd);
myDb1 = myApp1.newDatabase();
myDb1.open( rasbase, Database.OPEN_READ_ONLY );
MyTa1 = myApp1.newTransaction();
myTa1.begin();

Implementation2 myApp2 = new Implementation2( "http://" + server2 + ":" + port2 );
((RasImplementation)myApp2).setUserIdentification(user, passwd);
myDb2 = myApp2.newDatabase();
myDb2.open( database2, Database.OPEN_READ_ONLY );
MyTa2 = myApp2.newTransaction();
myTa2.begin();

// ...now access both databases...

myTa1.commit();
myDb1.close();

myTa2.commit();
myDb2.close();

ODMG Functions Available

rasj does not implement ODMG fully (this would go beyond its purpose), rather it contains those functions necessary for rasdaman database access. When using the HTML hypertext documentation, clicking through the org.odmg package ultimately gets you to the rasdaman classes which implement the corresponding ODMG class. There, methods not available are marked as such.

Further Information

Details on how to process the query result can be found in Storage Layout. The example code makes use of the demonstration database whose set-up routines are part of the distribution package; find more on this topic in the rasdaman Installation and Administration Guide.

9.7. Points and Intervals

9.7.1. Overview

Point and interval handling is needed for indexing arrays, such as in­dication of array boundaries. To this end, classes RasPoint, RasS­Interval, and RasMInterval for n-dimensional points, 1-D (“single-“) intervals, and n-dimensional (“multi-“) intervals resp. are provided.

Value Ranges and Consistency Constraints

All points, 1-D and n-D intervals can span negative values as well. Furthermore, intervals can have any integer value as lower bound. This is in contrast to most programming languages where usually the lower bound is fixed to 0.

However, intervals obviously need to match some consistency criteria to be valid. Foremostly, in a 1-D interval (class RasSInterval) as well as in an n-D interval (class RasMInterval) the lower bound must not be higher than the upper bound.

Further, operations between intervals of any type must yield a valid interval again. Consider the union of two 1-D intervals s1 and s2,

s1.unionWith( s2 )

Intervals s1 and s2 must be overlap or at least be adjacent, otherwise the resulting interval would contain a hole (mathematically speaking, it would not be simply connected). As such situations are not allowed for intervals in rasdaman, corresponding exceptions will be thrown by rasj.

If nevertheless two intervals should be merged which are apart from each other, then operation closureWith() can be used. It will “fill” the gap between the intervals so that a valid result interval comes out.

The HTML manual lists each possible situation. It is recommended to study this for getting an understanding of all valid and invalid interval combinations.

9.7.2. Class Hierarchy

* java.lang.Object
    * rasj.RasPoint
    * rasj.RasSInterval
    * rasj.RasMInterval

Note

Class java.lang.Object obviously has further subclasses, not just the one shown here.

9.7.3. How To Use

Here are some sample code fragments showing usage of the point and interval classes:

RasPoint

// (1) point instantiation using string constructor:
RasPoint p1 = new RasPoint( "[ 3, 7 ]" );
// (2) point instantiation using numerical constructor:
RasPoint p2 = new RasPoint( 5, 0 );

// get point dimension:
int d = p2.dimension();

// test if points are equal:
boolean b = p1.equals( p2 );

RasSInterval

// create a 1-D intervals (100,200) and (-150,400), resp.:
RasSInterval s1 = new RasSInterval( 100, 200 );
RasSInterval s2 = new RasSInterval( "-150:400" );
// no "[" and "]" !

// get upper bound of interval:
long hiBound = s2.high();
// get lower bound of interval:
long loBound = s2.low();

// test if interval intersects with another interval
// (the return value shows the kind of intersection)
int j = s1.intersectsWith( s2 );

RasMInterval

// create new 2-D interval, set bounds to (-1,1) and (3,7):
RasMInterval m1 = new RasMInterval( "[ -1:1, 3:7 ]" );
// create a 4-D interval, leaving open array bounds for now:
RasMInterval m2 = new RasMInterval( 4 );

// get number of cells:
long noOfCells = m1.cellCount();

9.8. Multidimensional Arrays

9.8.1. Overview

Instances of RasGMArray and its subclasses represent multidimensional arrays. To handle arrays with different base types and geometries, the “implements” relation of Java is used. With this approach, greyscale images, RGB images etc. can all be treated as subclasses of the general array class RasGMArray.

Currently supported are types for integer arrays (e.g., grayscale images) of various cell size, as well as types for floating-point arrays with single and double precision. All of them allow arrays of any dimension and extent per dimension.

Class Hierarchy

* rasj.odmg.RasObject (implements rasj.global.RasGlobalDefs)
    * rasj.RasGMArray (implements rasj.global.RasGlobalDefs)
        * rasj.RasMArrayByte
        * rasj.RasMArrayDouble
        * rasj.RasMArrayFloat
        * rasj.RasMArrayInteger
        * rasj.RasMArrayLong
        * rasj.RasMArrayShort

9.8.2. How To Use

A few code fragments will show appropriate usage of the array classes. To keep it brief and to the spot, we omit declarations and other standard steps; these can be looked up in the previous, complete coding examples.

Note: Current restriction

Queries can contain formal parameters, denoted by $1, $2, etc. (see Query Language Guide for details). In the current rasj implem­ent­at­ion, only one MDD object can be bound per query (however, it is possible to bind several scalar values). This limitation will be overcome in future releases.

Example 1: compute summary data from array

The following code example retrieves all MDD objects from a sample collection and, fore each object, computes the average cell value. As a safeguard, averaging is carried out only in case of integer cells (i.e., greyscale pixels).

myQu = myApp.newOQLQuery();
myQu.create( "select mr from mr" );
DBag resultSet = (DBag) myQu.execute();
if (resultSet != null)
{
    Iterator iter = resultSet.iterator();
    while (iter.hasNext())
    {
        result = (RasGMArray) iter.next();
        if(result.getTypeLength() != 1)
            System.out.println("skipping image because of non-int cell type" );
        else
        {
            byte[] pixelfield = result.getArray();
            double sum = 0.0;
            long size = result.getArraySize();
            for(int i=0; i<size; i++)
            sum += pixelfield[i];
            System.out.println( "Average over " + size +
            " pixels is " +
            ((sum/size)+128) );
        }
    }
}

Example 2: set up array object in main memory

The following code fragment instantiates a RasGMArray object as a 2-D greyscale image and fills it with values using the normal Java means:

// create 2-D MDD with cell length 1, i.e., type "byte":
RasGMArray myMDD = new RasGMArray(new RasMInterval( "[1:400,1:400]"), 1 );
// byte container for array data, matching in size:
byte[] mydata = new byte[160000];

// initialize array as all-black with two grey stripes:
for(int y=0; y<400; y++)
{
    for(int x=0; x<400; x++)
    {
        if((x>99 && x<151) || (x>299 && x<351))
            mydata[y*399+x]=100;
        else
            mydata[y*399+x]=0;
    }
}

// now insert byte array into MDD object
// (sets only the pointer, no copying takes place!):
myMDD.setArray(mydata);

As for the last line containing the import of array data into the MDD object, observe the following: There are specific get/set functions for the various supported array types, e.g., getIntArray(). While the setArray() and getArray() methods always will work, they will require data type conversion if the actual array cell type is not “byte”. Therefore, it is most efficient to always use that operation which respects the actual array data type.

The following code fragment instantiates a RasGMArray object as a 2-D greyscale image and fills it with values using the normal Java means:

Example 3: insert new array object into database

This example generates a new greyscale image collection named test in the database and inserts an image into this database collection.

Note that a new query object has to be generated for each query. It is not sufficient to just change the query string in the query object!

// set up query object for collection creation:
myQu.create( "create collection test GreySet" );
// set the object type name (used for server type checking):
myMDD.setObjectTypeName( "GreyImage" );
// finally, execute "create collection" statement:
myQu.execute();

// now create the insert statement:
myQu.create( "insert into test values $1" );
// let the server generate a new OID for the object to be
// inserted, and remember this OID locally:
myNewOID = myApp.getObjectId( myMDD );
// bind the MDD value which substitutes formal parameter $1:
myQu.bind( myMDD );
// ...and ship the complete statement to the server:
myQu.execute();

9.8.3. rasdaman Cell Types

The set of cell base types known to rasdaman encompasses the usual numeric types. Below find the table of types known, and the necessary information to map them to Java types.

Null values, i.e., values of cells which have not been assigned a value yet, always are the numerical zero value of the corresponding type. This extends in the obvious way to composite cells.

Rasdaman

Length

Description

octet

8 bit

signed integer

char

8 bit

unsigned integer

short

16 bit

signed integer

unsigned short

16 bit

unsigned integer

long

32 bit

signed integer

unsigned long

32 bit

unsigned integer

float

32 bit

single precision floating point

double

64 bit

double precision floating point

boolean

1 bit 1

true (nonzero value) false (zero value)

9.8.4. rasdaman Types vs. Java Types

Java types do not 1:1 correspond to rasdaman types. This is due to the fact that the Java type system in some aspects is different from what the ODMG Standard prescribes. Below find the most important caveats.

Long Integer

Long integer values in rasdaman always have 4 bytes, in accordance with the ODMG standard. The corresponding rasdaman types are Ras_Long and Ras_ULong.

In rasj, the array type to be used for 4-byte integers is RasMArrayInteger which matches with the Java int type occupying 4 bytes.

Mind that the Java type long represents 8 byte quantities. If an MDD object is passed to the database through rasj, a overflow test takes place on each integer value. An exception is thrown on overflow.

Unsigned Integers

Special care should be taken with unsigned integers, as Java does not support this. For example, for cells of type Ras_UShort (2 bytes) the array type RasMArrayInteger (4 bytes) must be used to collate values, according to the ODMG standard.

9.9. Storage Layout

9.9.1. Overview

At insertion time of an MDD object, several database-internal storage parameters can be set to affect the way the object is stored in the database. A RasStorageLayout object, attached to a RasGMArray MDD object, will guide storage of this MDD object when passed to the server through RasOQLQuery.execute().

9.9.2. Class Hierarchy

* java.lang.Object
    * rasj.RasStorageLayout

9.9.3. How To Use

The following code fragment shows how to associate a storage layout object with an MDD object; the storage layout will be evaluated at insertion time of the MDD into the database.

// create 2-D MDD with cell length 1, i.e., type byte:
RasGMArray myMDD =
new RasGMArray(new RasMInterval( "[1:400,1:400]" ), 1 );

// assume that there is some byte array prepared, insert it:
myMDD.setArray( mydata );

// set image type name
myMDD.setObjectTypeName("GreyImage");

// add storage layout object:
RasStorageLayout myLayout = new RasStorageLayout();

// now you can set either TileSize or TileDomain; to this
// end, continue with Alternative 1 or 2, as described below

Alternative 1: set tile size

Having prepared the object as described above, now the tiling strategy can be set. Experience tells that a good size for tiles is 4 MB, but bear in mind that the optimal size for tiles depends on the actual user behaviour as well as various system parameters.

// define size of tiles as 128,000 bytes:
myLayout.setTileSize( 128000 );
myMDD.setStorageLayout( myLayout );

Alternative 2: set domain shape

As an alternative to setting the overall tile size, the domain can be prescribed. This is more exact, as it allows to define not only size, but also the extent per dimension. For example, if it is known from the user access patterns there are ten times as much vertical slices requested than are horizontal ones, then it may be a good strategy to define tiles with a vertical:horizontal ratio of 10 to 1.

// define tiles with spatial extent [1:1000,1:100]:
myLayout.setTileDomain("[1:1000,1:100]");
myMDD.setStorageLayout( myLayout );

Note

rasdaman also allows to set the storage and compression format, as well as client/server transfer format. However, currently the interface controlling these parameters is only available via the C++ interface, not yet via Java. In future versions format and compression control will be available via Java, too.

9.10. Collections and Queries

9.10.1. Overview

Bag versus Set

Queries return multi-sets as results. The corresponding query result type is DBag.

A bag or multi-set is a collection of elements similar to sets an lists; like a set (and unlike a list), no particular sequence is defined, and like a list (and unlike a set), the same elements can occur multiply. While {1,2,3} is an example for a set, [1,2,2,3] is a bag example; [1,2,3] denotes the same bag as [3,2,1], because sequence is irrelevant in a bag.

Let us clarify the difference with an example. A query which returns the object identifiers (OIDs) of some database objects, such as

select oid(a)
from a

never will contain duplicates, as OIDs are unique by definition On the other hand, requesting summary information on MDD objects may well lead to duplicates; for example, in a query like this:

select avg_cells(a)
from a

several objects may share the same maximum or average cell value. In the latter case, it obviously is crucial to obtain duplicates also. Therefore, the query result always is DBag, which forms a particular subclass of the general class DCollection.

Nevertheless, we will use the term result set sometimes, as it is just common database speak.

Important Hint

Use org.odmg.DBag, do not use rasj.odmg.RasBag!

9.10.2. Class Hierarchy

* java.lang.Iterable<T>
    * java.util.Collection<E>
        * org.odmg.DCollection
            * org.odmg.DArray (also extends java.util.List<E>)
            * org.odmg.DBag
            * org.odmg.DList (also extends java.util.List<E>)
            * org.odmg.DSet (also extends java.util.Set<E>)
        * java.util.List<E>
            * org.odmg.DArray (also extends org.odmg.DCollection)
            * org.odmg.DList (also extends org.odmg.DCollection)
        * java.util.Set<E>
            * org.odmg.DSet (also extends org.odmg.DCollection)

9.10.3. How To Use

The following code piece demonstrates how to use object sets in the typical case of querying the database and piecewise processing the result set:

OQLQuery myQu = myApp.newOQLQuery();
myQu.create( "select mr from mr" );
DBag resultSet = (DBag) myQu.execute();
if (resultSet != null)
{
    Iterator iter = resultSet.iterator();
    while ( iter.hasNext() )
    {
        RasGMArray result = (RasGMArray) iter.next();
        // ...here now process result...
    }
}

Synchronous query execution

When a query is sent to the rasdaman server it will be executed in completeness - a running query cannot be aborted 2. Care should be taken therefore not to start queries requir­ing resources beyond the capability of the server hardware and soft­ware environment, as the rasdaman service may be blocked for an indefinite time period.

9.10.4. Query Result Type

Database collections satisfy some criterion of homogeneity; this common property is expressed through the underlying type definition. Likewise, a collection returned as a query result has such an underlying common type definition. However, as queries dynamically describe and instantiate structures, this may not always adhere to some type existing in the database - sometimes the structure is new, so a type structure has to be generated “on the fly”. While such a type does not have a name, its structure is well defined through the query itself.

This dynamic typing is predefined in the ODMG standard to which rasj adheres, so further information can be obtained there.

To access cells from arrays in query result bags, accessor functions are provided, such as getObject(), getInteger(). These functions are super­vised by the type checking mechanism, hence using a function on an in appropriate type will cause an exception of type ClassCast­Exception.

Generally speaking, it is up to the application to know the result type structure of the query it has sent to the server.

9.11. OIDs

9.11.1. Overview

The class RasOID manages object identifiers (OIDs) for persistent MDD and collections.

9.11.2. Class Hierarchy

* java.lang.Object
    * rasj.odmg.RasOID

Note

Class java.lang.Object obviously has further subclasses, not just the one shown here.

9.11.3. How To Use

The following code fragment prints the OID for each object in a query result set.

myQu = myApp.newOQLQuery();
myQu.create( "select mr from mr" );
DBag resultSet = (DBag) myQu.execute();
if (resultSet != null)
{
    Iterator iter = resultSet.iterator();
    while ( iter.hasNext() )
    {
        RasGMArray result = (RasGMArray) iter.next();
        System.out.println( "<"
        + result.getOID().getSystemName() + "|"
        + result.getOID().getBaseName() + "|"
        + result.getOID().getLocalOID() + " >" );
        // last statement is equivalent to:
        // System.out.println( getObjectId( result ) );
    }
}

9.12. Type Management

9.12.1. Overview

rasdaman allows to define new types during runtime of the system. This is in contrast to programming languages where type structures are fixed at compilation time. rasdaman, therefore, offers separate mechanisms to maintain database types; these are provided through the RasType class and its subclasses. For each structure relevant in dealing with persistent (i.e., database stored) entities, a corresponding type class is provided.

Note

Right now, rasj does not allow to create and manipulate persistent types in the database; methods provided mainly serve to inquire the result type of a query for a maximum of code flexibility. Database type manipulation can be done through rasql queries, for more details see Type Definition Using rasql.

9.12.2. Class Hierarchy

* java.lang.Object
    * rasj.RasType
        * rasj.RasBaseType
            * rasj.RasPrimitiveType (implements rasj.global.RasGlobalDefs)
            * rasj.RasStructureType
        * rasj.RasCollectionType
        * rasj.RasMArrayType
        * rasj.RasMIntervalType
        * rasj.RasOIDType
        * rasj.RasPointType
        * rasj.RasSIntervalType

9.12.3. How To Use

The following code piece demonstrates how the type structure given by some RasType object can be evaluated and printed in a user-friendly form.

// instantiate a sample MDD type object:
RasType rType = RasType.getAnyType( "marray <char, 1>" );

// Now let's forget again that we know rType, let's analyse.
// Check if the type object is some MDD type:
if (rType.getClass().getName().equals("rasj.RasMArrayType"))
{
    // yes, it is an MDD; is it structured or simple?
    if (rType.isStructType())
    {
        // yes, structured:
        System.out.println( "Structured base type is: " +
        rType.getBaseType() );
    }
    else
    {
        // no, atomic:
        System.out.println( "Atomic base type is: " +
        rType.getBaseType() );
    }
}
else
{
    // no, not an MDD at all.
    System.out.println(
    "type object doesn't describe an MArray." );
}

9.13. Exceptions

9.13.1. Overview

Exceptions serve to handle deviations from the desired flow of operation. Several exceptions can be thrown by rasj classes; as a general rule, all exceptions are subclassed from the general Java exception class java.lang.Exception. Exceptions are further grouped into four main classes

  • org.odmg.Exception

  • java.lang.Runtime­Exception

  • rasj.RasException

  • rasj.RasRuntimeException.

See the HTML documentation for details on the exception class hierarchy.

9.13.2. Class Hierarchy (pruned)

* java.lang.Object
    * java.lang.Throwable (implements java.io.Serializable)
        * java.lang.Exception
            * org.odmg.ODMGException
            * rasj.RasException
            * java.lang.RuntimeException
                * org.odmg.ODMGRuntimeException
                * rasj.RasRuntimeException

Note

All classes have further subclasses See Class Hierarchy and Class Hierarchy for more information.

9.13.3. Handling Exceptions in the Client

Catching an exception can be done, for example, as shown below. Obviously there are several ways doing this - however, a few rules should be obeyed:

  • Granularity of exception catching depends on the overall program structure and purpose. For example, for data insertion one may want to build not just one large transaction, but several smaller units which, in case of failure, can be rerun with less time expenditure.

  • Don’t forget to clean up program state during exception recovery - think of closing (aborting? committing?) transactions, closing the database, etc.

Sample exception handling code

The following code piece demonstrates simple exception handling. The whole database access code is wrapped into a try statement. In case of an exception, the corresponding catch statement attempts to abort the transaction (if any is open) and to close the database. If in the course of these actions another exception occurs (for example, because the communication line has broken down), an error message is generated and the program terminates.

try
{
    Implementation myApp = new RasImplementation( "http://" + server + port );
    ((RasImplementation)myApp).setUserIdentification(user, passwd);
    myDb = myApp.newDatabase();
    myDb.open(base, Database.OPEN_READ_ONLY);
    myTa = myApp.newTransaction();
    myTa.begin();
    // here do some work with the database
    myTa.commit();
    myDb.close();
}
catch ( java.lang.Exception e ) // catch any error
{
    System.out.println( e.getMessage() );
    try
    {
        if(myTa != null)
            myTa.abort();
        if(myDb != null)
            myDb.close();
    }
    catch ( org.odmg.ODMGException exp ) // catch an abort
                                         // or close error
    {
        System.err.println( "Cannot commit/close: " + exp.getMessage());
    }
}

9.13.4. Exceptions in the Class rasj.RasException

The following exceptions are rasj specific:

RasDimensionMismatchException

The dimensions of the two operand objects do not match.

RasIndexOutOfBoundsException

The specified index is not within the bounds of the array indexed.

RasResultIsNoCellException

The operation result is no cell, but an array cell is expected at this position. This happens, e.g., if the cast operator for casting to the base type of class RasGMarray is invoked on an object which is not ‘zero-dimensional’.

RasResultIsNoIntervalException

The result is no interval, but an interval is expected at this position.

RasStreamInputOverflowException

An initialization overflow occured. This happens, e.g., if the stream input operator is invoked more often than the object has dimensions.

RasTypeInvalidException

Access method does not fit base type.

9.13.5. Exceptions in the Class org.odmg.QueryInvalidException

RasQueryExecutionFailedException

This exception extends ODMGQueryInvalidException by offering direct access to the rasdaman error number and the line, column and token in the query string that produced the error.

9.13.6. Exceptions in the Class org.odmg.ODMGRuntimeException

RasConnectionFailedException

This exception is raised when the connection to the server fails.

9.13.7. Exceptions in the Class rasj.RasRuntimeException

RasClientInternalException

This runtime exception indicates an internal error on client side which cannot be solved by the user. In case of such an event, send a report to your dealer containing the complete error message and a precise description of the actions that lead to this exception.

RasTypeNotSupportedException

This exception is raised when the base type of a query result is not supported by the current version of the rasj package.

RasTypeUnknownException

This exception is raised when the base type of a query result is unknown on client-side.

RasInvalidNameException

This exception is thrown if an object name contains invalid characters.

RasIllegalULongValueException

Thrown if a RasMArrayLong is trying to be sent to the server where one or more cell values are out of the range of 32-bit unsigned integers.

RasIllegalUShortValueException

Thrown if a RasMArrayShort is trying to be sent to the server where one or more cell values are out of the range of 16-bit unsigned integers.

9.14. Compilation and Execution of Client Programs

9.14.1. Compiling Code Using rasj

Environment Variables

The CLASSPATH variable - which is used by the Java compiler to locate packages used - must be extended with the path for the rasj directory of the rasdaman distribution. This can be done, e.g., with the following command:

export CLASSPATH=$RMANHOME/lib/rasj.jar;$CLASSPATH

Alternatively, the -classpath or -cp option of javac can be used to explicitly make known the package locations to the Java compiler.

Further, the JDK class directory must be contained in CLASSPATH, and the JDK binaries directory must be contained in the PATH variable.

Java sources making use of the rasj package are compiled and run as usual. For example, a source file Lookup.java containing class Lookup would be compiled as

javac Lookup.java

Running it as an application would be done through this command line statement:

java Lookup

Sample Programs

Several sample Java programs are provided as part of the rasdaman distribution; they are located in the $RMANHOME/share/rasdaman/examples/java directory of the distribution.

Web Servlets and Applications

rasj allows to build applications written in Java which can be web servlets as well as applications. See petascope for example Geo Services Guide.

Notes

Remember the uppercase/lowercase distinction of Java!

For all classes with package definitions - such as rasj.RasGMArray - the package name must be prefixed.

9.14.2. Java Version Compatibility Statement

rasj has been successfully tested with JDK versions 1.7+.

9.14.3. HTTP communication

rasj internally uses HTTP to communicate with the rasdaman server. By selecting individual URLs and ports in the database open statement (see ODMG), safe database access across firewalls is possible.

9.15. HTML Documentation

The implementation is described in extensive documentation integ­rated with the source code from which a set of HTML files. This documentation can be used with any Web browser. The entry point for the complete documentation pages, including the rasj part, is doc/index.html in the rasdaman distribution directory (see Server Architecture).

ODMG Class Availability

Note that the org.odmg package is taken verbatim from the ODMG standard. rasdaman interface classes are derived as implementations of the standard classes. However, only those classes have been implemented which are necessary for rasdaman. If in doubt, the Implementation section should be consulted where unavailable items are marked (due to copyright restrictions, the ODMG text must remain unchanged).

1

memory usage is one byte per pixel

2

This has nothing to do with transactions - after each completion of a query, the embracing transaction can be aborted indeed.