DODS - Getting Started with DODS
dods.gif (11357 bytes)The purpose of this document is to get you up to speed quickly with DODS.

Introduction

The Data Object Design Studio (DODS) is a software development tool. DODS is an object-oriented design tool that generates the code most developers would rather not write the old-fashioned way.

DODS allows you to design the data-layer classes that comprise the foundation of an application that will utilize the Enhydra application framework. Then, DODS will generate the Java source code for those data-layer classes, and compile them for you.

DODS Projects

In DODS, you create a Data Object entity for each data-layer class needed by your application. Each Data Object contains Attributes.

An Attribute describes either a piece of data (e.g. int, String, Date) or a reference to another Data Object. By using reference Attributes, you create an interconnected hierarchy of Data Objects.

A collection of Data Object specifications is stored as a Project file. You can reopen a Project file and make changes to your Data Objects.

Code Generation

When you are happy with the Data Objects you have designed, DODS will generate the source code to implement them. Using DODS to design Data Objects is easy, and the steps are described in later sections. The purpose of DODS is to generate Java and SQL code for you. As an simple example, you could create a Data Object to represent a dog with the Attribute 'name' and the Attribute 'age'. For the 'Dog' Data Object, the following source code would be generated:

  • Dog.sql: Contains the SQL 'create table' command needed to create the 'dog' table in the relational database. Execute the 'create table' command using your favorite interactive SQL tool.


    Each non-constant Attribute in a Data Object is represented by a column in the table definition generated for that object. In addition, each generated table definition contains two columns used by the Enhydra database framework: 'oid' and 'version'.

      create table Dog (
      name VARCHAR(50),
      age INTEGER,
      oid DECIMAL(19,0) NOT NULL, // primary key
      version INTEGER NOT NULL // update counter
      );

  • DogDO.java: Contains the class DogDO which represents a row from the table in the database. This class provides a set and get method for each Attribute, methods to handle caching, etc. Each DO class is derived from GenericDO, an Enhydra framework class; thus, each generated DO class automatically utilizes the database management features of the Enhydra framework.
    class DogDO extends GenericDO {

      // static members for use in constructing complex DB queries.
      // For examples usages, see the javadoc for QueryBuilder
      // and the examples below.
      static final RDBTable table = new RDBTable( "dog" );
      static final RDBColumn PrimaryKey = new RDBColumn( "oid" );
      static final RDBColumn name = new RDBColumn( "name" );
      static final RDBColumn age = new RDBColumn( "age" );

      // method to instantiate a new 'dog' object not yet in the dB
      static DogDO createVirgin() { ... }

      // methods to retrieve a 'dog' object from the 'dog' table
      // using various forms of the primary key
      static DogDO createExisting(String handle) { ... }
      static DogDO createExisting(BigDecimal handle) { ... }
      static DogDO createExisting(ObjectId handle) { ... }

      // method returning the primary key value
      // for this virgin/existing object
      String getHandle() { ... }

      // get/set methods for each Attribute of 'dog'
      String getName() { ... }
      void setName(String newValue) { ... }
      int getAge() { ... }
      void setAge(String newValue) { ... }

    }

  • DogQuery.java: Contains the class DogQuery which provides SQL query access to the table in the database. The DogQuery class will search the database table according to criteria you specify dynamically, and return a collection of DogDO objects that represent the rows found in the table.
    Class DogQuery { (

      // methods to specify query parameters
      void setQueryName( String nameToSearchFor ) { ... }
      void setQueryAge( int ageToSearchFor ) { ... }

      // methods to retrieve rows from database
      DogBDO getNextBDO(); // retrieve one row at a time
      DogBDO[] getBDOArray(); // retrieve all rows at once

    }

  • DogBDO.java: Contains the class DogBDO (BDO = Business Data Object.) When you implement the business logic of your application, the DogBDO class will ease your interaction with the DogDO class.


    Class DogBDO {

      // method to instantiate a new 'dog' object not yet in the dB
      static DogDO createVirgin() { ... }

      // methods to retrieve a 'dog' object from the 'dog' table
      // using various forms of the primary key
      static DogDO createExisting(String handle) { ... }
      static DogDO createExisting(BigDecimal handle) { ... }
      static DogDO createExisting(ObjectId handle) { ... }

      // method returning the primary key value
      // for this virgin/existing object
      String getHandle() { ... }

      // get/set methods for each Attribute of 'dog'
      String getName() { ... }
      void setName(String newValue) { ... }
      int getAge() { ... }
      void setAge(String newValue) { ... }

      // commit() inserts this virgin object into the dB as a new row,
      // or updates the existing row with changes made with setXxx
      void commit() { ... }
      // delete() removes the dB row represented by this object
      void delete() { ... }

    }

Many-to-One Relationships

For Data Objects that are referenced by other Data Objects, the BDO class will also contain convenience lookup methods to retrieve those associated objects.

Many-to-Many Relationships

A Data Object that contains references to two other types of Data Objects is used to implement a many-to-many mapping between objects of those two types. Data Objects involved in a many-to-many relationship will contain convenience methods to retrieve associated objects, and methods to map and unmap associations between objects.

Note: The BDO classes are an artifact of earlier projects executed at Lutris Technologies. The functionality of the BDO classes could (and probably will) be folded into the DO classes in a later release.

Such changes in the code that DODS generates are accomplished by changing the source code templates that DODS uses. See the dods.conf file for details. Also see the Enhydra mailing list for messages posted by developers who have altered the templates toward their own designs.

Package Structure

When DODS generates your source code, it creates a directory structure that matches the package hierarchy you have designed. DODS creates the Makefiles in each directory, and runs 'make' on the generated source code.

The source tree layout for a typical Enhydra application can be seen by running the 'newapp' utility. For example, the commands
cd /tmp
newapp myApp

will produce the following directory structure:

  • /tmp/
  • myApp/
  • myApp/
  • presentation/
  • business/
  • data/
  • All the application code would be belong in a Java package named "myApp".
    DODS would be used to design classes to go in the package "myApp.data".

    NOTE: In DODS, each XxxDO class should be created in the package "myApp.data" (or a sub-package).

    When you specify the directory for DODS to write the generated code, it attempts to match the hierarchy of packages you have created against the hierarchy of directories above the target directory you specified. If they match, DODS adjusts the Makefiles it generates to integrate with your application; otherwise, each time you adjust your DODS project file and regenerate the code and Makefiles, you must perform this integration by hand.

    Using the Generated Code

    After you create a database using the .sql files, you can code your application business objects to use your Data Objects. You can then code your presentation objects to use your business objects. Here are some examples of using the classes generated by DODS
    NOTE: Run 'make javadoc' on the generated source code to see more examples. Also see javadoc for the QueryBuilder class.

    Create a new 'dog' row in the database for a dog named 'Bob':

    DogBDO bob = DogBDO.createVirgin();
    bob.setName( "Bob" );
    bob.setAge( 1 );
    bob.commit();

    The servlet composes an HTML page containing a SELECT using bobName as option text and using bobHandle as the OPTION VALUE, and containing an INPUT field labeled "Age". It then sends that HTML to the vet's browser. The vet wants to change Bob's age, and so enters the new age, chooses the option labeled "Bob", and submits the form to servlet B. Servlet B uses the handle VALUE of the selected OPTION to instantiate a DogBDO to represent Bob's row in the dog table. It then sets Bob's new age, and updates the row.

    String bobName = bob.getName();
    String bobHandle = bob.getHandle();
    String dogHandle = getOptionFromRequest();
    String newAge = getAgeFromRequest(); // get value of "Age" INPUT field from request parameter
    DogBDO selectedDog = DogBDO.createExisting( dogHandle );
    selectedDog.setAge( newAge );
    selectedDog.commit();

    Where the methods getOptionFromRequest( ) gets the attribute VALUE of chosen OPTION from request parameter and getAgeFromRequest( ) gets the value of "Age" INPUT field from request parameter.

    Performing a query

    From another HTML page, the vet searches for dogs by name. Servlet C is passed the name submitted from the HTML page, and performs a search of the dog table for dogs with that name.

    String dogName = // get INPUT name from request parameter
    DogQuery q = new DogQuery();
    q.setQueryName( dogName );
    DogBDO selectedDog;
    while ( null != ( selectedDog = q.getNextBDO() ) )
    debugMsg( dogName + "'s age is " + selectedDog.getAge() );

    Performing a more complex query

    Say you want to print any dogs named "Fido" that are 2, 3 or 4 years old. Use the Query class as usual, but access its QueryBuilder object to refine the query.

    DogQuery dq = new DogQuery();
    dq.setQueryName( "Fido" );
    QueryBuilder qb = dq.getQueryBuilder();
    qb.addWhere( DogDO.age, 2, QueryBuilder.GREATER_OR_EQUAL );
    qb.addWhere( DogDO.age, 4, QueryBuilder.LESS_OR_EQUAL );
    qb.addOrderByColumn( DogDO.age );
    // print SQL "select" statement before execution,
    // compare against next example
    qb.debug();
    DogBDO[] youngFidos = dq.getBDOArray();
    for ( int i = 0; i < youngFidos.length; i++ ) {
    DogBDO dog = youngFidos[i];
    print( dog.getName() + " is " +
    dog.getAge() + " years old." );
    }

    Performing the same query using just the QueryBuilder. When you are simply generating a data report (especially one that joins multiple tables) it is sometimes simplest to use the QueryBuilder directly.

    Vector fields = new Vector(); // bind set of desired columns
    fields.addElement( DogDO.name );
    fields.addElement( DogDO.age );
    QueryBuilder qb = new QueryBuilder( fields );
    qb.addWhere( DogDO.name, "Fido" );
    qb.addWhere( DogDO.age, 2, QueryBuilder.GREATER_OR_EQUAL );
    qb.addWhere( DogDO.age, 4, QueryBuilder.LESS_OR_EQUAL );
    qb.addOrderByColumn( DogDO.age, "ASCENDING" );
    // print SQL "select" statement before execution,
    // compare against previous example
    qb.debug();
    RDBRow row;
    while ( null != ( row = qb.getNextRow() ) ) {
    print( row.get( DogDO.name ).getString() + " is " +
    row.get( DogDO.age ).getInteger() + " years old." );
    }

    Using RDBColumn and RDBRow

    Note that the column names are not expressed as hard-coded strings; instead the static final RDBColumn members of the DogDO class are used. This protects the developer against problems caused when the DODS GUI is later used to make changes to the 'dog' table. Examples:

    • Another developer changes the column name in the table. The above example query would continue to compile and execute correctly. Whereas, hard-coded strings would cause a run-time error which would require fixing.
    • Another developer removes the 'age' column from the 'dog' table. The example query would no longer compile, reminding the developer precisely what change is needed in the application code. Whereas, hard-coded strings would cause a run-time error, and more difficult maintenance.

    QueryBuilder supports other where-clause syntax (see addWhereOpenParen and addWhereOr), including subqueries (see addWhereIn.)

    Extending a DODS-generated Query class to provide a convenient interface
    for performing the same query as above:

    class AdvancedDogQuery extends PersonQuery {
    void setQueryAgeRange( int min, int max ) {
    QueryBuilder qb = dq.getQueryBuilder();
    qb.addWhere( DogDO.age, 2, QueryBuilder.GREATER_OR_EQUAL );
    qb.addWhere( DogDO.age, 4, QueryBuilder.LESS_OR_EQUAL );
    qb.addOrderByColumn( DogDO.age );
    }
    }

    // using the extended query class
    AdvancedDogQuery dq = new AdvancedDogQuery();
    dq.setQueryName( "Fido" );
    ad.setQueryAgeRange( 2, 4 );
    DogBDO[] youngFidos = dq.getBDOArray();
    for ( int i = 0; i < youngFidos.length; i++ ) {
    DogBDO dog = youngFidos[i];
    print( dog.getName() + " is " +
    dog.getAge() + " years old." );
    }


    Using DODS

    There are three different panels in DODS: There is a Graphical View on top, and below that, there is a Package/Object Tree and an Attribute Table. The Graphical View shows the hierarchy of the DataObject you've created. For instance, Customer extends Person, etc.

    The Tree is a directory structure of the packages which hold the Data Objects which will be created by DODS. When the project is finished and built, this directory structure will be created with the appropriate .java files in each directory corresponding to the Data Objects in those packages.

    The Table is used to display the attributes of a DataObject. When a DataObject is selected in either the Tree or the Graphical View, it's Attributes are listed in the table. For instance, a Customer might have a phone number, Address, and probably a name. Each of these attributes would be listed in the table when the Customer object is selected.

    Example

    Run DODS by executing the command output/bin/dods. As a simple example collection of Data Objects, let's use Customers, Stores and Store Employees.

    Step 1: Creating the package hierarchy

    First, we are going to need packages for these data objects. In the Tree panel is a folder icon for the default package named "root". Click the "root" package icon to select it. Click Edit-->Package to bring up a dialog box, change the name to "myApp", and click Ok. Now let's create sub-packages. Choose Insert-->Package; A dialog will pop up asking for a name, and also displaying a tree to choose the package that this new package will be in. Currently the only package to put it in is "myApp." Type in the name "data" and hit OK. This creates a new package folder on the Tree.

    This arrangement of packages fits into the package hierarchy generated by the 'newapp' utility for an application named 'myApp'. Remember: Java package names start with lowercase, Java class names start with uppercase.)

    Step 2: Creating the data objects

    Create the example Person Data Object

    Since Customer and Employees are both types of people, let's create a base class named Person to contain the common attributes.

    Click (select) the "data" package in the Tree, and click Insert-->Data Object.
    The Data Object Editor dialog appears. Set the name to "Person". Leave the "Extends" set to "Nothing"; the Person class does not extend any other classes in the Tree.

    Click the Package tab and make sure the new "Person" Data Object will be placed in the "myApp.data" package.

    Click the Database tab and set the Table Name to "person". For now, ignore the other settings.

    Click OK at the bottom of the dialog, and the "Person" Data Object appears in the Graphical View and in the Tree.

    The "Person" Data Object is represented in the Tree as a blue circle icon. If you need to adjust the settings for a package or Data Object, you can double-click it's icon to bring up the appropriate Editor dialog.

    A Person will have a name. In DODS, "name" will be an Attribute of the "Person" Data Object. When DODS generates the PersonDO.java class for you, "name" will be a data member, and will have get and set methods. In the PersonSQL.sql file that DODS generates, "name" will be a column specified in the "person" table.

    To add the "name" Attribute to Person, select Person in the Tree, and click Insert-->Attribute. The Attribute Editor dialog appears.

    Under the General tab, set the Name of the Attribute to "name".

    Under the Java tab, set the Java Type to String. You may provide an initial value for the "name" Attribute, but leaving it blank is fine. You may also provide Javadoc text, which will appear in the PersonDO.java file that DODS will generate.

    Under the Database tab, set the dB Type to VARCHAR (a likely database type for storing Strings.) Here you can specify whether you want the database table "Person" to be indexed by the "name" column, whether the column can contain a NULL value, and whether you intend to search the table by "name" values. Since searching by name is often useful, check the "Can be queried" checkbox.

    If all Persons were to have the same name, you set the "name" value to be constant; the "name" data member in the PersonDO class would be "final", and the "person" database table would have no "name" column. Ignore the "Referenced DO" checkbox for now.

    Click OK at the bottom of the Attribute Editor dialog to add the "name" Attribute to the "Person" Data Object. In the Table panel the "name" Attribute now appears. The Table columns marked with colored glyphs indicate the checkboxes chosen in the Attribute Editor. Note that because you checked the "Can be queried" checkbox under the Database tab, a 'Q' glyph is shown for this Attribute. These glyphs are for your quick reference, and clicking their boxes is a quick way of toggling the settings for an Attribute. You can move your mouse over each glyph heading in the Table to see a reminder of the Attribute setting each glyph represents. When you have a Data Object with many Attributes, you can sort the Attributes in the Table by clicking on a heading glyph.

    Go ahead and create a Store object as well, and give it a name attribute.

    In our example, there will be two kinds (subclasses) of Person: Customers and Employees.

    Create the example Employee Data Object by extending Person

    Select Person in the Tree and click Insert-->Data Object. The Data Object Editor appears. Enter "Employee" for the name of the new Data Object. In the "Extends" menu, select "myApp.data.PersonDO."

    Click OK at the bottom of the Editor dialog.

    In the Tree panel, the circle icon for Person has changed from blue to yellow; this indicates that Person is now an abstract class.

    NOTE: In DODS, Data Objects which are extended must be abstract. When a Data Object is extended, DODS automatically marks it as abstract. This is due to the way Data Object classes generated by DODS map to the database. Only non-abstract "leaf" classes have tables in the database.

    Note also that the blue circle icon for Employee is in the "myApp" package, instead of the "myApp.data" package; we forgot to set the package for Employee in the Editor. Simply drag the Employee icon to the "data" package folder icon.

    Establish a one-to-many relationship between Store and Employee

    Now let's establish the relationship between Stores and Employees. For our example, one or more (i.e. many) Employees work for each Store, and each Employee works for only one Store. To represent this, add an 'employer' Attribute to Employee. Click Insert-->Attribute again and set the Attribute name to 'employer'. Under the Java tab, set the type this Attribute to myApp.data.EmployeeDO.

    Under the Database tab, check the "Referenced DO must exist" checkbox. This will impose an integrity constraint in the database to ensure than a Customer's accountManager is always a valid Employee.

    Click OK. Now click on the Customer in the Graphical View panel. An arrow appears, pointing from Customer to Employee; this indicates the object reference you just created.

    DODS will create a StoreBDO.getEmployeeDOArray() method to retrieve an array of EmployeeDO objects that reference a given StoreDO.

    Create the example Customer Data Object and establish a many-to-many relationship to Stores

    Create a Customer object that extends Person. Add an accountNumber Attribute to the Customer Data Object; select the Customer icon and then click Insert-->Attribute. Set the Attribute name to "accountNumber"; under the Java tab, make it an integer; under the Database tab, check "Can be queried."

    For our example application, let's say we want to be able to know which Customers visit each Store, and also which Stores are visited by each Customer.
    This is a many-to-many relationship: each Customer visits many Stores, and each Store is visited by many Customers. This relationship cannot be established simply be giving Customer a reference Attribute to Store, and vice versa; such an arrangement would allow the database to show each Customer visiting only one Store, and each Store having just one Customer. To represent a many-to-many relationship, we need to create a special intermediary object.

    Create an object named CustStore. Give it an Attribute named 'customer' that is a reference to CustomerDO. Give it another Attribute named 'store' that is a reference to StoreDO. Each CustStore object instance in the database will show that a given Customer visits a given Store.

    DODS will create a CustomerBDO.getStoreDOArray_via_CustStore() method that returns an array of StoreDO objects referenced by a given CustomerDO. DODS will also create a StoreBDO.getCustomerDOArray_via_CustStore() method that returns an array of CustomerDO objects referenced by a given StoreDO. See the generated code for other handy methods.

    Step 3: Saving your project

    That pretty much explains everything about creating a set of Data Objects. You should now save your project. There are several other Options on the menus.

    You can edit Packages, Data Objects, and Attributes that already exist by selecting them and choosing Edit-->...

    You can delete packages, data objects and attributes, but the undo function only saves the last delete that has been performed.

    Step 4: Building your project

    Click Build

    Finally, when you are ready to build all of the code for the Data Objects, click File-->Build All. This option is available if there are no errors in the Objects you have created. If there is an error somewhere, you can choose Edit-->Find Next Error, and it will take you to the Data Object which has an error. Errors show up in the Table with a red exclamation mark. Click on the exclamation mark to see what the error is.

    If you have not saved your project before, the Save Project dialog will appear. Enter the path and name for your project file and click OK.

    Next you will see a dialog labeled Destory and Create New DODS Directory.

    For this example you would navigate to the directory

    /tmp/myApp/myApp

    and select the subdirectory

    data/

    Or, type /tmp/myApp/myApp/data.

    WARNING:Always verify the path you enter is correct. DODS removes everything in and under that directory, and recreates it to match the current package structure of your project.

    Running with Parameters

    The script that starts DODS

    output/bin/dods

    can be given optional parameters.

    dods [ project file [ output directory [ regen ] ] ]

    If you specify a project file, it will be opened automatically when DODS starts.

    If you specify an output directory, it will be preselected when you click the Build button.

    If you provide "regen" as the third parameter, the DODS GUI will not appear, but the named project file will be loaded, and the code generators will write source code to the named output directory. The "regen" parameter is useful for running DODS from a makefile to completely rebuild an application. The project file can be thought of as the actual "source code" for the data layer of the application.

    The Data Object Editor

    The Database Tab (in the Data Object Editor dialog), has the following:

    • Table Name: When entering a name for a database table, bear in mind the naming restrictions of your chosen database vendor. For example, there may be a maximum length for the name, the name cannot be an SQL reserved word, and there may be names that are reserved for use by the database itself.
    • Every Class: For future use.
    • Every Concrete Class: For future use.
    • Entire Hierarchy: For future use.
    • Lazy Loading: This flag affects the behavior of the DO class (defined in the DO.java file for the Data Object.) If checked, then when you supply a known ObjectId to create a DO instance, the DO instance is created but the corresponding row in the table is not retrieved until the first get or set method call is made. This is useful when you are reconstituting a hierarchy of objects from rows in the table, but you will not always need the data for this particular object in that hierarchy. Checking 'Lazy Loading' delays the hit on the database until the moment the data is actually needed. Depending upon how your application accesses its database, this can result in extra database hits, and hurt performance. If not checked, then all the data members are retrieved from the table when the DO instance is created. If your application will not always need these data members, this can waste memory.
    • Cached: This flag affects the behavior of the DO class. If checked, all DO instances are stored in a cache inside the DO class. Subsequent queries of the table using the Query class will first check the cache before hitting the database. This is appropriate when different parts of your application hold references to the same DO instance.
      WARNING: there are known design issues with the generated code regarding the cache mechanism.
    • Fully Cached: This flag affects the behavior of the DO class. If checked, 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. Note that there is a refreshCache() method available if your application needs to refresh the cache with new values in the table.
    The Attribute Editor

    The Database Tab (in the Attribute Editor dialog), has the following:

    • dB Type: This pulldown menu holds a list of database column types that are valid for storing the Java type chosen for this Attribute.
    • Size: For some column types (e.g. CHAR, VARCHAR, etc.) a size can be specified for the column.
    • Is An Index: If checked, a database index is created on this column in the table.
    • Can Be Null: If *not* checked, the "NOT NULL" restriction is placed on the column.
    • Can Be Queried: If checked, the Query class generated for this Data Object will include a set method for this column to allow restricting the search.
    • Referenced DO Must Exist: If checked and this Attribute is a reference to another Data Object (i.e. the Java type for this Attribute is another DO) then a "REFERENCES" restriction is placed on the column. This enforces referential integrity between the tables for these two Data Objects.
    • Value is Constant: If checked, the Attribute is made a constant data member in the DO class, and no column is created in the table for this Data Object.
    The Query Classes

    The Query classes generated by DODS allow you to search the database for DOs. Attributes of the DO which are marked "Can be queried" will have a method setQueryAttributeName() in the Query class. These setQuery methods allow you to prune the search results.

    The Query classes generated by DODS all use the QueryBuilder helper class. The setQueryAttributeName methods invoke the QueryBuilder.addWhereClause() method to construct the SQL select command that performs the search. After creating an instance of a Query class, you can obtain the associated instance of QueryBuilder to add extra clauses to the select command. (Some developers elect to extend a Query class to implement new methods for such extra functionality.) Using extra clauses, your select command can perform more complex searches.

    DB2 Note: The QueryBuilder.NOT_EQUALS qualifier will not work with DB2 databases. Use the String "<>" instead.

    Querying a View

    It is possible to use DO/Query classes to access a view instead of a table.
    Say you use DODS to create a DO named Person, and you want a view named 'count_people':

    create view count_people (total) as select count(*) from person

    You would create another DO named Count, specify its table name to be 'count_people', and add an integer attribute named 'total', and mark that attribute as Can Be Queried.

    Then click Build to let DODS generate the classes PersonDO, PersonBDO, PersonQuery, PeopleSQL.sql CountDO, CountBDO, CountQuery, CountSQL.sql

    Discard the CountSQL.sql file, and remove the 'create table count_people' statement from the create_tables.sql file that DODS generated.

    Use the create_tables.sql file to define your tables in your database. Then manually create the count_people view (using the create view above.)

    The CountQuery class can now be used just as you would any Query class. The CountDO object returned by CountQuery will contain the 'total' you desire. NOTE: Only 'get' methods should be called on the CountDO object.


    Running with XWindows

    Depending on the platform you may need to do some configuration work to get DODS to display properly in an XWindows environment. Below are some instructions for getting DODS to work via remote X Server using the JDK1.2. Linux and XVision users may also need to install new font.properties files for Java 2.

    If you're running DODS under Linux with JDK1.2, it should just work, provided your fonts are world readable, and the directories containing them are executable. Blackdown's prerelease JDK1.2 had permissions problems that are probably fixed in their more current version.

    If you're running either Linux or Windows, and you telnet to your Unix (Solaris/Linux) Server and want to run DODS. You may run into some horrendous display issues if your system is not configured properly.

    If your workstation is a Linux system, you might notice that JDK1.2 does not support 16 bit color depths on a remote XFree86 Server. If you're running 16 bit color depth, you probably want to change it down to 8 bits. Here's how I do this (On Red Hat, anyway - I don't know how different versions of Linux/XFree86 are packaged). There might be a better way, but I haven't found it:

    On the system hosting DODS
    1. Copy font.properties.xfree86 provided with DODS to $JDKDIR/jre/lib/font.properties this will get rid of font not found problems. (JDKDIR is the path to java1.2.)
    2. Make a backup copy of /etc/X11/XF86Config - DON'T LOSE THIS COPY
    3. Change the color depth level to 8.
    • If you feel comfortable editing XF86Config by hand, go ahead and do that to adjust your color depth to 8,
    • If prefer to use a tool, Red Hat supplies XConfigurator - to use that, first you have to shutdown your X Server (I do this by editing /etc/inittab, changing the default init level to 3, and rebooting, but there are other ways)
    • Run XConfigurator, change your bpp (bits-per-pixel) to 8. (if you have problems here, you can restore your backup XF86Config file)
    1. Restart your X Server (set default init level back to 5) . You're done.
    Windows XVision Users

    If your workstation is a Windows system running XVision, then you may notice Java dumping core quite heinously when trying to run DODS. Then XVision will give you some suggestions about configuration changes you can make to fix this problem. So, you want to do two things:

    1. On the UNIX system, copy font.properties.xvision to $JDKDIR/jre/lib/font.properties, this will get rid of font not found problems.
    2. On the Windows system, go into the Color tab of XVision properties, click the radio button that allows the user to select the color properties, then select PseudoColor and uncheck the Windows
      System Colors.

    These problems are probably not particular to DODS, but more to differences between JDK1.1.7 and 1.2. If you don't have any problems when trying to run DODS remotely, there's no reason to make these
    configuration changes. It should be made clear that these changes are to be made only if you're running Java applications like DODS via remote X server, and are having problems.

    If you still have font not found warnings after replacing the font.properties file, you can make a choice to either live with DODS without the fonts that Java can't find, or try to fix the problem yourself. You can somewhat easily edit font.properties using sed.

    For instance, if I encountered font not found warnings on the Java console, I would telnet to the UNIX box and do the following:

    1. Enter xlsfonts to find out which fonts my X server can use
    2. For each font not found (you'll see a lot of warnings, but usually two, maybe three unfound fonts mentioned over and over again), pick a new font from the list given by xlsfonts.
    3. cat font.properties | sed -e 's///' > font.properties.NEW
      Where is a font selected from xlsfonts, formatted in the same manner as the other fonts in the file (with \* instead of real metrics, \%d for the point size, etc - reading font.properties will give you an idea of what it should look like)
    4. cp font.properties font.properties.ORIG;
      mv font.properties.NEW font.properties


    With this process, it shouldn't take one too long to generate a font.properties that their system can use. It's especially important to keep that original font.properties file if you're not familiar with either sed or the X font structure - you can get into a mess pretty quick.

    Note: In some cases dialogs may appear blank when you open them ununder XWindows. If this happens, you can resize the dialog to force the controls to appear.

    For all the latest information on DODS, please refer to http://dods.enhydra.org
    Questions, comments, feedback? Let us know...