Using Java with Caché Jalapeño
Using ObjectManager
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

Both Jalapeño and the standard Java binding work by associating a Java object in memory with a corresponding Caché object used to store persistent data, but Jalapeño Java objects are very different from the standard Java proxy objects. Unlike the standard binding, Jalapeño requires a “persistence manager” class to provide a link between Java objects and the persistent database.

The standard Caché Java binding starts with Caché classes and generates Java proxy classes. The generated classes are designed to work closely with Caché, and include built-in methods for database operations such as opening, saving, and deleting. Each Java proxy object contains everything necessary to interact with its corresponding Caché object.
Jalapeño, on the other hand, must be able to work with pre-existing Java classes that do not include such methods. It starts with these Java classes and generates corresponding Caché classes. Instances of the generated classes are used to store persistent data, and may also contain database features such as indices and relationships. Since the Java objects do not contain database methods, all interactions with the database are managed by an instance of the Jalapeño ObjectManager class.
This chapter provides functional examples of how to use the methods provided by ObjectManager. The following subjects are discussed:
Also see the online Jalapeño Tutorial, which provides step-by-step instructions for creating two Jalapeño applications that use some of the most common ObjectManager methods.
Note:
The examples in this chapter are designed to demonstrate working ObjectManager methods in as few lines as possible, and therefore ignore good coding practices such as error checking. Although the examples have all been tested and work as described, they are not meant to be taken verbatim as templates for production code.
Creating a Jalapeño Project
This section describes TinyPojo, a very simple application that uses Jalapeño (see The Complete TinyPojo Program for a listing of the finished project). The following topics are discussed:
Creating a Persistence Manager
The following code fragment from class TinyPojo creates an ObjectManager that connects to the USER namespace:
  import com.jalapeno.ApplicationContext;
  public static com.jalapeno.ObjectManager  objManager;
  ...
  String  url="jdbc:Cache://localhost:1972/USER";
  String  user = "_SYSTEM";
  String  pwd = "SYS";
  objManager = ApplicationContext.createObjectManager(url,user,pwd);
  ...
  objManager.close();
Compare this to the standard Java binding, which uses a Caché Database object to establish the connection (see Creating a Connection Object in Using Java with Caché), and then passes the connection to an instance of a projected Java class. Since Jalapeño applications use a standard Java Connection object, they have the potential to connect to any database program with an appropriate JDBC driver.
Adding a POJO class to the Project
A POJO (Plain Old Java Object) class is just a standard Java class containing property and method definitions, created in the Java development environment of your choice. The examples in this book frequently use the Employee class:
  package tinyproject;
  import com.jalapeno.annotations.*;

  @Index (name="EmpIdx", propertyNames={"ssn"}, isPrimaryKey=true)
  public class Employee {

    public String name = null;
    public String ssn = null;
    public int salary = 0;

    @Relationship(type=RelationshipType.MANY_TO_ONE,
      inverseClass="Department", inverseProperty="staff")
    public Department department = null;

    public String showProps () throws Exception {
      return " name:" + name + " ssn:" + ssn + " salary:" + salary;
    }
  }

The Employee class is a normal Java class except for the addition of two Jalapeño annotations. The @Index annotation specifies ssn as the primary key, and @Relationship specifies a many-to-one relationship between this class and the Department class (discussed later in this chapter). These annotations are described in detail in Adding Indices and Adding Relationships.
The Jalapeño SchemaBuilder utility (see Generating Caché Schema with SchemaBuilder) is used to create a corresponding class definition (schema) in Caché. It generates the following schema for the Employee class:
  Class tinyproject.Employee Extends %Library.Persistent [ SqlTableName = Employee ]
  {
  Relationship department As Department(JAVATYPE = "tinyproject.Department")
  [ Cardinality = one, Inverse = staff ];

  Property name As %Library.String(JAVATYPE = "java.lang.String", MAXLEN = 4096);
  Property salary As %Library.Integer(JAVATYPE = "int");
  Property ssn As %Library.String(JAVATYPE = "java.lang.String", MAXLEN = 128);

  Index EmpIdx On ssn [ PrimaryKey, Unique ];

  XData JavaBlock
  {
  <JavaBlock>
    <Package implementation="tinyproject.cache" pojo="tinyproject"></Package>
    <UseSameNames>false</UseSameNames>
    <Name implementation="Employee" pojo="Employee"></Name>
    <ResolveNameCollisions>false</ResolveNameCollisions>
    <EagerFetchRequired>true</EagerFetchRequired>
  </JavaBlock>
  }
  }
The schema contains the same properties as the original Java class, adds the index and relationship information specified by the annotations, and records some information in JavaBlock that ObjectManager will use to determine how instances of the class can be manipulated. The Employee schema can be viewed in Caché Studio, just like any other Caché class:
Viewing Employee.cls
Note:
SQL reserved words should not be used as class or property identifiers. To force the use of a different class or property name when the Caché proxy is generated, set the name parameter of the @CacheClass or @CacheProperty annotation.
For a list of SQL reserved words, see the Reserved Words section in the Caché SQL Reference.
Using the Persistence Manager
The TinyPojo application's SampleCode class uses a few simple ObjectManager method calls that demonstrate how to save an object to the persistent database, retrieve it to memory, and then delete the database object.
First, it creates an Employee object in memory and sets its properties:
  Employee newEmp = new Employee ();
  newEmp.name = "Clem Smith";
  newEmp.ssn = "111-22-3333";
  newEmp.salary = "65000";
The object has not yet been added to the persistent database, and therefore does not have a database Id. A call to the getId() method would return null. The insert() method is used to save the object to the database:
  objManager.insert(newEmp, true);
After the call to insert(), the object is open and attached to the database, so a call to getId() returns a valid value. We can now destroy the object in client memory, and later use the saved Id to retrieve it from the database:
  myId = objManager.getId(newEmp);
  newEmp = null;

  newEmp = (Employee)objManager.openById(Employee.class, myId);
See Manipulating Persistent Objects for more details about insert(), getId(), and openById().
When the application is finished, it erases the test data from the persistent database, using the killExtent() method to delete all instances of Employee:
  objManager.extentManager ().killExtent (Employee.class);
See Database Maintenance with ObjectManager.ExtentManager for more information about the killExtent() method. Also see Calling PopulateUtils from a Java Application, which describes an easy way to generate test data.
The Complete TinyPojo Program
The code examples in the previous sections were taken from the Jalapeño application presented here. The application has four classes:
class TinyPojo
This class creates a connection object and an ObjectManager (see Creating a Persistence Manager), calls some sample code that uses the ObjectManager, then closes the connection.
Since no instances of the TinyPojo class will be stored in the database, the optional @Transient annotation has been added to prevent SchemaBuilder from generating a corresponding Caché class.
package tinyproject;
import com.jalapeno.ApplicationContext;
import com.jalapeno.ObjectManager;
import com.jalapeno.annotations.Transient;

@Transient
public class TinyPojo {
  public static ObjectManager objManager;

/* Define the connection parameters */ 

  public static String  url="jdbc:Cache://localhost:1972/USER";
  public static String  user = "_SYSTEM";
  public static String  pwd = "SYS";

  public static void main( String[] args ) throws Exception
  {
/* Create an ObjectManager that uses the connection 
   parameters to open a connection to the database. */

    objManager = ApplicationContext.createObjectManager(url,user,pwd);
/* Run the rest of the application, then close the connection. */

      SampleCode.runExample();
      objManager.close();
   }
}
class Employee
This is a simple POJO data class containing the name, social security number, and salary of a company employee, plus a method for returning a string to display these properties.
The annotations tell SchemaBuilder to add some database information not present in the POJO class. @Index tells it to add a primary index on ssn, and @Relationship tells it to add a many-to-one relationship to the Department class. The resulting Cache schema is described in Adding a POJO class to the Project. The annotations are described in detail in Adding Indices and Adding Relationships.
package tinyproject;
import com.jalapeno.annotations.*;

@Index (name="EmpIdx", propertyNames={"ssn"}, isPrimaryKey=true)
public class Employee {

  public String name = null;
  public String ssn = null;
  public int salary = 0;

  @Relationship(type=RelationshipType.MANY_TO_ONE,
    inverseClass="Department", inverseProperty="staff")
  public Department department = null;

  public String showProps () throws Exception {
    return " name:" + name + " ssn:" + ssn + " salary:" + salary;
  }
}
Also see the tinyproject.MakeEmployee class (later in this chapter), which demonstrates an easy way to generate populated Employee objects for use as test data.
class Department
This POJO class represents a department in a company, and contains a list of Employee objects belonging to the department. The deptname property can have a value of "Operations", "Sales", "Training", or "Management". The manager property contains an Employee object belonging to the Management department, and the staff property is a list of all other employees in the department.
The @Relationship annotation is the inverse of the one in the Employee class, and establishes a one-to-many relationship with Employee. For a detailed discussion of @Relationship, see Adding Relationships.
package tinyproject;
import java.util.ArrayList;
import com.jalapeno.annotations.*;

public class Department {

  public String deptname = null;
  public Employee manager = null;

  @Relationship(type=RelationshipType.ONE_TO_MANY,
    inverseClass="Employee", inverseProperty="department")
  public ArrayList<Employee> staff = new ArrayList<Employee> ();
}
class SampleCode
This class creates an Employee object and manipulates it with the ObjectManager created by class TinyPojo (see Using the Persistence Manager).
Since no instances of this class will be stored in the database, the optional @Transient annotation has been added to prevent SchemaBuilder from generating a corresponding Caché class.
package tinyproject;
import com.jalapeno.ObjectManager;
import com.jalapeno.annotations.Transient;

@Transient
public class SampleCode {
  public static ObjectManager objManager = TinyPojo.objManager;
  public static void runExample() throws Exception
  {
/* Create an Employee object in memory. The value of the object Id
   is null because it has not been inserted into the database. 
*/
    Employee newEmp = new Employee ();
    newEmp.name = "Clem Smith";
    newEmp.ssn = "111-22-3333";
    newEmp.salary = 65000;
    Object myId = objManager.getId(newEmp);
    System.out.println("\nCreate newEmp (id:"+ myId +") "+ newEmp.showProps());
/* Save the object to the database, get the Id of the saved object, 
   and erase the object from memory. 
*/
    objManager.insert(newEmp, true);
    myId = objManager.getId(newEmp);
    System.out.println("\nInsert object (Id:"+ myId +") "+ newEmp.showProps());
    newEmp = null;
/* Use the saved Id to get the object back from the database. Finally, clean up
   the test database by deleting all Employee objects. 
*/
    Employee storedEmp = (Employee)objManager.openById(Employee.class, myId);
    System.out.println("\nOpen stored object "+ storedEmp.showProps());
    objManager.extentManager ().killExtent (Employee.class);
  }
}
Manipulating Persistent Objects
These functions allow objects in the database store to be manipulated.
Creating or Updating an Object
The object manager has the following methods for saving instances of objects:
Each of these methods takes the boolean parameter deep, which determines whether or not objects referenced by the given object should also be saved.
insert() and update()
In many cases, it is simplest to save new objects with insert(), and save existing objects with update(). The following code fragment creates a new Employee object, calls insert() to save it, saves the database Id in myId, and then erases the in-memory object:
  Employee Emp = new Employee ();
  Emp.name = "Huck Finn";
  Emp.ssn = "111-22-3333";
  Emp.salary = "44500";
  Object  myId = objManager.insert(Emp, true);
  Emp = null;
Later, the object is reopened (using the saved database Id), a property is changed, and update() is called to save the existing object:
  Employee Emp2 = (Employee)objManager.openById(Employee.class, myId);
  Emp2.salary = "55000";
  objManager.update(Emp2, true);
save()
When a routine must deal with both new and existing objects, the save() method can be used. It determines which operation to perform by testing to see if the object has a database Id, or if the database contains an instance with the same primary key. The following method attempts to save an instance of Employee without knowing whether or not it already exists in the database:
  protected void saveEmployee (Employee Emp) throws Exception {
    objManager.save (Emp, true);
  }
In some cases, it may not be possible for the save() method to make a correct decision about whether to insert or update. For example, suppose we mistakenly save a new object that has the same primary key as an existing object. The insert() method would throw a database constraint error (“UNIQUE or PRIMARY KEY Constraint failed uniqueness check upon INSERT”), but save() would simply update the existing object with the new data.
This problem can be solved by using the @ID annotation to store a copy of the database Id in the POJO object. If a POJO has a placeholder and its value is not null, save() attempts to update the existing database instance. If the value is null, a new database instance is inserted. This solution may not work if the placeholder is primitive type int, which is initialized to 0 rather than null. Although 0 is not a valid Id, save() will attempt to update rather than insert if the Id is non-null, throwing an exception when the invalid update fails.
Accessing Objects by Id
The following methods can be used to determine the database Id of an object, and open or delete it by Id:
getId()
The getId() method returns the internal database Id of the given object. It returns null if the object is not open (or has not yet been inserted into the database). The following example inserts a recently created Employee object into the database, and later tests to see if it is still open before modifying and updating it:
  objManager.insert(Emp, true);
  ...
  if (objManager.getId(Emp)!=null) {
    Emp.name("Smith, Clem");
    objManager.update(Emp, true);
  }
openById()
The openById() method opens an object by referencing the class name and database Id:
  Employee Emp = (Employee)objManager.openById(Employee.class, myId);
The object is returned as java.lang.Object, and must be cast to the appropriate class.
removeFromDatabase()
The removeFromDatabase() method deletes an object from the database. If the object is open, the object reference can be passed directly to the method:
  objManager.removeFromDatabase(Emp);
Otherwise, the object can be deleted by reference to its class and database Id:
  objManager.removeFromDatabase(Employee.class, myId);
Also see the killExtent() method, which removes all members of a class from the persistent database.
Accessing Objects by Primary Key
The following methods can be used to determine the primary key of an object, and open or delete it by primary key:
getPrimaryKey() and openByPrimaryKey()
The openByPrimaryKey() method uses a PrimaryKey value to find and open an object in the persistent database. The key can be either a string, or an object returned by the getPrimaryKey() method. In each of the following examples, a key value is obtained from an open Employee object, the object is destroyed, and then openByPrimaryKey() is called to open it again:
  String keystr = Emp.ssn;
//   keystr value is "448-76-5499"
  Emp = null;
  Emp = (Employee)objManager.openByPrimaryKey(Employee.class, keystr)
  Object key = objManager.getPrimaryKey(Emp);
  Emp = null;
  Emp = (Employee)objManager.openByPrimaryKey(Employee.class, key)
  Object key = objManager.getPrimaryKey(Emp);
  String keystr = key.toString();
//   keystr value is "TinyPojo.Employee:EmpIdx {ssn} [448-76-5499]"
  Emp = null;
  Emp = (Employee)objManager.openByPrimaryKey(Employee.class, keystr)
removeFromDatabaseByPrimaryKey()
The removeFromDatabaseByPrimaryKey() method removes an instance of given class with a given ID from the database. The key can be in any of the formats described previously for openByPrimaryKey().
Object key = objManager.getPrimaryKey(Emp);
objManager.removeFromDatabaseByPrimaryKey(Employee.class, key);
Also see the killExtent() method, which removes all members of a class from the persistent database.
Opening Objects by Query
Use the openByQuery() method to open a set of database objects specified by an SQL query.
openByQuery()
The openByQuery() method returns an iterator that can be used to open all database objects that satisfy a given SQL query. The following method uses the simplest form of openByQuery() to open and display all Employee objects in the database:
  private static void displayEmployees () throws Exception
  {
    Iterator empList = objManager.openByQuery (Employee.class, null, null);
    while (empList.hasNext ()) {
      Employee nextEmp = (Employee)empList.next ();
      Object newId = objManager.getId(nextEmp);
      System.out.println("   Id:"+ newId + ": " + nextEmp.showProps());
    }
  }
The following slightly more complex example supplies a partial SQL statement and a parameter. This example opens all Employee instances where the employee name starts with param:
  String sql = "name %STARTSWITH ?";
  Object[] param = new Object[]{"M"};
  Iterator empList = objManager.openByQuery (Employee.class, sql, param);
The previous examples use a form of openByQuery() that can only refer to the properties of the specified class. For more complex queries, omit the class name and provide a complete SQL statement. The following example opens and displays all Employee objects in the Sales and Training departments with salaries higher than $50,000:
  // Find employees and managers in Sales or Training with
  // salaries higher than $50,000.

  private static void highSalaries () throws Exception
  {
    String sql =
        "SELECT tinyproject.Employee.%ID, tinyproject.Department.deptname "
      + "FROM tinyproject.Employee, tinyproject.Department "
      + "WHERE (tinyproject.Employee.department = tinyproject.Department.ID "
      + "    OR tinyproject.Employee.ID = tinyproject.Department.manager ) "
      + "AND tinyproject.Department.deptname IN (?,?) "
      + "AND tinyproject.Employee.salary > ? "
      + "ORDER by tinyproject.Employee.salary DESC";

    Object[] param = new Object[]{"Sales","Training","50000"};

    Iterator employees = objManager.openByQuery (sql, param);
    for (Iterator it = employees; it.hasNext ();) {
      Employee nextEmp = (Employee)it.next ();
      System.out.println(
        " dept:"+ nextEmp.department.deptname + nextEmp.showProps());
    }
  }
Performing Transactions
ObjectManager provides the following methods for transaction processing:
Transaction processing is a complex subject, and a realistic example would be beyond the scope of this chapter, but the basic methods can be demonstrated quite simply. The following example inserts several Employee objects into the database, and simulates an error condition by trying to insert one of the objects twice, causing the method to throw a primary key constraint error:
  public void makeTrans (ArrayList<Employee> empList) throws Exception
  {
// Create and add some bad data
    Employee badEmp = new Employee();
    badEmp.ssn = empList.get(0).ssn;
    badEmp.name = "Bademployee, Test A.";
    empList.add(2,badEmp);
// Process the list
    for (Iterator it = empList.iterator(); it.hasNext ();) {
      Employee nextEmp = (Employee)it.next ();
      objManager.startTransaction ();
      if (objManager.isInTransaction ()) {
        System.out.println("transaction: " + nextEmp.showProps());
      }
      try {
        objManager.insert(nextEmp, true);
        objManager.commit ();
      }
      catch (Exception e) {
        System.out.println("\tTransaction error: " + e.toString());
        objManager.rollback ();
      }
    }
  }
When the exception is encountered, the transaction is rolled back, and an error message is logged. The output from this method would look similar to the following:
  transaction: name:Gold,Lisa B. ssn:592-90-6581 salary:31327
  transaction: name:Zucherro,Maureen M. ssn:154-82-2410 salary:71473
  transaction: name:Bademployee, Test A. ssn:592-90-6581 salary:0
     Transaction error: com.intersys.objects.CacheServerException: 
  ...
  transaction: name:Press,Alvin D. ssn:782-72-3101 salary:96518
XML Serialization with ObjectManager.utilities
The ObjectManager.utilities class provides an interface to serialize objects (store objects as XML text) and deserialize them (convert the XML back to objects). This section describes two ways of doing this:
A class must be made serializable (annotated with @CacheClass(xmlSerializable)) before it can be processed by the ObjectManager.utilities methods. See Using @CacheClass xmlSerializable for detailed information.
Writing an XML String
Use the serializeToXML() method to store objects in XML strings. The serializeToXML() method creates a string containing an XML representation of a given object.
The following example serializes a set of Employee objects. It is assumed that the Employee class has been made serializable (see Using @CacheClass xmlSerializable).
serializeToXML()
This example serializes a set of Employee objects and stores their XML representations in a string. The method then returns the string after deleting the objects from the database.
A call to openByQuery() returns an iterator for all Employee objects in the database (see Opening Objects by Query). Each instance is serialized and stored in the string. Before an instance is serialized, the name property is altered so that it will be possible to distinguish the serialized version from the original:
public static String storeXmlString() throws Exception {
  System.out.println("\nWrite all Employee objects to an XML string:");
  java.lang.StringBuilder storeEmp = new java.lang.StringBuilder();

  storeEmp.append("<rootElement>");
  Iterator it = objManager.openByQuery (Employee.class, null, null);
  while (it.hasNext ()) {
    Employee Emp = (Employee)it.next ();
    Emp.name = Emp.name + " (xml)";
    String xmlStr = objManager.utilities().serializeToXML(Emp, "UTF-8", null);
    storeEmp.append(xmlStr);
    System.out.println("  " + xmlStr);
  }
  storeEmp.append("</rootElement>");
After all instances have been serialized, the Employee objects are deleted from the persistent database, and the XML string is returned:
  System.out.println("Deleting all Employee objects from database.\n");
  objManager.extentManager ().killExtent (Employee.class);

  System.out.println(
    "\nCreated object string:\n" +
    "start>>\n" + storeEmp.toString() + "\n<<end\n");
  return storeEmp.toString();
}
When this method is run, the console output will look similar to the following:
Write all Employee objects to XML strings:
  <Employee><name>Xenia,Roger S. (xml)</name><salary>39484</salary>
<ssn>645-49-9613</ssn></Employee>
  <Employee><name>Nathanson,Debra K. (xml)</name><salary>82396</salary>
<ssn>930-76-7567</ssn></Employee>

Delete all Employee objects from memory and database.
Creating an XML Document
Use the startXMLDocument(), addToXMLDocument(), and closeXMLDocument() methods to create a document object containing XML strings. The startXMLDocument() method creates an XML document that can contain serialized representations of objects. The addToXMLDocument() method adds an XML representation of a given object to the document object. The closeXMLDocument() method closes the document object and produces a String representation of the document.
The following example serializes a set of Employee objects and writes them to a file. It is assumed that the Employee class has been made serializable (see Using @CacheClass xmlSerializable).
startXMLDocument(), addToXMLDocument(), and closeXMLDocument()
The call to startXMLDocument() creates xmlDoc, an XML document object that will act as a container for a set of serialized Employee objects. The entire set of serialized objects will be placed inside a root element named <EmployeeList>.
private static void createXmlFile (String xmlFile) throws Exception {
  System.out.println("Add Employee objects to XML document:");

// Create XML document object
  String root = "EmployeeList";
  Object xmlDoc =
    objManager.utilities().startXMLDocument(root, "UTF-8", null);
The addToXMLDocument() method is used to serialize each Employee object and insert it into xmlDoc:
  Iterator it = objManager.openByQuery (Employee.class, null, null);
  while (it.hasNext ()) {
    Employee newEmp = (Employee)it.next ();
    objManager.utilities ().addToXMLDocument (xmlDoc, newEmp);
    System.out.println("  " + newEmp.showProps());
  }
After all Employee objects have been added, the closeXMLDocument() method is called to convert the contents of the document object into an XML string:
  String xmlStr = objManager.utilities ().closeXMLDocument (xmlDoc);
  System.out.println("\nCreated document object:\n" + xmlStr);
Finally, the XML string is written to a file:
  System.out.println("\nWriting document to file:\n\t" + xmlFile);
  java.io.PrintStream outFile =
    new java.io.PrintStream (new java.io.FileOutputStream (xmlFile));
  outFile.println (xmlStr);
  outFile.flush ();
  outFile.close ();
}
When this method is run, the console output will look similar to the following:
Add Employee objects to XML document:
  name:Xenia,Roger S. (xml) salary:39484 ssn:645-49-9613
  name:Nathanson,Debra K. (xml) salary:82396 ssn:930-76-7567

Created document object:
<?xml version="1.0" encoding="UTF-8"?>
<EmployeeList><Employee><name>Xenia,Roger S. (xml)</name><salary>39484</salary>
<ssn>645-49-9613</ssn></Employee><Employee><name>Nathanson,Debra K. (xml)</name>
<salary>82396</salary><ssn>930-76-7567</ssn></Employee></EmployeeList>

Writing document to file:
    C:\Dev\TinyPojo\EmployeeList.xml
Reading Serialized Objects
Use the readFromXML() method to access objects in XML strings. The readFromXML() method reads the XML string and converts it back into an object in memory. If possible, it then saves the object to the database.
The following example deserializes a set of Employee objects.
readFromXML()
In this example, the serialized objects previously stored in the string are deserialized by readFromXML(). If there is an open connection to the database, the objects will be saved, but they will not be opened, so the call to getId() should always return null:
public static void getXmlString(String xmlStr) throws Exception {
  System.out.println("Dserialize objects and save them to the database:");

// Read serialized Employees
  List list =
    (List)objManager.utilities ().readFromXML (Employee.class, xmlStr);
  for (Iterator it = list.iterator (); it.hasNext ();)
  {
    Employee Emp = (Employee) it.next ();
    Object newId = objManager.getId(Emp);
    System.out.println("  Id:"+ newId + Emp.showProps());
  }

The restored database objects are opened and displayed. After they have been opened, the call to getId() will return a valid Id:
// Display recovered Employee objects
  System.out.println("\ngetXmlString() recovered Employee objects:");
  Iterator it = objManager.openByQuery (Employee.class, null, null);
  while (it.hasNext ()) {
    Employee Emp = (Employee)it.next ();
    Object newId = objManager.getId(Emp);
    System.out.println("  Id:"+ newId + Emp.showProps());
  }
}
When this method is run, the console output will look similar to the following:
Deserialize objects and add them to the database:
  Id:null name:Xenia,Roger S. (xml) salary:39484 ssn:645-49-9613
  Id:null name:Nathanson,Debra K. (xml) salary:82396 ssn:930-76-7567

Deserialized Employee objects:
  Id:1 name:Xenia,Roger S. (xml) salary:39484 ssn:645-49-9613
  Id:2 name:Nathanson,Debra K. (xml) salary:82396 ssn:930-76-7567
Reading Serialized Objects from a File
The contents of an XML file can be passed directly to readFromXML(). The following example just reads a file and passes it to the getXmlString() method listed in the previous example:
  private static void readXmlFile (String xmlFile) throws Exception {
    System.out.println ("Get list of serialized Employee objects from file:");
  
    java.io.BufferedReader inBuf =
      new java.io.BufferedReader (new java.io.FileReader (xmlFile));
    java.lang.StringBuilder inStr = new java.lang.StringBuilder();
    while (inBuf.ready ()) inStr.append(inBuf.readLine ());
    getXmlString(inStr.toString());
  }
Database Maintenance with ObjectManager.extentManager
The ObjectManager.extentManager interface provides methods for generating and deleting data.
The examples in this section use both the Employee class and the Department class from the TinyPojo project (see Creating a Jalapeño Project).
Deleting Test Data
The following methods can be used to delete class definitions and test data from the database:
deleteClassDefinition()
The deleteClassDefinition() method deletes the definition of a given class from the persistent database. For example, if the following code were called from within the tinyproject package, it would delete Employee.cls and Department.cls from the USER.tinyproject namespace:
objMgr.extentManager().deleteClassDefinition (Employee.class);
objMgr.extentManager ().deleteClassDefinition (Department.class);
killExtent()
The killExtent() method deletes all instances of the class (and its subclasses) from the database. The following method deletes all in-memory objects with purgeEverything(), and then deletes all instances of Employee and Department from the database:
public void cleanupMyDatabase ()
{
  objMgr.purgeEverything ();
  objMgr.extentManager ().killExtent (Employee.class);
  objMgr.extentManager ().killExtent (Department.class);
}
For information on classmethod %KillExtent, see Deleting Saved Objects in Using Caché Objects, and the class documentation for %Library.Persistent. This method can also be called directly from the command line (see Calling KillExtent from the Command Line).
Creating Test Data
The following methods can be used to create sets of test data and refresh the indices for a class:
populate()
The populate() method creates randomly populated instances of the given class in the database. This method can only be applied to classes that use the @CacheClass(populatable) annotation (see Using @CacheClass populatable).
The following method generates num instances of the TinyPojo project's Employee class in the database, and then opens and displays each Employee instance:
public static void  populateDatabase (int num) throws Exception
{
  int ret = objManager.extentManager().populate(Employee.class, num);
  System.out.println ("Created " + ret + " Employee objects.");
  for (Iterator it = 
    objManager.openByQuery(Employee.class, null, null); it.hasNext();)
  {
    Employee Emp = (Employee)it.next();
    Object newId = objManager.getId(Emp);
    System.out.println( "\nId:" + newId + "  " + Emp.showProps() ); 
  }
}
rebuildIndices()
The rebuildIndices method rebuilds all entries for each index that originates in the specified class. The following method uses killExtent() to delete all instances of the TinyPojo project's Employee class from the database, calls the method presented in the previous example to repopulate with new data items, and then calls rebuildIndices() to rebuild the indices for the class:
public void newEmployeeData ()
{
  objMgr.extentManager ().killExtent (Employee.class);
  populateDatabase (10);
  objMgr.extentManager ().rebuildIndices(Employee.class);
}
Calling PopulateUtils from a Java Application
In some cases, it may be desirable to generate test data from within your Java application rather than using a pre-generated test database. The com.intersys.classes.PopulateUtils class provides an easy way to access the functions of the Caché %Library.PopulateUtils class from Java.
The following example is a class that can be added to the TinyPojo project (see Creating a Jalapeño Project) to generate populated instances of the project's Employee class:
class MakeEmployee
  package tinyproject;
  import com.jalapeno.annotations.Transient;

  import com.intersys.objects.Database;
  import com.intersys.objects.CacheDatabase;
  import com.intersys.classes.PopulateUtils;
  import java.util.ArrayList;

  &Transient
  public class MakeEmployee
  {
    private Database db;

    MakeEmployee (String url, String user, String pwd) throws Exception {
      db = CacheDatabase.getReadOnlyDatabase(url, user, pwd);
    }

    public ArrayList<Employee> empList (int min, int max, Department dept) throws Exception {
      ArrayList<Employee> staffList = new ArrayList<Employee>();
      int staffNum = PopulateUtils.Integer(db, min, max);
      for(int i = 0; i < staffNum; i++) {
        Employee newEmp = new Employee();
        newEmp.name = PopulateUtils.Name (db);
        newEmp.salary = PopulateUtils.Integer(db, 25000, 120000);
        newEmp.ssn = PopulateUtils.SSN (db);
        newEmp.department = dept;
        staffList.add(newEmp);
      }
      return staffList;
    }
  }
The CacheDatabase.getReadOnlyDatabase() method returns a standard Caché Java binding Database object (see Creating a Connection Object in Using Java with Caché). PopulateUtils uses this link to call the various classmethods of the %Library.PopulateUtils class.
Here is a method that uses MakeEmployee.empList() to generate and insert a set of new Department and Employee objects:
  public void makeDept () throws Exception {
// Create an empty Management department
    Department Managers = new Department();
    Managers.deptname = "Management";

// Create and fill the other departments
    String [] deptnames = {"Operations","Sales","Training"};
    for(int i = 0; i < deptnames.length; i++) {
      Department newDept = new Department();
      newDept.deptname = deptnames[i];
      newDept.staff = MakeEmployee.empList(2, 4, newDept);
      newDept.manager = MakeEmployee.empList(1, 1, Managers).get(0);

// Insert the new department. Deep save also inserts all 
// employees in the staff list.
      TinyPojo.objManager.insert(newDept, true);
    }
// Insert the Management department and all managers. 
    TinyPojo.objManager.insert(Managers, true);
  }