This document describes how to do this for a sample application that connects to a database and retrieves, inserts, updates, and deletes data from the database associated with the Customer object. This document contains information on the following tasks:
The Code Generator component of Object Translator generates the following
files for the Customer object:
Customer.java | This class contains the attributes of the object, its getter and setter methods, and the Store, Restore, and Destroy methods. |
CustomerOID.java | This class represents an object identifier for the customer object. It contains methods needed to get and set object-identifier values. |
CustomerCollection.java | This class contains methods for a collection of Customer objects: those to Store, Restore, and Destroy a collection; those to add or remove an object from the collection; and those to navigate within the collection of objects. |
import com.informix.ormapper.*;Define a variable of type OConnection named conn. Depending on the database you are using, define the database URL and the driver name. The following example uses an Informix database and the Informix JDBC driver, Version 2.1x.
Connection conn; String url = "jdbc:informix-sqli://[MachineName]:[Port#]/" + "[DatabaseName]:informixserver=[ServerName];" + "user=[OptionalUserName];password=[OptionalPassword]"; String driverName = "com.informix.jdbc.IfxDriver"; try { conn = new OConnection(url, driverName); } catch (DatabaseException e) { System.out.println(e); }
Customer cust = new Customer(conn);
getAttribute_name
setAttribute_name
For example, if the Customer object has an attribute named cust_id, the following getter and setter methods are generated:
getCust_id
setCust_id
You use these methods as follows:
Integer cid = getCust_id(); // Get cust_id. setCust_id(new Integer(12)); // Set cust_id to 12 (for example).
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.restore();Note: If you are restoring collection objects, you can specify whether to perform a shallow or deep restore using the Object Translator GUI (see the online help provided with the GUI).
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.setCust_name("XYZ Company"); cust.store();To update an object, follow these steps:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.restore(); cust.setCust_name("ABC Company"); cust.store();Note: If you are storing or restoring collection objects, you can specify whether to perform shallow or deep stores and restores using the Object Translator GUI (see the online help provided with the GUI).
To destroy an object, follow these steps:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.destroy();Note: When destroying object hierarchies, you can specify whether to perform a shallow or deep destroy using the Object Translator GUI (see the online help provided with the GUI).
You use the Object Translator GUI to create and generate the objects, and to specify that they are in a collection relationship. While defining each parent (Customer and Order), you can set their default RestoreType, StoreType, and DestroyType properties to Deep or Shallow. If you choose Deep for both parent objects, then when your application calls the Customer object's Restore, Store, or Destroy methods, Object Translator also performs those operations on the Order and OrderLine objects. (For information on using the Object Translator GUI, see the online help provided with the GUI.)
This section tells how to work with collection objects in the following ways:
For example, in the scenario where Customer and Order are Object Translator-generated classes and Customer has a collection of Order objects, you can restore a Customer object and its Order collection and print them, as follows:
Customer cust = new Customer(conn); cust.setDeepRestore(true); // Overwrite the default if necessary. cust.setCust_id(new Integer(12)); cust.restore(); String name = cust.getCust_name(); System.out.println("Customer: " + name); // Get a collection of orders just for this customer. OrderCollection col = cust.getOrderCollection(); Order order = col.nextObject(); while (order != null) { System.out.println("Order ID: " + order.getOrder_id()); order = col.nextObject(); }Note: When the restore type is Shallow (the default in the Object Translator GUI), lazy-instantiation of the OrdersCollection object occurs, so the object is fetched or instantiated only when necessary. In this case, the usage is exactly the same as shown above, but the OrderCollection object is restored only when cust.getOrderCollection() is called. When the restore type is Deep, OrderCollection is restored internally when the Customer object is restored.
For example, if Customer and Order are Object Translator-generated classes and Customer has a collection of Order objects, you can insert a Customer object and its collection of Order objects, as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.setCust_name("XYZ Company"); OrderCollection ordCol = new OrderCollection(conn); Order ord1 = new Order(conn); ord1.setOrder_id(new Long(1001)); ord1.setCust_id(new Integer(12)); ord1.setOrderRep("Jane Smith"); ordCol.addObject(ord1); Order ord2 = new Order(conn); ord2.setOrder_id(new Long(1002)); ord2.setCust_id(new Integer(12)); ord2.setOrderRep("Jane Smith"); ordCol.addObject(ord2); cust.setOrderCollection(ordCol); cust.store();
For example, update a Customer object and its collection of Order objects, as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.restore(); cust.setsetCust_name("ABC Company"); OrderCollection ordCol = cust.getOrderCollection(); Order ord1 = ordCol.firstObject(); ord1.setOrderRep("Tom Sawyer"); Order ord2 = ordCol.nextObject(); ord2.setOrderRep("Tom Sawyer"); cust.store();Note: The default store type is Deep. If the store type is set to Shallow, you must explicitly call the Store method of the collection object. Thus, in the example above, if the store type is Shallow, to store the orders, you must call the Store method of the OrderCollection object and add the statement "ordCol.store();" after the "cust.store();" statement.
To destroy a collection object, set the attribute for that object and then call the Destroy method of that object.
For example, in the scenario where Customer and Order are Object Translator-generated classes and Customer has a collection of Order objects, let cust_id and order_id be the primary key attributes for Customer and Order respectively and then call the Destroy method for the object, as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.restore(); OrderCollection ordCol = cust.getOrderCollection(); Order ord = ordCol.nextObject(); while (ord != null) { ord = ordCol.nextObject(); } ordCol.destroy(); cust.destroy();Note: The default destroy type is Shallow. To destroy the Customer object and all of its Order objects when the destroy type is Shallow, you must first restore every Order object that needs to be deleted. You must also explicitly destroy the OrderCollection object before destroying the Customer object. If the destroy type is set to Deep, you do not need to destroy the OrderCollection object; hence, in the above scenario, "ordCol.destroy();" is not necessary.
This section tells how to perform the following tasks:
For example, in the scenario where Customer and Address are Object Translator-generated classes and Customer has an embedded Address object, you can restore a Customer object and its embedded Address object, as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.restore(); String name = cust.getCust_name(); Address addr = cust.getAddress(); String address1 = addr.getAddress1(); String address2 = addr.getAddress2(); String city = addr.getCity(); String state = addr.getState(); String zip = addr.getZip(); System.out.println(name+"\n"+address1+"\n"+address2+"\n"+city+"\n"+state+" "+zip);
For example, in the scenario where Customer and Address are Object Translator-generated classes and Customer has an embedded Address object, you can insert a Customer object and its embedded Address object as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.setCust_name("XYZ Company"); Address addr = new Address(); addr.setAddress1("1 North First Street"); addr.setAddress2("Suite 800"); addr.setCity("San Jose"); addr.setState("CA"); addr.setZip("94555"); cust.setAddress(addr); cust.store();
For example, update a Customer object and its embedded Address object, as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.restore(); cust.setCust_name("ABC Company"); Address addr = cust.getAddress(); addr.setAddress1("3344"); addr.setAddress2("Riverside Street"); addr.setCity("Santa Barbara"); addr.setState("CA"); addr.setZip("93212"); cust.store();
To destroy an embedded object, set the attribute for that object and then call the Destroy method of that object.
For example, in the scenario where Customer and Address are Object Translator-generated classes and Customer has an embedded Address object, set the cust_id attribute for Customer. Then destroy a Customer object and its embedded Address object, as follows:
Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.destroy();
For example, you can store information about "XYZ Company," restore the information, change the Cust_name attribute to "ABC Company," and update Cust_name with the new name, as follows:
conn.setAutoCommit(false); // Set manual transaction on the connection. Customer cust = new Customer(conn); cust.setCust_id(new Integer(12)); cust.setCust_name("XYZ Company"); cust.store(); conn.commit(); cust.setCust_id(new Integer(12)); cust.restore(); cust.setCust_name("ABC Company"); cust.store(); conn.rollback();In this case, the Cust_name attribute remains set to XYZ Company.
There are two kinds of concurrency locking:
In general, the optimistic concurrency option implies an isolation level of READ_COMMITTED. This means that no locks are set on the data being read and only committed changes from other transactions are seen. Other transactions are prevented from reading uncommited changes; they cannot execute "dirty reads."Optimistic. No read locks are placed on columns. If you use this option, you can choose the detect mechanism that Object Translator uses to determine whether data has changed since the last time it read the data.
Pessimistic. Read locks are placed on the columns. The read locks are released when the transaction is committed.
The pessimistic concurrency option implies an isolation level of SERIALIZABLE
or REPEATABLE_READ. For Informix database servers, these two settings are
equivalent. When a connection is set to pessimistic concurrency, dirty
reads, non-repeatable reads, and phantom reads are prevented. For more
information, see your database server manual and the Java 2 API regarding
java.sql.Connection.
The four concurrency-change-detection types that you can specify are:
DETECT_NONE (the default): There is no change detection; values are not compared.
DETECT_CHANGEDROW: The original value(s) of only the queried column(s) that comprise the changed row indicator are compared to the new values of those same columns.
DETECT_UPDATED: The original values of only the queried columns that have been updated are compared to the new values of those updated columns.
DETECT_QUERIED: The original value(s) of only the queried column(s) that comprise the changed row indicator are compared to the new values of those same columns.
When you use the Optimistic option, you can set the concurrency-change-detection type at the connection level or the object level. When you set the detection type at the connection level, the detection type will be used as the default for all the objects associated with the connection, unless it is overwritten by the detection type of individual objects. The default detection type for a connection is DETECT_NONE.
To set the type of concurrency locking, call setLockType() on the OConnection object. For example:
conn.setLockType(OConnection.PESSIMISTIC);To set the change detection for optimistic locking, call setDetectType() on the OConnection object or the Object Translator object. For example:
if (conn.getLockType() == OConnection.OPTIMISTIC) { // Set the default to use all updated columns for change detection. conn.setDetectType(OConnection.DETECT_UPDATED); } Customer cust = new Customer(conn); cust.setCust_id(new Integer(1)); cust.restore(); // Set the change detection type for Customer object to use // Changed Row Indicator. cust.setDetectType(OConnection.DETECT_CHANGEDROW); cust.setCust_name("Big-E-Donut.com"); // DatabaseException with message "The row has been changed since last fetch." // will be thrown if any changes by others are detected. cust.store();
A UDR can return a single value or it can return a result set. In the Object Translator Java runtime component, custom methods always return java.sql.ResultSet object references. You must scroll through the result set and get individual values from the result set.
In the following example, AddIntegers is a custom method that is mapped to a UDR that takes two integers and returns the sum:
java.sql.ResultSet rs; rs = cust.AddIntegers(new Integer(21), new Integer(68)); if (rs.next()) { // Prints "sum = 99" System.out.println("sum = " + rs.getInt(1)); }
Each collection object contains a cache. The cache is used to store individual objects (each of which represents a row in a result set) that have been retrieved from the database. The cache allows faster retrieval of the objects; new and updated values are also placed in the cache before a Store or Destroy method is called. The use of the cache is optimal for most scenarios. The exception is a batch query, when you want to retrieve a collection of objects in a read-only manner and view the objects one at a time (from first to last) just once.
You can turn caching off by calling the method setCaching(false) of the Object Translator collection object. If you turn caching off, you will not be able to store or destroy the collection object.
For example:
Customer cust = new Customer(conn); CustomerCollection col = new CustomerCollection(conn); col.setPredicate("state = 'CA'"); col.restore(); col.setCaching(false); // Turn caching off and use it in read-only mode. Customer cust = col.nextObject(); while (cust != null) { System.out.println("Name: " + cust.getName()); cust = col.nextObject(); }
Note: The NoResultSetException exception must be caught before DatabaseException. Although there can be multiple catch blocks after a try block, only one of the catch blocks is executed if an exception is raised from a try block. If you catch DatabaseException first, all the possible NoResultSetException exceptions raised from the try block are caught by the DatabaseException catch block, because NoResultSetException is a subclass of DatabaseException.
try
{
customer.restore(); //Throws both NoResultSetException
and DatabaseException.
}
catch (NoResultSetException
e)
{
System.out.println("Record not found.");
}
catch (DatabaseException
e)
{
System.out.println("Some other error in restoring the object.");
}
catch (InvalidObjectException
e)
{
System.out.println("Some other error in restoring the object.");
}
You can test for all exceptions in the Restore method of the Customer object because NoResultSetException is a subclass of DatabaseException. Here is an example:
try
{
customer.restore(); //Throws both NoResultSetException
and DatabaseException.
}
catch (DatabaseException
e)
{
System.out.println("Cannot restore object.");
}
catch (InvalidObjectException
e)
{
System.out.println("Some other error in restoring the object.");
}
The ObjectName.settings file contains the location of the XML document mapped to the map object named ObjectName. (A .settings file is not generated for an embedded object.) This XML document location in the .settings file is referred to as the location property. Object Translator-generated Java classes load the XML document specified by this property.
The name of the location property is formatted as follows:
com.informix.OT.ProjectNameLocationFor example, if your Object Translator project has been saved to a file named orgdbProject.XML, then the name of your location property is com.informix.OT.orgdbProjectLocation.
By default, the value of the location property is the current directory ("."). If your XML document is located elsewhere, you can set the property to a different value. You can set the location property in the Java application command line or in the init method of this map object's servlet code (if you chose to generate servlet code).
Note: The procedures in this section change only the location
of the XML document. If you want to change the name of the XML document,
you must either edit the ObjectName.settings file or specify
the new name in the Object Translator GUI and regenerate your project.
java -D"com.informix.OT.orgdbProjectLocation=c:\ObjectTranslator\org" OrgdbAppThis command line shows how to set the property to a jar file:
java -D"com.informix.OT.orgdbProjectLocation=c:\ObjectTranslator\org\orgdbProject.jar" OrgdbApp
System.setProperty("com.informix.OT.orgdbProjectLocation", ".");
//replace the parameter "." with the appropriate project dir/jar fileAs the comment instructs, set the second argument to either a directory or a jar file. For a directory, the line might look like this; notice the double slash characters in the directory name:
System.setProperty("com.informix.OT.orgdbProjectLocation", "c:\\ObjectTranslator\\org");For a jar file, the line might look like this:
System.setProperty("com.informix.OT.orgdbProjectLocation", "c:\\ObjectTranslator\\org\\orgdbProject.jar");
The OConnection class includes the setLocale and getLocale methods. You can call setLocale to receive Object Translator messages in the desired language. If you do not use this method, the language specified by the current system locale is used. If a locale-specific resource bundle cannot be found, then the default U.S. English resource bundle (Messages.properties) is used.
Note: The setLocale method does not affect the CLIENT_LOCALE or DB_LOCALE environment variables, which are used by the Informix database server and JDBC driver. Thus, error messages that originate from the database server or JDBC driver will be in the language specified by CLIENT_LOCALE. Include the ifxlang.jar file in your CLASSPATH setting to cause the JDBC driver to generate localized messages.
The following example shows how to use the setLocale and getLocale methods:
try
{
// Specify the URL,
appending the CLIENT_LOCALE and/or DB_LOCALE variables if needed.
String url = "jdbc:informix-sqli://big:1526/books:informixserver=big_us";
// Connect using the
URL and the default Informix driver.
OConnection conn = new
OConnection(url, null, "myUser", "myPassword");
// Set the Object Translator
runtime locale to German-Germany.
conn.setLocale(new Locale("de",
"DE"));
// Print the full locale
name. Locale: German (Germany)
System.out.println("Locale:
" + conn.getLocale().getDisplayName());
Customer cust = new Customer(conn);
cust.setCust_id(new Integer(12345));
// Restore the object.
If a Cust_id of 12345 does not exist, a NoResultSetException with
// a message of "No
result set" (in German, if available) will be raised.
cust.restore();
}
catch (DatabaseException e)
{
e.printStackTrace();
}
Connection pooling is a method for conserving scarce database resources by managing a pool of connections among concurrently active clients.
JNDI support and connection pooling are provided by your JDBC driver, your application server, or both via the DataSource object. For information on JNDI support and connection pooling, refer to the documentation for your JDBC driver and application servers.
The following example shows how a client can obtain a connection handle from a DataSource object and then pass the handle to the Object Translator OConnection constructor:
/**
* Get a connection by looking up a DataSource
Object.
*/
try
{
Context ctx = new InitialContext();
DataSource ds = (DataSource)
ctx.lookup(DS_NAME);
conn = new OConnection(ds.getConnection("userid", "secret"));
return true;
}
catch (Exception e)
{
return false;
}
The following example shows the creation process of a DataSource object. This process is specific to your application-deployment environment and would usually take place on the middle-tier server computer.
/**
* Create a DataSource and bind to a context.
* This code is usually run on the
server side.
*/
public boolean createDS()
{
try
{
IfxDataSource ds = new IfxDataSource();
ds.setIfxIFXHOST("myhost");
ds.setPortNumber(1526);
ds.setDatabaseName("books");
ds.setServerName("myhost_us");
ds.setDescription("Books database on MyHost");
Context ctx = new InitialContext();
System.out.println("Binding datasource " + DS_NAME );
ctx.bind(DS_NAME, ds);
return true;
}
catch (SQLException
e)
{
e.printStackTrace();
return false;
}
catch (NamingException
e)
{
e.printStackTrace();
return false;
}
}
To compile Object Translator-generated Java source code, and to deploy an application that uses the Object Translator-generated code, make sure that the Object Translator runtime package ormapper.jar and the appropriate JDBC driver are included in the correct CLASSPATH setting.
You can verify the ormapper.jar is in the CLASSPATH by running this command from the shell:
java com.informix.ormapper.Version
Last updated 14 June 2000.