ObjectStore Rapid Database Development for Java

Chapter 3

Run the Component Wizard

This chapter shows you how to use the Component Wizard to generate the code you will use to implement your application. Using the personnel database design file you created in Chapter 2 as input, you can select a number of code-generation options and let the Component Wizard do the rest.

This chapter covers the following topics:

Starting the Component Wizard

The Component Wizard is available as a Visual J++ plug-in or as a stand-alone tool that you can launch from the Database Designer. This chapter describes both ways to start the Component Wizard.

Visual J++ plug-in

Use the Component Wizard from within Visual J++ to automatically generate the Java classes for your application. The compiler uses the project information in order to be aware of all the files in your application, as well as the code that causes the compiler to invoke the postprocessor on all your persistent classes. You can select any database design from which to generate code.

Stand-alone tool

Use the Component Wizard as a stand-alone tool if you are using a Java compiler other than Visual J++. The code generated by the Component Wizard is based on the active design in the Database Designer.

Start the Component Wizard from Visual J++

To start the Component Wizard from Visual J++:

  1. Start Microsoft Developer Studio.

  2. Click File | New to open the New dialog box.

  3. Click the Projects tab and select ObjectStore Component Wizard for Java in the Projects list.



  4. Type the name Personnel in the Project Name field.

  5. If necessary, change the directory specified in the Location field. This field specifies where the Component Wizard will write the files it creates.

  6. Accept the default values for the remaining fields and then click OK.

Start the Component Wizard from the Database Designer

To start the Component Wizard from the Database Designer, select Component Wizard from the Tools menu.

After you start the Component Wizard, the ObjectStore Component Wizard for Java Step 1 of 2 dialog box opens.

Every dialog box of the Component Wizard has a Next and a Finish button. Both buttons advance the Component Wizard.

The Next button

Click Next to let the Component Wizard guide you through one step at a a time. You should consider using Next so that you can become familiar with all of the Component Wizard's features.

The Finish button

Click Finish to let the Component Wizard complete automatically, using default values wherever possible. Note that the Finish button might be unavailable if a subsequent dialog box in the Component Wizard has one or more fields that require user input.

Selecting the Database and Classes

If you are running the Component Wizard from within Visual J++, you first need to select a database. Then select the classes that you want to use in your application.

If you are running the Component Wizard from the Database Designer, the active database will be used. Then you need to select the classes that you want to use in your application.

Select a Database Design (Visual J++ Only)

To select a database design:

  1. Click the Open Database Design button to display the Open window.

  2. Locate and open the database design file for the personnel database you created in Chapter 2.

    Tip: ObjectStore database design files have a default extension of .dbs.

Select Classes

When you start the Component Wizard, all the classes in the database appear by default in the Design Classes list box.

Click Next to continue to the next step, as described in Defining Database Entry Points.

Tip: After you become more familiar with the Component Wizard, you can click the Finish button whenever it is available.

Defining Database Entry Points

Now you need to define the entry points, called roots, of your database. A database root gives an object a persistent name, which allows the object to serve as an entry point into persistent memory. When an object has a persistent name, any process can look it up by that name and retrieve it; you can find related objects by navigating from object to object.

Create Roots for Top-Level Classes

A database root can be any type of object or collection of objects. By default the Component Wizard creates a root for each top-level class in a schema that points to one of the collection types for ObjectStore. These types include OSTreeSet and OSVector. The Component Wizard uses OSTreeSet by default. For each of the selected classes, the Component Wizard generates the code to create the root, create the container, and update the class extent, that is, all the persistent instances of the class.

For more information

To learn more about roots, entry-point objects, and collections, see the ObjectStoreJava API User Guide.

Define Database Roots

The Component Wizard displays the default values that will be used to define the database roots for your application.

You can change these defaults by

This tutorial uses the default values supplied by the Component Wizard.

Display New Package Information

When you click the Next button, the Component Wizard displays the New Package Information dialog box. Click OK to continue.

You are now ready to build an application.

Examining the Component Wizard Code

This section examines some of the code generated by the Component Wizard.

Class Definitions

For each class you define in the Database Designer, the Component Wizard generates a file called ClassName.java where ClassName is the name of the class. The ClassName.java file contains the class definition, including attributes, declarations, and method signatures.

The following is an excerpt from the Employee.java file:

public class Employee extends Person{
// Attributes
      public int overTimeHours;
      private float salary;



// Operations
      public  float getSalary()
      {
            float ret=0;
            //TODO: Add your code here
            return ret;
      }
      public  void setSalary(float aSalary)
      {
            //TODO: Add your code here
      }
      public  float getOvertimeCost(float hourlyRate)
      {
            float ret=0;
            //TODO: Add your code here
            return ret;
      }


}
You need to provide the method body for each method you define in the Database Designer. See Defining Methods for more information on writing methods.

Class Constructor

For each class, the Component Wizard generates an empty constructor with no parameter, and a constructor that initializes all the attributes to the values passed as parameters to the constructor.

The following is an excerpt from the Person.java file:

public class Person{


      ////////////////////////////////////////////////////////
      // Constructor
      public Person()
      {
      }

      public Person(String _name, int _age)
      {
            name=_name;
            age=_age;
      }

}

Class Extent Handling

For each class for which an extent has been defined, the Component Wizard generates the following attribute definition:

//Extents
      public static Ext_OSTreeSet Ext = new Ext_OSTreeSet("Person");
The Ext attribute points to the extent for the class that is implemented as

Ext_OSTreeSet
The Component Wizard also generates the following method:

public void preFlushContents()
      {
            Segment theSegment=
Session.getCurrent().segmentOfpreFlushContentsObject();
            Database db = theSegment.getDatabase();
            Collection theExtent = (Collection) Ext.getExtents(db);
            if (!theExtent.contains(this))
                  updateExtents(db, true);
}
The preFlushContents method is called when the instance changes its persistent state. The previous implementation of the preFlushContents method ensures that when the instance becomes persistent because it has been included or referred to by another persistent object, it gets inserted into the proper extent.

The following generated method explicitly inserts an instance into its extent:

void updateExtents(Database db, boolean add)
      {
            Ext.update(this, db, add);
}
This method should be called after an instance has been created to insert it into the proper extent. When inserted into a persistent extent, the newly created instance becomes persistent itself.

For more information

To learn more about persistence by reachability, see the ObjectStoreJava API User Guide.

The extents.Java file

The extents.Java file contains the Extents class, which implements the default extent-handling functionality.

An extent is a collection of all the instances of a class in the database and can be implemented using any container class. The Component Wizard allows you to implement extents using either an OSTreeSet or OSVector; that is why the Extents class is an abstract class that gets specialized by Ext_OSTreeSet and Ext_OSVector. These classes are the classes for which an extent-handling mechanism has been specified in the Component Wizard.

Working with extents

To enable an application to retrieve an extent, the collection has to be reachable by navigating a root, that is, a named entry point into persistent memory. You can specify both the name of the root and the type of the collection used to implement a class extent in the ObjectStore Component Wizard for Java Step 2 of 2 dialog box.

In the personnel database, you implemented the extent of the Department and Person classes using an OSTreeSet; therefore, the class Ext_OSTreeSet is used. By default, root names are based on class names.

public abstract class Extents
{
      String m_name;
      Database m_db=null;
      Object m_obj;
      Object m_root;

      public String getRootName() {return m_name;};

      public Extents(String rootname)
      {
            m_name = rootname;
      }

      public abstract Object createExtents(Database db);

      public Object getExtents(Database db)
      {      
            try{
                  if (db!=null){
                        m_db      = db;
                        m_root      = m_db.getRoot(m_name);
                  }
            }
            catch(DatabaseRootNotFoundException RootNotFound){
                  m_root = null;
            }

            if (m_root==null){
                  m_root = createExtents(db);
                  setExtents(m_root);
            }

            return m_root;
      }

      public void update(Object obj, Database db)
      {
            m_obj      = obj;
            m_db      = db;
      }

      protected void setExtents(Object root)
      {
            m_root = root;
            m_db.createRoot(m_name, root);
      }

      protected boolean checkType(Object obj, String type)
      {
            Class c = obj.getClass();
            String name = c.getName();
            return (name.compareTo(type) == 0);
      }
}

Public methods

The public methods of this class are

      public String getRootName()
 Returns the name of the root that points to the extent.

public abstract Object createExtents(Database db); Implemented by the Ext_OSTreeSet and Ext_OSVector classes. It creates the proper container collection for the extent.

public Object getExtents(Database db) Returns the class extent. If the extent does not exist, it calls the createExtents method to create one and attaches it to the proper root.

public void update(Object obj, Database db) Inserts the obj object into the extent.

For more information

For more information on database roots, see the ObjectStoreJava API User Guide.

Defining Methods

The Component Wizard generates the signatures of the methods you define with the Database Designer; you will need to define the method implementation.

Consider the following example of the body of the getSalary method of the Employee class.

The Component Wizard generates the following code:

      public  float getSalary()
      {
            float ret=0;
            //TODO: Add your code here
            return ret;
      }
The getSalary method returns the value of the salary attribute. The method body might look like this:

public  float getSalary()
      {
            return salary;
      }
The setSalary method sets the value of the salary attribute. The method body might look like this:

public  void setSalary(float aSalary)
      {
            //TODO: Add your code here
            salary = aSalary;
      }
The getOvertimeCost method should return the product of the hourlyRate parameter and the number of overtime hours stored in the overTimeHours attribute:

      public  float getOvertimeCost(float hourlyRate)
      {
            float ret=0;
            //TODO: Add your code here
            ret= overTimeHours * hourlyRate;
            return ret;
      }

Writing an Application

This section describes how to get started writing an ObjectStoreapplication using the files generated by the Component Wizard.

The top.Java class

The top.java class contains the skeleton of a simple main for your application. You can use this class to get started with the implementation of your application.

final public class Top
{
      public static Database db=null;

      public static void main(String argv[]) throws java.io.IOException
      {
            String dbName="db.odb";
            ObjectStore.initialize(null, null);

      try{
            try{
                  db = Database.open(dbName,  ObjectStore.OPEN_
UPDATE);
            }
            catch (DatabaseNotFoundException e){
                  db = Database.create(dbName,ObjectStore.ALL_READ | 
ObjectStore.ALL_WRITE);
            }
            Transaction t = Transaction.begin(ObjectStore.UPDATE);

            //insert your code here


            t.commit();
            db.close();
      }
      catch(Exception e){
            System.out.println(e);
      }
      finally{
            ObjectStore.shutdown(true);
      }
  }
}
The db attribute points to a Database object:

public static Database db=null;
The database gets opened in the main function:

try{
      db = Database.open(dbName,  ObjectStore.OPEN_UPDATE);
}
If it does not exist it is created:

catch (DatabaseNotFoundException e){
      db = Database.create(dbName,ObjectStore.ALL_READ | 
ObjectStore.ALL_WRITE);
}
The main function also shows how you can start and commit a transaction:

Transaction t = Transaction.begin(ObjectStore.UPDATE);
//insert your code here
t.commit();

Writing the Main Function

In this example, you create a couple of persistent instances of the Department class and associate some employees with them.

The main function of the Top class might contain the following:

Transaction t = Transaction.begin(ObjectStore.UPDATE);

//insert your code here
//Creating a Department instance 
Department dep1 = new Department();
dep1.departmentName = "Marketing";
dep1.employees = new Employee[10];

//Adding dep1 to the extent of Departments
dep1.updateExtents(db, true);

t.commit();
This code creates a new Department instance and sets its name to Marketing.

The updateExtent call inserts the newly created Department into the proper extent. Given that the class extent is allocated persistently (it is reachable from a root), the dep1 object instance automatically becomes persistent.

For more information

To learn more about roots, entry-point objects, and collections, see the ObjectStoreJava API User Guide.

Now add some Employees and attach them to Marketing:

//Creating some Employee instances
Employee e1= new Employee(10, 20000, "John", 33);
Employee e2= new Employee(25, 35000, "Peter", 40);

//Attaching the employees to the Department
dep1.employees[0]= e1;
dep1.employees[1]= e2;
When you attach e1 and e2 to the employees array, they become persistent by reachability because dep1 is a persistent object.

To complete the example, add another Department with some additional employees.

//Creating another Department instance 
Department dep2 = new Department();
dep2.departmentName = "Sales";
dep2.employees = new Employee[10];

//Adding dep2 to the extent of Departments
dep2.updateExtents(db, true);

//Creating some Employee instances
Employee e3= new Employee(10, 50000, "Chris", 51);
Employee e4= new Employee(45, 38000, "Larry", 39);
Employee e5= new Employee(15, 35000, "Andy", 55);

//Attaching the employees to the Department
dep2.employees[0]= e3;
dep2.employees[1]= e4;
dep2.employees[2]= e5;

Building the Project

This section shows you how to build a project, using either the Java JDK or Visual J++.

Building the Project with JDK

The Component Wizard automatically generates a batch file called doall.bat that contains the commands you need to compile and execute your project.

The doall.bat file

The following is the contents of the doall.bat file:

@echo off

ECHO Compiling source files
javac *.java

ECHO Running ObjectStore classfile postprocessor
call osjcfp @cfpargs

ECHO run the program
java Personnel.Top
The doall.bat assumes that you are using the javac command-line compiler and that it is in your bin path. If this is not the case, make the appropriate changes to doall.bat.

After all the Java files are compiled, doall.bat calls the postprocessor to process all the classes that are part of the schema you defined with the Database Designer.

How to build a project

To build a project with JDK:

  1. Make the directory where you generated your project your current directory.

  2. Run doall.bat.

The cfpargs file

The cfpargs file is generated by the Component Wizard and contains the flags for the postprocessor. This is the contents of the cfpargs file for the personnel example:

-dest . -inplace
-persistaware
Top.class
Extents.class
Ext_OSTreeSet.class
Ext_OSVector.class
-persistcapable
Customer.class
Department.class
Employee.class
Person.class
If the compilation and postprocessing operations successfully complete, the java Personnel.TOP command executes your application.

For more information

See the postprocessor documentation in the ObjectStoreJava API User Guide.

Building the Project Using Visual J++ 1.1

When you run the Component Wizard from Visual J++, it generates the VJ++ package that includes all the Java files needed to compile the application based on the schema you defined with the Database Designer.

The Component Wizard also sets the project so that at the end of the compilation process, the compiler calls the postprocessor.

To build a project

To build the project using Visual J++, select Rebuild All from the Build menu.

The following code is a sample of the output of the compilation process:

To run the application

To run the application, select Execute from the Build menu, or press Ctrl+F5.

The first time you run the application, Visual J++ prompts you to enter the name of the class you want to execute. In this example, you enter Personnel.Top.

If Visual J++ displays "ERROR: Could not execute Personnel.Top: The system cannot find the file specified", check that you added the proper class path to the list of class directories. For example, if you created your project under c:\Myprojects\Personnel, make sure the c:\Myprojects directory is included in the list of class directories:

To add a directory to the Class path:

  1. Select Options from the Tools menu.

  2. Click the Directories tab.

  3. Select Class File from the Show directories for: list and then click OK.





[previous]

Copyright © 1998 Object Design, Inc. All rights reserved.

Updated: 10/06/98 15:51:13