Finding out if database supports a transaction isolation level

You can get an instance of DatabaseMetaData by invoking getMetaData on a connection. Then you can query whether or not your db supports a certain isolation level by invoking supportsTransactionIsolationLevel.

Main.java:

import java.util.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) throws Exception {
      try {
         Class.forName("org.gjt.mm.mysql.Driver").newInstance();
         Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.1/esus", 
                                                       "joris",
                                                       "mypass");
 
         DatabaseMetaData dbMeta = conn.getMetaData(); 
         System.out.println(dbMeta.supportsTransactionIsolationLevel(
                                               Connection.TRANSACTION_READ_COMMITTED));
         System.out.println(dbMeta.supportsTransactionIsolationLevel(
                                               Connection.TRANSACTION_READ_UNCOMMITTED));
         System.out.println(dbMeta.supportsTransactionIsolationLevel(
                                               Connection.TRANSACTION_REPEATABLE_READ));
         System.out.println(dbMeta.supportsTransactionIsolationLevel(
                                               Connection.TRANSACTION_SERIALIZABLE));
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Transaction isolation level

Imagine a multi-user system where user A is performing an some updates in a table in a transactional context while another user B is trying to read from it. Some problems arise, for example: should B be able to read uncommitted updates by A? This is an important issue because B could get an inconsistent view on the tables.

These types of inconsistensies could occur:

  • dirty-read: A has changed a row in the table, but hasn’t committed yet. B reads it, but the data could in fact be non-existent, since A may still roll back later.
  • non-repeatable read: B performs a read, but A modifies or deletes it during its transaction. If B reads the same row again, it will get no or different results.
  • phantoms: A does a query on a set of rows to perform an operation. B modifies the table such that the query of A would have given a different result. The table may be left inconsistent.

The transaction isolation level is used to solve these issues. The default isolation level is TRANSACTION_SERIALIZABLE, where all of the aforementioned inconsistensies will not occur. This is excellent where data integrity is crucial. However, because of locking, it has low performance.

The other options are documented in the API, interface java.sql.Connection:

static int TRANSACTION_READ_COMMITTED 
          Dirty reads are prevented; non-repeatable reads and phantom reads can occur. 
static int TRANSACTION_READ_UNCOMMITTED 
          Dirty reads, non-repeatable reads and phantom reads can occur. 
static int TRANSACTION_REPEATABLE_READ 
          Dirty reads and non-repeatable reads are prevented; phantom reads can occur. 
static int TRANSACTION_SERIALIZABLE 
          Dirty reads, non-repeatable reads and phantom reads are prevented. 

You can set the transaction isolation level with the method setTransactionIsolation on a particular connection:

   conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

Using transactions with JDBC

SQL statements can be grouped together in a single statement to ensure the ACID (Atomicity, Consistency, Isolation, Durability) characteristics. By default, each SQL statement is auto-commited. In other words, it is treated as a transaction by itself and will be committed right away. This may not be desirable in cases where all the SQL statements need to be executed or none of them, if one fails. The way this can be done with JDBC is by turning off auto-commit mode before the group of statements and turn auto-commit back on after.

   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();
   stmt.executeUpdate("UPDATE accounts SET balance = 100 where accountid = 1");
   stmt.executeUpdate("UPDATE products SET itemsleft = 0 where prodid = 4");
   stmt.rollback();
   stmt.executeUpdate("UPDATE products SET itemsleft = 0 where prodid = 3");
   stmt.commit();
   conn.setAutoCommit(true);  

In this example, the first two updates will not affect the database table because of rollback. The last update is explicitely committed.

Typically, you would use commit and rollback in conjunction with Exception handling. eg.

   try {
      conn.setAutoCommit(false);
 
      updateInventory();
      updateBalance();
 
      conn.commit();
      conn.setAutoCommit(true);
   }
   catch(ShoppingException e) {
      e.printStackTrace();
      conn.rollback();
      conn.setAutoCommit(true);
   }

Using a PreparedStatement

If you need to execute a certain SQL statement a number of times, you can have it optimized by the underlying DBMS by using a PreparedStatement. A PreparedStatement is called a precompiled SQL statement, but can still be parametrized. In other words, it can accept certain input parameters.

So:

   Statement stmt = connection.createStatement();
   stmt.executeUpdate("INSERT INTO products (description, price) " +
                      "VALUES ('Chateau Meyney, St. Estephe', 18.75, 2)");

will have the same result as:

   PreparedStatement insertStmt = connection.prepareStatement("
                                       "INSERT INTO products (description, price) " +
                                       "VALUES (?, ?, ?)";
   insertStmt.setString(1, "Chateau Meyney, St. Estephe");
   insertStmt.setFloat(2, 18.75f);
   insertStmt.setInt(3, 2);
   insertStmt.executeUpdate();

The latter one does take somewhat more time to set up (precompilation), but if you need to insert a lot of rows, it is beneficial cause you can reuse insertStmt and change its parameters.

executeUpdate returns the number of rows that were affected.

You can do the same thing for SELECT statements with executeQuery. It returns a ResultSet containing the rows that match your query.

If you need to clear the parameters that were set, invoke the method clearParameters.

Main.java:

import java.util.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) {
      try {
         Database db = new Database("org.gjt.mm.mysql.Driver",
                                    "jdbc:mysql://192.168.0.1/esus",
                                    "joris",
                                    "mypass");
         Connection con = db.getConnection();
         ProductDAO prodDAO = new ProductDAO(con);
 
         printCollection(prodDAO.getAllRows()); 
 
         prodDAO.insert(new Product("Chateau Meyney, St. Estephe",       18.75f, 2));
         prodDAO.insert(new Product("Chateau Montrose, St. Estephe",     54.25f, 2));
         prodDAO.insert(new Product("Chateau Gloria, St. Julien",        22.99f, 2));
         prodDAO.insert(new Product("Chateau Beychevelle, St. Julien",   61.63f, 2));
         prodDAO.insert(new Product("Chateau La Tour de Mons, Margeaux", 57.03f, 2));
         prodDAO.insert(new Product("Chateau Brane-Cantenac, Margeaux",  49.92f, 2));
  
         printCollection(prodDAO.getAllRows()); 
         db.close();
      }
      catch(DatabaseException e) {
         e.printStackTrace();
      }
   }
 
   public static void printCollection(Collection c) {
      Iterator iter = c.iterator();
      while (iter.hasNext()) {
         System.out.println(iter.next());
      }
   }
}
 
class Product
{
   private String description;
   private float price;
   private int itemsleft;
 
   public Product() { }
 
   public Product(String description, float price, int itemsleft) {
      setDescription(description);
      setPrice(price);
      setItemsleft(itemsleft);
   }
  
   public void setDescription(String description) {
      this.description = description;
   }
 
   public void setPrice(float price) {
      this.price = price;
   }

   public void setItemsleft(int itemsleft) {
      this.itemsleft = itemsleft;
   }
 
   public String getDescription() {
      return description;
   }
 
   public float getPrice() {
      return price;
   }
  
   public int getItemsleft() {
      return itemsleft;
   }
 
   public String toString() {
      return "Product [description=" + getDescription() + ", price=" + getPrice() + 
             ", itemsleft=" + getItemsleft() + "]";
   }
}
 
class Database
{
   Connection connection = null;
  
   public Database(String driver, String url, String user, String pass) 
                      throws DatabaseException 
   {
      try {
         Class.forName(driver).newInstance();
 
         connection = DriverManager.getConnection(url, user, pass);
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Connection getConnection() {
      return connection;
   }
 
   public void close() throws DatabaseException {
      try {
         connection.close();
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   } 
}   
 
class DatabaseException extends Exception {
   public DatabaseException() {
   }
 
   public DatabaseException(String message) {
      super(message);
   }
}
 
class ProductDAO 
{
   Connection connection = null;
   PreparedStatement insertStmt = null;
 
   public ProductDAO(Connection connection) {
      this.connection = connection;
   }
 
   public void insert(Product prod) throws DatabaseException {
      try {
         if (insertStmt == null) {
            insertStmt = connection.prepareStatement(
                            "INSERT INTO products (description, price, itemsleft) " +
                            "VALUES (?, ?, ?)");
         }
 
         insertStmt.setString(1, prod.getDescription());
         insertStmt.setFloat(2, prod.getPrice());
         insertStmt.setInt(3, prod.getItemsleft());
         insertStmt.executeUpdate();  
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Collection getAllRows() throws DatabaseException {
      try {
         ArrayList al = new ArrayList();
 
         Statement stmt = connection.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM products");
         while (rs.next()) {
            Product prod = new Product();
            prod.setDescription(""+rs.getString("description"));
            prod.setPrice(rs.getFloat("price"));
            prod.setItemsleft(rs.getInt("itemsleft"));
            al.add(prod);
         }
         
         stmt.close();
 
         return al;
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
}

Update rows from a database table

Check out the MySQL syntax for UPDATE here.

Here’s an example that modifes a value in the customer table. You need to create a Statement object from a Connection and invoke executeUpdate on it, passing it the SQL UPDATE command. It returns a ResultSet containing the database rows that match your query. You can then iterate over the rows with the next method. The first call to next will position the “cursor” to the first row. You can get a particular column in that row with the getXXX methods, specifying either the column index or the column name. Make sure the database column type and the resulting variable type match, or a proper conversion is done. If types don’t match, a Bad format SQLException is thrown.

Main.java:

import java.util.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) {
      try {
         Database db = new Database("org.gjt.mm.mysql.Driver",
                                    "jdbc:mysql://192.168.0.1/esus",
                                    "joris",
                                    "mypass");
         Connection con = db.getConnection();
         CustomerDAO custDAO = new CustomerDAO(con);
 
         printCollection(custDAO.getAllRows()); 
 
         Customer cust = custDAO.getCustomer("Joris Van den Bogaert");
         if (cust != null) {
            cust.setEmail("joris_vandenbogaert1@yahoo.com");
            custDAO.updateEmail(cust);
         }
  
         System.out.println();
         printCollection(custDAO.getAllRows()); 
         db.close();
      }
      catch(DatabaseException e) {
         e.printStackTrace();
      }
   }
 
   public static void printCollection(Collection c) {
      Iterator iter = c.iterator();
      while (iter.hasNext()) {
         System.out.println(iter.next());
      }
   }
}
 
class Customer
{
   private String name;
   private String email;
 
   public Customer() { }
 
   public Customer(String name, String email) {
      setName(name);
      setEmail(email);
   }
  
   public void setName(String name) {
      this.name = name;
   }
 
   public void setEmail(String email) {
      this.email = email;
   }
 
   public String getName() {
      return name;
   }
 
   public String getEmail() {
      return email;
   }
 
   public String toString() {
      return "Customer [name=" + getName() + ", email=" + getEmail() + "]";
   }
}
 
class Database
{
   Connection connection = null;
  
   public Database(String driver, String url, String user, String pass) 
                      throws DatabaseException 
   {
      try {
         Class.forName(driver).newInstance();
 
         connection = DriverManager.getConnection(url, user, pass);
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Connection getConnection() {
      return connection;
   }
 
   public void close() throws DatabaseException {
      try {
         connection.close();
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   } 
}   
 
class DatabaseException extends Exception {
   public DatabaseException() {
   }
 
   public DatabaseException(String message) {
      super(message);
   }
}
 
class CustomerDAO 
{
   Connection connection = null;
 
   public CustomerDAO(Connection connection) {
      this.connection = connection;
   }
 
   public void updateEmail(Customer cust) throws DatabaseException {
      try {
         Statement stmt = connection.createStatement();
 
         stmt.executeUpdate("UPDATE customers SET email = '" + cust.getEmail() + "' " +
                            "WHERE name = '" + cust.getName() + "'");
         stmt.close();      
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Customer getCustomer(String name) throws DatabaseException {
      try {
         Statement stmt = connection.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM customers " +
                                          "WHERE name='" + name + "'");
         if (rs.next()) {
            Customer cust = new Customer();
            cust.setName(rs.getString("name"));
            cust.setEmail(rs.getString("email"));
            return cust;
         }
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
 
      return null;
   } 
 
   public Collection getAllRows() throws DatabaseException {
      try {
         ArrayList al = new ArrayList();
 
         Statement stmt = connection.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM customers");
         while (rs.next()) {
            Customer cust = new Customer();
            cust.setName(""+rs.getString("name"));
            cust.setEmail(rs.getString("email"));
            al.add(cust);
         }
         
         stmt.close();
 
         return al;
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
}

outputs:

Customer [name=Joris Van den Bogaert, email=joris1@esus.com]
Customer [name=Alicia Kolesnikova, email=alicia1@esus.com]

Customer [name=Joris Van den Bogaert, email=joris_vandenbogaert1@yahoo.com]
Customer [name=Alicia Kolesnikova, email=alicia1@esus.com]

Retrieving rows from a database table using JDBC

Check out the MySQL syntax for SELECT here.

Here’s an example that gets all the rows from a customer table. You need to create a Statement object from a Connection and invoke executeQuery on it, passing it the SQL SELECT command. It returns a ResultSet containing the database rows that match your query. You can then iterate over the rows with the next method. The first call to next will position the “cursor” to the first row. You can get a particular column in that row with the getXXX methods, specifying either the column index or the column name. Make sure the database column type and the resulting variable type match, or a proper conversion is done. If types don’t match, a Bad format SQLException is thrown.

Main.java:

import java.util.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) {
      try {
         Database db = new Database("org.gjt.mm.mysql.Driver",
                                    "jdbc:mysql://192.168.0.1/esus",
                                    "joris",
                                    "mypass");
         Connection con = db.getConnection();
         CustomerDAO custDAO = new CustomerDAO(con);
 
         Collection c = custDAO.getAllRows();
         Iterator iter = c.iterator();
         while (iter.hasNext()) {
            System.out.println(iter.next());
         }
  
         db.close();
      }
      catch(DatabaseException e) {
         e.printStackTrace();
      }
   }
}
 
class Customer
{
   private String name;
   private String email;
 
   public Customer() { }
 
   public Customer(String name, String email) {
      setName(name);
      setEmail(email);
   }
  
   public void setName(String name) {
      this.name = name;
   }
 
   public void setEmail(String email) {
      this.email = email;
   }
 
   public String getName() {
      return name;
   }
 
   public String getEmail() {
      return email;
   }
 
   public String toString() {
      return "Customer [name=" + getName() + ", email=" + getEmail() + "]";
   }
}
 
class Database
{
   Connection connection = null;
  
   public Database(String driver, String url, String user, String pass) 
                      throws DatabaseException 
   {
      try {
         Class.forName(driver).newInstance();
 
         connection = DriverManager.getConnection(url, user, pass);
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Connection getConnection() {
      return connection;
   }
 
   public void close() throws DatabaseException {
      try {
         connection.close();
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   } 
}   
 
class DatabaseException extends Exception {
   public DatabaseException() {
   }
 
   public DatabaseException(String message) {
      super(message);
   }
}
 
class CustomerDAO 
{
   Connection connection = null;
 
   public CustomerDAO(Connection connection) {
      this.connection = connection;
   }
 
   public Collection getAllRows() throws DatabaseException {
      try {
         ArrayList al = new ArrayList();
 
         Statement stmt = connection.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM customers");
         while (rs.next()) {
            Customer cust = new Customer();
            cust.setName(rs.getString("name"));
            cust.setEmail(rs.getString("email"));
            al.add(cust);
         }
         
         stmt.close();
 
         return al;
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
}

Inserting data in a database table

Here’s an example that populates a customer table. Basically, get a statement from a connection and call executeUpdate passing in the insert SQL statement.

Notice that this answer is using plain JDBC. Maybe you would like to check out JPA these days (Hibernate, EclipseLink, …)

Main.java:

import java.util.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) {
      try {
         Database db = new Database("org.gjt.mm.mysql.Driver",
                                    "jdbc:mysql://192.168.0.1/esus",
                                    "joris",
                                    "mypass");
         Connection con = db.getConnection();
         CustomerDAO custDAO = new CustomerDAO(con);
 
         Customer cust1 = new Customer("Joris Van den Bogaert", "joris1@esus.com");
         Customer cust2 = new Customer("Alicia Kolesnikova", "alicia1@esus.com");
 
         custDAO.insert(cust1);
         custDAO.insert(cust2);
 
         db.close();
      }
      catch(DatabaseException e) {
         e.printStackTrace();
      }
   }
}
 
class Customer
{
   private String name;
   private String email;
 
   public Customer(String name, String email) {
      setName(name);
      setEmail(email);
   }
 
   public String getName() {
      return name;
   }
 
   public String getEmail() {
      return email;
   }
}
 
class Database
{
   Connection connection = null;
  
   public Database(String driver, String url, String user, String pass) 
                      throws DatabaseException 
   {
      try {
         Class.forName(driver).newInstance();
 
         connection = DriverManager.getConnection(url, user, pass);
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Connection getConnection() {
      return connection;
   }
 
   public void close() throws DatabaseException {
      try {
         connection.close();
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   } 
}   
 
class DatabaseException extends Exception {
   public DatabaseException() {
   }
 
   public DatabaseException(String message) {
      super(message);
   }
}
 
class CustomerDAO 
{
   Connection connection = null;
 
   public CustomerDAO(Connection connection) {
      this.connection = connection;
   }
 
   public void insert(Customer cust) throws DatabaseException {
      try {
         PreparedStatement stmt = connection.createPreparedStatement();
         stmt.executeUpdate("INSERT INTO customers (name, email) " + 
                            "VALUES (?, ?)'");
         stmt.setString(1, cust.getName());
         stmt.setString(2, cust.getEmail());
         stmt.close();
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
}

Creating a database table using JDBC

Check out the MySQL syntax for CREATE TABLE here.

Here’s an example that creates 4 tables in the database esus. Create your SQL create table query string and call executeUpdate on a Statement.

Main.java:

import java.util.*;
import java.sql.*;
 
public class Main {
   public static void main(String []args) {
      try {
         Database db = new Database("org.gjt.mm.mysql.Driver",
                                    "jdbc:mysql://192.168.0.1/esus",
                                    "joris",
                                    "mypass");
 
         db.createTable("customers", "custid int(10) not null auto_increment, " +
                                     "name varchar(30), " +
                                     "email varchar(50), " + 
                                     "primary key(custid)");
         db.createTable("products", "prodid int(10) not null auto_increment, " +
                                    "description varchar(100), " +
                                    "price float(6, 2), " +
                                    "itemsleft int(10), " +
                                    "primary key(prodid)");
         db.createTable("orders", "orderid int(10) not null auto_increment, " + 
                                  "custid int(10), " +
                                  "timestamp datetime, " +
                                  "status tinyint, " +
                                  "primary key(orderid), " +
                                  "index custid (custid)");
         db.createTable("orderitems", "orderid int(10) not null, " +
                                      "prodid int(10) not null, " + 
                                      "quantity int(5) not null, " +
                                      "price float(10, 2) not null, " + 
                                      "primary key(orderid, prodid)";
         db.createTable("accounts", "accountid int(10) not null auto_increment, " +
                                    "custid int(10), " +
                                    "balance float(10,2), " +
                                    "primary key(accountid)");
      }
      catch(Database.DatabaseException e) {
         e.printStackTrace();
      }
   }
}
 
class Database
{
   Connection connection = null;
  
   public Database(String driver, String url, String user, String pass) 
                      throws DatabaseException 
   {
      try {
         Class.forName(driver).newInstance();
 
         connection = DriverManager.getConnection(url, user, pass);
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public void createTable(String table, String columns) throws DatabaseException {
      try {
         Statement stmt = connection.createStatement();
         stmt.executeUpdate("create table " + table + " (" + columns + ")");
         stmt.close();
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public class DatabaseException extends Exception {
      public DatabaseException() {
      }
 
      public DatabaseException(String message) {
         super(message);
      }
   }
}   

Retrieve a Java object from a file on the local file system using JDNI

You can bind an object into a context, provided your object is a Reference or implements the Referenceable interface. The object is stored in a file called .bindings as a set of properties.

The following example shows how to read the object created in the QA How do I store a Java object in a file on the local file system using JNDI?.

Read.java:

import javax.naming.event.*;
import javax.naming.*;
import java.util.*;
import java.io.*;
  
public class Read
{
   public static void main(String []args) {
      try {
         Properties properties = new Properties();
         properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
         properties.put(Context.PROVIDER_URL, "file:///");
 
         InitialContext ctx = new InitialContext(properties);
 
         Context context = (Context) ctx.lookup("c:\temp\");
 
         Member member = (Member) context.lookup("member.obj");
         System.out.println(member);
 
         ctx.close(); 
      }
      catch(NamingException ne) {
         ne.printStackTrace();
      }
   }
}

prints out:

[Joris Van den Bogaert, joris1@esus.com]

Store a Java object in a file on the local file system using JNDI

You can bind an object into a context, provided your object is a Reference or implements the Referenceable interface. The object is stored in a file called .bindings as a set of properties.

The following example shows how to store the object Member containing two Strings username and email.

Write.java:

import javax.naming.*;
import java.util.*;
import java.io.*;
  
public class Write
{
   public static void main(String []args) {
      try {
         Properties properties = new Properties();
         properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
         properties.put(Context.PROVIDER_URL, "file:///");
 
         InitialContext ctx = new InitialContext(properties);
 
         Context context = (Context) ctx.lookup("c:\temp\");
 
         Member member = new Member("Joris Van den Bogaert", "joris1@esus.com"); 
         context.rebind("member.obj", member);
 
         ctx.close(); 
      }
      catch(NamingException ne) {
         ne.printStackTrace();
      }
   }
}

Member.java:

import javax.naming.*;
 
class Member implements Referenceable 
{
   private String username;
   private String email;
 
   public Member(String username, String email) {
      this.username = username;
      this.email = email;
   }
 
   public String toString() {
      return "[" + username + ", " + email + "]";
   }
 
   public Reference getReference() throws NamingException {
      Reference reference = new Reference(Member.class.getName(),
                                          MemberFactory.class.getName(),
                                          null);
      reference.add(new StringRefAddr("username", username));
      reference.add(new StringRefAddr("email", email));
 
      return reference;
   }
}

MemberFactory.java:

import javax.naming.spi.ObjectFactory;
import javax.naming.*;
import java.util.*;
 
public class MemberFactory implements ObjectFactory
{
   public MemberFactory() { }
 
   public Object getObjectInstance(Object object, 
                                   Name name, 
                                   Context ctx, 
                                   Hashtable env) throws Exception {
      if (object instanceof Reference) {
         Reference reference = (Reference) object;
         if (reference.getClassName().equals(Member.class.getName())) {
            String username = (String) ((StringRefAddr) reference.get(0)).getContent();
            String email    = (String) ((StringRefAddr) reference.get(1)).getContent();
 
            return new Member(username, email);
         }
      }
 
      return null;
   }
}

The .bindings file, located in c:temp looks like a simple properties file:

#This file is used by the JNDI FSContext.
#Tue Jan 14 00:53:47 CET 2003
member.obj/RefAddr/0/Type=username
member.obj/RefAddr/1/Content=joris1@esus.com
member.obj/RefAddr/0/Content=Joris Van den Bogaert
member.obj/RefAddr/0/Encoding=String
member.obj/FactoryName=MemberFactory
member.obj/ClassName=Member
member.obj/RefAddr/1/Encoding=String
member.obj/RefAddr/1/Type=email