Table of Contents
The Data Object Design Studio (DODS), shown in Figure 1, is a tool which, for the given doml file, can generate SQL script files for creating tables (for each table separately and one cumulative file for creating all tables), one file for deleting all tables, and/or java code for data objects described in the given doml file. DODS also has possibility to compile generated java classes and to parse SQL files (to split cumulative SQL into more separated SQL files using SQLSplitter tool).
![]() |
Figure 1: DODS Generator Wizard
Data objects described in the given DOML file correspond to tables in the database. Each data object has attributes, which describe database columns, and reference attributes, which refer to other data objects. Reference attributes let you create a hierarchy of data objects (for example, many-to-one or many-to-many relationships).
For the given DOML, DODS generates all of the code to implement it. For example:
SQL code to define the database tables
Java code to create the corresponding application data objects
For each data object, DODS generates a set of source files. For example, if your DOML file includes the definition of an entity named "thing," then DODS would generate the following:
A file named thing.sql containing the SQL CREATE TABLE command to construct a table in a relational database.
Java source file defining a data object representing a row in the table.
This class provides a "set" and "get" method for each attribute, methods to handle caching, and is a subclass of the Enhydra framework class GenericDO. In this example, the class would be named ThingDO.
Java source file that defines a query class, which provides SQL query access to the database table.
The query class returns a collection of ThingDO objects that represent the rows found in the table matching criteria passed from the application..
DODS is one part of Enhydra 5.1. If Enhydra 5.1 is installed, so is DODS. In this case, DODS home directory <dods_home> is: <enhydra_home>/dods.
Since this version, DODS has become independent from Enhydra, which means that can be used without it. In this case, DODS home directory <dods_home> is the directory in which independent DODS is installed.
DODS independence is detailly explained in the chapter DODS independence.
Table of Contents
This chapter describes the syntax of DOML files, which are used by the Data Object Design Studio (DODS) to generate data access code for Enhydra applications.
The hierarchy of tags in a DOML file is:
<doml>
<database>
<package>
<package>
....
</package>
<table>
<column>
<type/>
<referenceObject/>
<initialValue/>
<javadoc/>
</column>
<index>
<indexColumn/>
</index>
</table>
</package>
</database>
</doml>
The references of these tags are described in "DOML tag reference" ( html , pdf )
The following snippet shows content of a DOML file, sample.doml, which creates tables containing data about cars, car dealers, and car owners.
<?xml version="1.0"encoding="UTF-8"?>
<doml>
<database database="Standard"templateset="standard">
<package id="sample">
<table id="sample.Dealer">
<column id="Name">
<type dbType="VARCHAR"javaType="String"/>
</column>
</table>
<table id="sample.Owner">
<column id="Name">
<type dbType="VARCHAR"javaType="String"/>
</column>
<column id="Age">
<type dbType="INTEGER"javaType="int"/>
</column>
</table>
<table id="sample.Car">
<column id="LicensePlate">
<type dbType="CHAR"javaType="String"/>
</column>
<column id="Dealer">
<referenceObject reference="sample.Dealer"/>
<type dbType="none"javaType="sample.DealerDO"/>
</column>
</table>
<table id="sample.CarOwner">
<column id="Car">
<referenceObject reference="sample.Car"/>
<type dbType="none"javaType="sample.CarDO"/>
</column>
<column id="Owner">
<referenceObject reference="sample.Owner"/>
<type dbType="none"javaType="sample.OwnerDO"/>
</column>
<column id="IsCurrent">
<type dbType="BIT"javaType="boolean"/>
</column>
<index id="index_1" unique="true">
<indexColumn id="Car"/>
</index>
</table>
</package>
</database>
</doml>
Sample of DOML file for using indexes. Computers.doml in given in <dods_home>/examples/doml_examples directory.
There are two different ways to run dods generator. If you want to start generator quickly, you can start wizard by typing
dods (for Windows)or
./dods (for Linux)without any parameter. Those files are located in
<enhydra_home>/bin folder, for DODS in Enhydra.
<dods_home>/bin folder, for independent DODS
Note:
<enhydra_home>/bin (in the case DODS is used in Enhydra), or <dods_home>/bin folder (for independent DODS) should be added in the system path. Then, DODS can be started from any directory (by typing dods).
If you want to start generator without wizard, you need to type (in the command line) dods with additional parameters. You can find details in the third chapter "Custom Compile" ( html, pdf ) of the document "Starting DODS" ( html , pdf ).
For more details see document "Starting DODS" ( html , pdf ) mentioned previous in this chapter.
Table of Contents
Since this version, DODS is independent from Enhydra. This means that it is possible for user to make any application (it doesn't need to be enhydra application) that can use DODS.
DODS works with DatabaseManagers. DatabaseManager is class that provides facilities for work with databases.
There are two modes of using DODS:
non-threading
In non-threading mode, only one DatabaseManager is used for the whole application, no matter the application has one or more Threads.
threading
In threading mode, there is one DatabaseManager for every Thread. User needs, for every Thread, to define DatabaseManager. If, for any Thread, the DatabaseManager is not defined, the default DatabaseManager is used.
In the following text, the DODS independence is explaned for non-threading mode.
To make non-enhydra application that can use DODS, the following things must be done:
in main application,
add code that makes new DatabaseManager and registers it in DODS:
try {
. . .
String fileName = "discRack.conf";
DatabaseManager dbManager =
StandardDatabaseManager.newInstance(fileName);
DODS.register(dbManager);
. . .
} catch (Exception e) {
e.printStackTrace();
}
where "discRack.conf" is an example of application's configuration file. This file is the same as the Database Manager section of Enhydra application's configuration file.
This file can look like this:
#
# The databases that are used by CSAM. Each of these databases
# has configuration parameters set under DatabaseManager.DB."databaseName".
#
DatabaseManager.Databases[] = "sid1"
#
# The default database used in this application.
#
DatabaseManager.DefaultDatabase = "sid1"
#
# Turn on/off debugging for transactions or queries. Valid values
# are "true" or "false".
#
DatabaseManager.Debug = "false"
#
# The type of database. Normally this is "Standard".
#
DatabaseManager.DB.sid1.ClassType = "Standard"
# DatabaseManager.DB.sid1.ClassType = "Oracle"
#
# The jdbc driver to use.
#
DatabaseManager.DB.sid1.JdbcDriver = "org.enhydra.instantdb.jdbc.idbDriver"
# DatabaseManager.DB.sid1.JdbcDriver = "oracle.jdbc.driver.OracleDriver"
# DatabaseManager.DB.sid1.JdbcDriver = "sun.jdbc.odbc.JdbcOdbcDriver"
#
# Database url.
#
DatabaseManager.DB.sid1.Connection.Url = "jdbc:idb:@OUTPUT@/discRack.prp"
# DatabaseManager.DB.sid1.Connection.Url = "jdbc:oracle:thin:@MyHost:MyPort:MyDBName"
# DatabaseManager.DB.sid1.Connection.Url = "jdbc:odbc:discRack"
#
# Database user name. All connection are allocated by this user.
#
DatabaseManager.DB.sid1.Connection.User = "scott"
#DatabaseManager.DB.sid1.Connection.User = "Admin"
# Database user password.
#
DatabaseManager.DB.sid1.Connection.Password = "tiger"
#DatabaseManager.DB.sid1.Connection.Password = ""
#
# The maximum number of connections that a connection
# pool will hold. If set to zero, then connections
# are allocated indefinitly or until the database
# refuses to allocate any new connections.
#
DatabaseManager.DB.sid1.Connection.MaxPoolSize = 30
#
# Maximum amount of time that a thread will wait for
# a connection from the connection pool before an
# exception is thrown. This will prevent possible dead
# locks. The time out is in milliseconds. If the
# time out is <= zero, the allocation of connections
# will wait indefinitely.
#
DatabaseManager.DB.sid1.Connection.AllocationTimeout = 10000
#
# Used to log database (SQL) activity.
#
DatabaseManager.DB.sid1.Connection.Logging = false
#
# The number of object identifiers that are allocated
# as a group and held in memory. These identifiers
# are assigned to new data objects that are inserted
# into the database.
#
DatabaseManager.DB.sid1.ObjectId.CacheSize = 20
DatabaseManager.DB.sid1.ObjectId.MinValue = 1000000
#
# User wildcards
#
DatabaseManager.DB.User.userWildcard = "*"
DatabaseManager.DB.User.userSingleWildcard = "_"
DatabaseManager.DB.User.userSingleWildcardEscape = "$"
DatabaseManager.DB.User.userWildcardEscape = "$"
#
# Cache configuration
#
DatabaseManager.DB.Cache.defaultMaxCacheSize = 5000
DatabaseManager.DB.Cache.Person.maxCacheSize = -1
DatabaseManager.DB.Cache.Disc.maxCacheSize = 3000
DatabaseManager.DB.Cache.Person.readOnlyCache = true
DatabaseManager.DB.Cache.Disc.readOnlyCache = false
DatabaseManager.DB.Cache.Person.defaultMaxSimpleQueryCacheSize = 1000
DatabaseManager.DB.Cache.Person.defaultMaxComplexQueryCacheSize = 200
DatabaseManager.DB.Cache.Person.maxSimpleQueryCacheSize = 150
DatabaseManager.DB.Cache.Person.maxComplexQueryCacheSize = 70
DatabaseManager.DB.Cache.Disc.defaultMaxSimpleQueryCacheSize = 1000
DatabaseManager.DB.Cache.Disc.defaultMaxComplexQueryCacheSize = 200
DatabaseManager.DB.Cache.Disc.maxSimpleQueryCacheSize = 900
DatabaseManager.DB.Cache.Disc.maxComplexQueryCacheSize = 200
DatabaseManager.DB.Cache.Person.initalConditionForCache = "*"
The example of non-enhydra application that can use DODS is DiscRack application, explained in next section.
Examples of DODS non-enhydra applications are included in DODS installation and they are in DODS, in directory:
<DODS_HOME>/examples
Process of running non-enhydra application will be presented in this section on the example Disc Rack. This example application is in <DODS_HOME>/examples/discrack directory.
To run example , these steps have to be done in Command Promt:
first, go to wanted example (directory)
cd <DODS_HOME>/examples /discrack
second, run ant,by typing:
antant will build this application in its <output_directory>
then, go to application's output directory:
cd <output_directory>
then, example will be run with:
run
Table of Contents
Caching affects the behaviour of the DO class. If checked, all DO instances are stored in the cache inside the DO class. Subsequent queries of the table use the Query class for queries. The results of all Queries, are complete. When you insert new DO into the database, the DO is also (automatically) inserted into the cache. When you delete DO from the database, the DO is also (automatically) deleted from the cache.
The possible cache types are:
None
This flag means that there is no caching available.
LRU
The size of the cache is limited by the maximal number of data objects that can be stored in. When the cache is full, the DOs in it are being replaced by new data objects according to LRU (least recently used) algorithm. This algorithm says that the DO (data object) which had been used the least recently (in the scale of time, the DO to which had been accessed the longest time ago) is replaced with the new data object.
Full (special case of LRU caching)
This is LRU cache which is unbounded (maximal number of data objects has no limit). The entire table is queried and cached when your application starts. This is appropriate for tables of "static" data which is accessed frequently and which will not change during the execution of your application. In this case, all Queries search the cache, hitting the database is never performed (because all database DOs are stored in the cache).
Default value of caching is "none".
Since this version, beside cache of data object, caching queries is also enabled. Caching now looks like this:
Select clause:
For query by oid, first is checked in the DO cache (cache of data objects) if there is data object with desired oid. If data object is not find in the cache, hitting the database is performed.
For full caching, for query by oid, first is also checked in the DO cache if there is data object with desired oid. If data object is not find in the cache, hitting the database is not performed (all data objects are in the DO cache, so there is no result of this query).
For all other queries, first is checked whether the query is already in the QueryCache (cache of queries)
If query is in the cache, the oids of the results are retrieved from QueryCache
For every result oid, it is checked whether there is that DO in the cache.
The time needed for performing queries by oid on database for all oids from result that are not in the cache is compared against the time needed for performing the whole query.
If the time needed for performing queries by oid on database is less, data objects are retrieved from the cache, or, if they are not there, from database (using queries by oid).
If the time is bigger, or the query is not in the query cache, the query is performed on database. The results are retreved from database. The query and oids of result data objects are put in the QueryCache
Insert clause:
DO is inserted in the database
DO is added in the DO cache
All complex queries are removed from QueryCache
For every simple query from QueryCache it is checked whether inserted DO is the result and if yes, the DO is included in query results
Delete clause:
Delete DO from the database
Remove DO from the DO cache (if it is there)
Go through QueryCache and wherever find this DO, remove it from query results
Update clause:
Update DO in the database
Update DO in the DO cache (if it is there)
All complex queries are removed from QueryCache
For every simple query from QueryCache it is checked whether updated DO is the query result
If yes, the DO is included in query results (if DO is not already in the query results, add it)
If no, if DO already exists in the query results, it is remove from there
In application's configuration file, there are following (optional) information about cache:
default maximal DO cache size
default maximal simple query cache size
default maximal complex query cache size
default read-only
maximal DO cache size (for every cached table)
maximal simple query cache size (for every cached table)
maximal complex query cache size (for every cached table)
read-only value for every cached table
initial "where" statement (with which the cache will be initialized)
Example: For file discRack.conf with type of caching LRU, part of code for cache configuration can look like this:
#
# Cache configuration
#
DatabaseManager.DB.Cache.defaultMaxCacheSize = 5000
DatabaseManager.DB.Cache.Person.maxCacheSize = -50
DatabaseManager.DB.Cache.Disc.maxCacheSize = 3000
DatabaseManager.DB.Cache.Person.readOnlyCache = true
DatabaseManager.DB.Cache.Disc.readOnlyCache = false
DatabaseManager.DB.Cache.Person.defaultMaxSimpleQueryCacheSize = 1000
DatabaseManager.DB.Cache.Person.defaultMaxComplexQueryCacheSize = 200
DatabaseManager.DB.Cache.Person.maxSimpleQueryCacheSize = 150
DatabaseManager.DB.Cache.Person.maxComplexQueryCacheSize = 70
DatabaseManager.DB.Cache.Disc.defaultMaxSimpleQueryCacheSize = 1000
DatabaseManager.DB.Cache.Disc.defaultMaxComplexQueryCacheSize = 200
DatabaseManager.DB.Cache.Disc.maxSimpleQueryCacheSize = 900
DatabaseManager.DB.Cache.Disc.maxComplexQueryCacheSize = 200
DatabaseManager.DB.Cache.Person.initalConditionForCache = "*"
In the following text are explained maximal cache sizes (for DO cache and query caches). The parameters maxCacheSize, maxSimpleQueryCacheSize and maxComplexQueryCacheSize of application's configuration file define these sizes.
maxCacheSize > 0
This cache is limited. The maximal number of elements in the cache is maxCacheSize.
maxCacheSize = 0
This means that there is no cache available. This value excludes cache from use.
maxCacheSize < 0
This cache is unlimited.
If any of parameters maxCacheSize, maxSimpleQueryCacheSize or maxComplexQueryCacheSize are not defined in configuration file, the size of the cache is defined by parameter defaultMaxCacheSize (or defaultMaxSimpleQueryCacheSize or defaultMaxComplexQueryCacheSize) of the same configuration file. The rules for these values are the same as for maxCacheSize, maxSimpleQueryCacheSize and maxComplexQueryCacheSize explained before.
If neither parameter maxCacheSize nor parameter defaultMaxCacheSize are defined, DODS has its own constants:
DEFAULT_MAX_CACHE_SIZE
DEFAULT_MAX_SIMPLE_QUERY_CACHE_SIZE and
DEFAULT_MAX_COMPLEX_QUERY_CACHE_SIZE
The read-only value tells whether the cache is read-only or not. The parameter readOnlyCache of application's configuration file defines read-only value.If it is read-only, the operations: insert, update or delete on the database are not possible. The default DODS value is false.
In the following text is explained initial "where" statement. The parameter initalConditionForCache of application's configuration file defines it. This is "where" part of select clause with which the cache will be initialized.
initalConditionForCache = "*"
This means that the entire table will be added to the DO cache in DO cache inicialization.
initalConditionForCache = "<where_clause>"
This means that the DOs from table that satisfy <where_clause> will be added to the DO cache in DO cache inicialization.
If this parameter does not exist in the application's configuration file, by default, no data object will be added to cache during its inicialization.
In previous mentioned example for part of code for cache configuration, for table Person cache type is full, because maxCacheSize is negative, readOnlyCache is true and initalConditionForCache is "*". This combination of values of parameters form special cache of LRU: full cache.
Like cache size, user wildcards are also defined in application's configuration file.
Example:
For file discRack.conf part of code for user wildcards can look like:
#
# User wildcards
#
DatabaseManager.DB.User.userWildcard = "*"
DatabaseManager.DB.User.userSingleWildcard = "_"
DatabaseManager.DB.User.userSingleWildcardEscape = "$"
DatabaseManager.DB.User.userWildcardEscape = "$"
DODS generates java code that is database independent. This means that java code is the same no matter which base you use.
When you want to change the database, the only thing you need to do is to change <App_name>.conf file (update it with information considering new database). This change is necessary for connection to database.
Enhydra has the possibility of working with more than one database at the same time. This means that, when the application is started, you don't have to stop it in order to change the database the application uses.
If you want to use this Enhydra option, you must (in <App_name>.conf file) define all logical databases you want to use. For each of these databases you must configurate all needed parameters. If you don't want to use this Enhydra option, the default database will be used.
When you update <App_name>.conf (with information about all databases) and start you application, it uses the default database. The definition of the new (desired) database is being done in the stage of creation of DO and Query objects.
When you create Query object for a database (given or default), the result of this Query are only DOs from that database, not from any other base.
If caching is used, there is only one cache for all <object_class>DOs (<object_class>DOs from all databases are placed in the same cache).
When you create DO for a specific database, this DO can't change database any more. If you want to translate one DO object from its database to another, you must create new DO in that another database, and then copy data of DO you want to translate into new DO (there are copy methods which you can use for this). In this way, new DO gets its own ID of its base.
Query object can change database. When you change database of the Query object, now the result of this Query will be DOs from this new database; you won't be able to get the DOs from the previous database any more.
DODS takes care of referential integrities within the database which means that DODS searches referenced object in the same database in which the object that referenced it is. If you want to use referenced objects from any other database, you must yourself take care of referential integrities.
In the <object_class>DO class public constructors and methods (loadData, createVirgin, createForExisting, createExisting) are now defined and with the parameter database. You can use them with this parameter in which case the object will be created for the given logical database, or you can use these constructors and methods without database parameter. In this case, they will be created for default database.
Tip: Be very careful when you add DO objects in the databases, or when you use Query objects. Now, there is more than one database that is used, and it's more difficult to track in which database, which DO object is placed, and for which base you run Query.
Tip: When you use multi databases with full caching, it would be better to announce in advance which databases will be used (with the method useLogicalDatabase(String database)) so that all needed DOs would be put in the cache at once, not partial.
DODS has the possibility of converting doml file, release 5.*. As described in the second chapter "Quick Compile" ( html, pdf ) of the document "Starting DODS" ( html , pdf ), Generator Wizard has a possibility of converting doml file into four document types: html, pdf, xmi and ptl. The name of the target (html, pdf, xmi, ptl) files will be the same as the name of doml file that is being converted, and they would be located in output directory.
The doml file can also be converted manually. For this purpose are used files in <dods_root>/bin folder, and they are:
doml2html - converts doml 5.* file into html file.
doml2html is used with the following parameters:
doml2html [-help] [doml5*-file] [html-file]
where:
help - prints message for usage and exits.
doml5*-file - doml file relese 5.*.
html-file - desired target html file.
doml2pdf - converts doml 5.* file into pdf file.
doml2pdf is used with the following parameters:
doml2pdf [-help] [doml5*-file] [pdf-file]
where:
help - prints message for usage and exits.
doml5*-file - doml file relese 5.*.
pdf-file - desired target pdf file.
doml2xmi - converts doml 5.* file into xmi file.
doml2xmi is used with the following parameters:
doml2xmi [-help] [doml5*-file] [xmi-file]
where:
help - prints message for usage and exits.
doml5*-file - doml file relese 5.*.
xmi-file - desired target xmi file.
doml2ptl - converts doml 5.* file into ptl file.
doml2ptl is used with the following parameters:
doml2ptl [-help] [doml5*-file] [ptl-file]
where:
help - prints message for usage and exits.
doml5*-file - doml file relese 5.*.
ptl-file - desired target ptl (Rational Rose) file.
doml31_2_doml51 - converting doml 3.1 file into doml 5.1 file.
doml31_2_doml51 is used with the following parameters:
doml31_2_doml51 [-help] [doml31-file] [doml51-file]
where:
help - prints message for usage and exits.
doml31-file - doml file relese 3.1.
doml51-file - desired target doml file relese 5.*.
User can make its own template sets. All template sets (standard, multidb and users) are placed in one directory. The name and location of this directory can be set (or changed) in dods.properties file (in <dods_home> directory). Within this directory, every template set is placed in its own subdirectory.
To configure DODS, use dodsConf.xml file, located in <dods_root>/build/conf directory.
This file contains the following information:
location of templates - tag <TemplateDir>
example:
<TemplateDir>C:/DODS/build/template</TemplateDir>
for each database vendor, location of its configuration file (in xml format) - tag <Database>
example:
<Database>
<Vendor name="Standard">C:/DODS/build/conf/StandardConf.xml</Vendor>
<Vendor name="InstantDB">C:/DODS/build/conf/InstantDBConf.xml</Vendor>
<Vendor name="Oracle">C:/DODS/build/conf/OracleConf.xml</Vendor>
<Vendor name="Informix">C:/DODS/build/conf/InformixConf.xml</Vendor>
<Vendor name="MSQL">C:/DODS/build/conf/MSQLConf.xml</Vendor>
<Vendor name="Sybase">C:/DODS/build/conf/SybaseConf.xml</Vendor>
<Vendor name="PostgreSQL">C:/DODS/build/conf/PostgreSQLConf.xml</Vendor>
<Vendor name="HypersonicSQL">C:/DODS/build/conf/HypersonicSQLConf.xml</Vendor>
<Vendor name="DB2">C:/DODS/build/conf/DB2Conf.xml</Vendor>
<Vendor name="QED">C:/DODS/build/conf/QEDConf.xml</Vendor>
<Vendor name="MySQL">C:/DODS/build/conf/MySQLConf.xml</Vendor>
</Database>
Database Vendor's configuration file contains informatio about that database (type of ObjectId, column name for oid and version, information about DeleteCascade, constraints, quotes,comments, characterd for like and wildcard, mapping JDBC types to vendor-specific data types,...).
If tags <ClassPath>, <ClassName> are not mentioned, standard code is generated for that database vendor.
If database is specific, path to jar file for that database vendor is in tag <ClassPath>, and its main class is in tag <ClassName>.
example, for database Informix:
<ClassPath>C:/DODS/lib/dbvendors/informix.jar</ClassPath>
<ClassName>com.lutris.appserver.server.sql.informix.InformixLogicalDatabase</ClassName>