JPOX
JPOX
JPOX  |  Ver 1.0  |  Ver 1.1  |  Ver 1.2  |  JDO  |  JPA  |  Project
Java Data Objects
JDO Persistence Manager

To understand JPOX you need to understand the basics of JDO. Here we'll discuss a few basic ideas that are core to JDO. An application has 2 primary interfaces to JDO. These are the PersistenceManagerFactory, and the PersistenceManager. We explain in this section the role of these classes and the primary methods called on each.

PersistenceManagerFactory

The first point of access for an application developer is to obtain an PersistenceManagerFactory. This is typically performed as follows

Properties props=new Properties();
props.put("javax.jdo.PersistenceManagerFactoryClass","org.jpox.PersistenceManagerFactoryImpl");
props.put("javax.jdo.option.ConnectionDriverName","com.mysql.jdbc.driver");
props.put("javax.jdo.option.ConnectionURL","jdbc:mysql://localhost/jpox");
props.put("javax.jdo.option.ConnectionUserName","mysql");
props.put("javax.jdo.option.ConnectionPassword","");
PersistenceManagerFactory pmf=JDOHelper.getPersistenceManagerFactory(props);

So we've obtained our entry point into JDO (using JPOX), specifying the data store that we will be using (in this case a MySQL RDBMS datastore). If the application developer wants to use several datastores then they create one PersistenceManagerFactory for each. The PersistenceManagerFactory provides the mechanism for obtaining PersistenceManagers (see below), as well as controlling the connectivity to the datastore.

PersistenceManager

The PersistenceManager is the main interface to persistence of objects for the application developer. It is the interface to making an object persistent, as well as to retrieving persisted objects, and removing them from persistent storage. To obtain a PersistenceManager

PersistenceManager pm=pmf.getPersistenceManager();

We now can perform operations on objects, making them persistent, querying them, deleting them etc. The application developer needs to bear in mind that, in general, they need to perform all operations on objects within a transaction. This will be demonstrated below.

Making an object persistent

So the developer has an object that they want to persist. The following snippet demonstrates the way of doing this

MyClass my_obj=....;
Transaction tx;
try
{
    tx = pm.currentTransaction();
    tx.begin();

    pm.makePersistent(my_obj);

    tx.commit();
}
catch (Exception e)
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

The makePersistent method of PersistenceManager makes the object persistent in the datastore, and updates the 'state' of the object from Transient to Hollow.

When an object is persisted, if it has any other objects referenced from that object they they also will be made persistent. This is referred to as persistence-by-reachability. The main benefit of this is that if you have an object graph to persist, then you don't need to call makePersistent() on all objects, instead just using one that can be used to find all of the others. persistence-by-reachability is also run at the time of calling commit() on the transaction. This has the effect that if you had called makePersistent() on an object and that had persisted another object, and before commit you had removed the relation to this other object, then at commit() the reachability algorithm will find that this other object is no longer reachable and will remove it from persistence.

Retrieving an object from persistence

So we've made some of our objects persistent, and now we want to retrieve them in our application. Here's one way of retrieving objects of a particular type.

try
{
    tx = pm.currentTransaction();
    tx.begin();

    Extent e=pm.getExtent(mydomain.MyClass.class,true);
    Iterator iter=e.iterator();
    while (iter.hasNext())
    {
        MyClass my_obj=(MyClass)iter.next();
        ...
    }

    tx.commit();
}
catch (Exception e)
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

The Extent interface is one of the ways to retrieve your objects. The others use the Query interface, allowing more precise filtering over the objects returned.

Deleting an object from persistence

So we can persist objects, and retrieve them. Now we want to remove one from persistence.

try
{
    tx = pm.currentTransaction();
    tx.begin();

    ... (code to retrieve object in question) ...

    pm.deletePersistent(my_obj);

    tx.commit();
}
catch (Exception e)
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}
Making an object transient

As we have seen in the JDO States guide, an object can have many possible states. When we want to take an object and work on it, but removing its identity we can make it transient. This means that it will retain the values of its fields, yet will no longer be associated with the object in the datastore. We do this as follows

try
{
    tx = pm.currentTransaction();
    tx.begin();

    ... (code to retrieve object in question) ...

    pm.makeTransient(my_obj);

    tx.commit();
}
catch (Exception e)
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

... (code to work on "my_obj")
Attach/Detach of objects

In a similar vain to the previous section, we can place an object in a state that it can be worked on, but we want to retain its association to the object in the datastore. To do this we need to detach the object first, then we update it, and then we can push our changes to the object in the datastore by attaching this updated object. So we do this

Object detachedObj = null;

// Detach the object from the datastore
try
{
    tx = pm.currentTransaction();
    tx.begin();

    ... (code to retrieve object in question) ...

    detachedObj = pm.detachCopy(my_obj);

    tx.commit();
}
catch (Exception e)
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

... (code to work on "detachedObj")

// Attach the updated object to the datastore
try
{
    tx = pm.currentTransaction();
    tx.begin();

    pm.makePersistent(detachedObj);

    tx.commit();
}
catch (Exception e)
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

So we firstly detached the object, we then updated it elsewhere in our system, and we finally attached the updated object. This made the necessary changes to the datastore version of the object.

Refresh of objects

In the situation where you have an object and you think that its values may have changed in the datastore you can update its values to the latest using the following

pm.refresh(obj);

What this will do is as follows

  • Refresh the values of all FetchPlan fields in the object
  • Unload all non-FetchPlan fields in the object

If the object had any changes they will be thrown away by this step, and replaced by the latest datastore values.