# 4ODS Tutorial

Mike Olson
Revision 1.0 (Initial Draft) [MCO]

1. | Introduction
2. | Databases and Transactions
3. | Object Definition Language (ODL)
4. | Objects and pstubs
5. | Extensions and Inheritance
6. | Binding and extents
7. | Collections
8. | Relationships and Object attributes
9. | Type Definitions
10. | Literal Data types
10.1. | Enumerations
10.2. | Structures
10.3. | Unions
10.4. | dates, Times, Intervals, and Timestamps
11. | Operations and Exceptions
12. | Object Query Language (OQL)
13. | Object Interchange Format (OIF)
14. | Advanced Usage
14.1. | Overridding pstubs
14.2. | Overridding literals
14.3. | Multithreaded applications

### Introduction

This document will attempt to walk users of 4ODS through many of the common use cases of working with 4ODS. Each section will describe using a different facet of the library. Each will have a coresponding file of example code that will be referenced and explained.

### Databases and Transactions

4ODS is an object database wrapper around various forms of back end persistent stores. Someday it will have it own storage capabilities, but until then we build off of some of the excelent RDBMS available. Currently we do support connecting to Postgres, Oracles through optimized adapters, and any ODBC compliant database through the ODBC adapter.

Also, because not everyone has Oracle, or Postgres, 4ODS ships with a Dbm driver. This driver works great for simple tasks, but it is not concurrent so don't use it in a multi-threaded application.

To set which driver 4ODS uses, you define the environment variable FTODS_DB_DRIVER to the name of the database adapter. The default is Dbm. To set the driver to Postgres you would issue the following:

    export FTODS_DB_DRIVER=Postgres

or on windows

    set FTODS_DB_DRIVER=Postgres

4ODS has a database object that conforms to the ODMG Database interface. To access the database, import the module Database and create an instance of the database. The database instance is basically a transaction factory. In a ODMG compliant database, there is only on active transaction per thread. This can get a bit confusing some times and we will cover it in more detail in a later sections.

    from Ft.Ods import Database

    db = Database.Database()
    db.open("DBNAME")

    db.close()

You must be very careful to close your database when you are done with it in Python 1.5.2 because it contains circular references with all of the transactions that it creates. In the above code, we created a Database instance, and opened it. The parameter to the open command is the name of the database. The above code will run even if you do not have a database called "DBNAME". This is because 4ODS does not attempt to connect to the database until you begin a transaction.

to create a transaction, you use the "new" interface on a opened database. At this time you will need to make sure that you don't have the environment adapter envinroment variable set, and the Dbm database directory exists. The location of where Dbm will store you data can be found with the following script. You will need to make sure this directory exists and that you have access to it.

    [molson@penny 4Suite]$ python -c "from Ft.Lib import DbmDatabase;print DbmDatabase.DATABASE_DIR"

You will then need to create an empty 4ods database. To do this you can use the command line command. Unless otherwise specified in this tutorial, we will use the name "test" as the name of our database. We will also be reinitializing the database between each demonstration script.

Create a new Database

    4odb create test

Destroy an existing Database

    4odb destroy test

With a new database, we can run the tutorial script transaction.py

transaction.py

    import sys
    from Ft.Ods import Database

    db = Database.Database()
    db.open(sys.argv[1])

    tx = db.new()
    tx.begin()

    #This is where you do all of your transaction processing

    tx.commit()
    db.close()

We would then put our code to access and modify the database inbetween the begin and commit of the transaction. If, after doing your processing, you do not want to commit you changes to the persistent store, you can call abort on the transaction.

### Object Definition Language (ODL)

Before we can use a 4ODS database, we must define what types of objects can be stored in the system. This is very similar to defining your table structure in a RDBMS, or you interfaces in a CORBA system. To perform this task, we use a langauge called ODL. This is very simialr to CORBA's IDL. With it, we can define interfaces, classes, structures, enumerations, unions, collections and more. From this, 4ODS will initialize the database's meta model, and generate a series of "pstubs" (more on these later)

One of the most powerful features of a ODMG compliant database is its ability for introspections. Stored in the database is the entire set of meta relationships defined by the ODL that was used to create the database. A standard set of interfaces is defined for accessing (and on really impressive ODMG systems modifying) the meta model of the system run time. It goes as far as allowing you to use these meta objects in the same transactions as other the pstub objects.

simple.odl

    module Test {

      class Person {
        attribute string name;
        attribute short age;
      };
    };

The above file, simple.odl, is a very simple example of an ODL file, but it will sufice for our current purposes. In it, we define a module and a class. The module is used to scope names, and the class defines an object type that can be stored in the database.

To initialize the "test" database with this ODL, we use the command line script 4odb init. Below is a sample output from a Unix terminal when this is run (Windows output is very similar):

    [molson@penny tutorial]$ 4odb destroy test
    [molson@penny tutorial]$ 4odb create test
    [molson@penny tutorial]$ 4odb init test simple.odl

4ODS comes with a command line tool that allows you to view a 4ODS databases meta model. The command is called "4odb metadig". It takes one parameter, the name of the database to view. Once run, it will prompt you for a name to resolve in the metamodel, then it will pretty print that object. Now is probably a good time to note that the ODMG specification defines that all user objects (defined through ODL) are in a modele called ODLMetaObjects. There for, when we run the metadig command and query the object "ODLMetaObjects" we see a module, with our module (and class) defined inside of it

Output from 4odb metadig test

    [molson@penny tutorial]$ 4odb metadig test
    4ODS MetaDig Tool
    Version 0.11.1b2 Copyright Fourthought, Inc 2001
    >>> ODLMetaObjects
    Module:  ODLMetaObjects
      Name:  ODLMetaObjects
      Comment:  Created by Initialization of Repo
      Defined In: Repository id(2)
      Defines:
        Module:  ODLMetaObjects::Test
          Name:  Test
          Comment:
          Defined In: ODLMetaObjects id(21)
          Defines:
            Class:  ODLMetaObjects::Test::Person
              Extent:  None
              Keys: None
              Extender: None
              Extensions:
                None
              Inherits: None
              Derives: None
              Of Collection:
                None
              Of Specifier:
                None
              Of Union:
                None
              Of Operation:
                None
              Of Property:
                None
              Of constant:
                None
              Of TypeDefs:
                None
              Defines:
                Attribute:  ODLMetaObjects::Test::Person::name
                  is_read_only: 0
                  type:  string
                  Name:  name
                  Comment:
                  Defined In: ODLMetaObjects::Test::Person id(23)
                Attribute:  ODLMetaObjects::Test::Person::age
                  is_read_only: 0
                  type:  short
                  Name:  age
                  Comment:
                  Defined In: ODLMetaObjects::Test::Person id(24)
    >>>

You are not limited by the command line if you want to view the meta model of a database. The Database interface defines a method called "schema". We can use it to get the root of the Meta Model. The next example script metadata.py shows how to do this. It then recursively prints out all of the classes and modeules in the system.

metadata.py

    import sys
    from Ft.Ods import Database
    from Ft.Ods.MetaData import MetaKind

    def pprint(ds,indent = ''):
        print indent + ds.absolute_name()
        for d in ds.defines:
            if d.meta_kind in [MetaKind.mk_module,
                               MetaKind.mk_class]:
                pprint(d,indent + '  ')

    def run():

        db = Database.Database()
        db.open('test')

        tx = db.new()
        tx.begin()

        repo = db.schema()
        pprint(repo)

        tx.abort()
        db.close()

    if __name__ == '__main__':
        run()

metadata.py Output

    [molson@penny tutorial]$ python metadata.py
    Repository
      ODLMetaObjects
        ODLMetaObjects::Test
          ODLMetaObjects::Test::Person
      ODLTypes

### Objects and pstubs

### Extensions and Inheritance

### Binding and extents

### Collections

### Relationships and Object attributes

### Type Definitions

### Literal Data types

#### Enumerations

#### Structures

#### Unions

#### dates, Times, Intervals, and Timestamps

### Operations and Exceptions

### Object Query Language (OQL)

### Object Interchange Format (OIF)

### Advanced Usage

#### Overridding pstubs

#### Overridding literals

#### Multithreaded applications