The standard JPA and JDO runtime environments are
local and online. They are
local in that components such as
EntityManager
s,
PersistenceManager
s, and queries connect directly to
the datastore and execute their actions in the same JVM as the code using
them. They are online in that changes to
managed objects take place in the context of an active
EntityManager
or PersistenceManager
.
These two properties, combined with the fact that managers
cannot be serialized for storage or network transfer, make the standard
JPA and JDO runtimes difficult to
incorporate into some enterprise and client/server program designs.
Kodo extends the standard runtime to add remote and offline capabilities in the form of enhanced Detach and Attach APIs, Remote Managers, and Remote Commit Events. The following sections explain these capabilities in detail.
The JPA Overview describes JPA's standard detach and attach APIs in Chapter 8, EntityManager. The JDO Overview does the same for JDO in Section 8.7, “Detach and Attach Functionality”. This section enumerates Kodo's enhancements to the standard behavior.
In JPA, objects detach automatically when they are
serialized or when a persistence
context ends. The specification does not define any way to
explicitly detach objects. The extended
KodoEntityManager
, however, allows
you to explicitly detach objects at any time.
public Object detach (Object pc): public Object[] detachAll (Object... pcs): public Collection detachAll (Collection pcs):
Each detach method returns detached copies of the given instances. The copy mechanism is similar to serialization, except that only certain fields are traversed. We will see how to control which fields are detached in a later section.
When detaching an instance that has been modified in the current transaction (and thus made dirty), the current transaction is flushed. This means that when subsequently re-attaching the detached instances, Kodo assumes that the transaction from which they were originally detached was committed; if it has been rolled back, then the re-attachment process will throw an optimistic concurrency exception.
You can stop Kodo from assuming the transaction will commit by
invoking setRollbackOnly
prior to
detaching your objects. Setting the RollbackOnly
flag prevents Kodo from flushing
when detaching dirty objects; instead Kodo just runs its pre-flush
actions (see the
KodoEntityManager.preFlush
or
KodoPersistenceManager.preFlush
Javadoc for details).
This allows you to use the same
instances in multiple attach/modify/detach/rollback cycles.
Alternatively, you might also prevent a flush by making your
modifications outside of a transaction (with
NontransactionalWrite
enabled) before detaching.
When attaching, Kodo uses several strategies to determine the optimal way to merge changes made to the detached instance. As you will see, these strategies can even be used to attach changes made to a transient instance which was never detached in the first place.
If the instance was detached and detached state is enabled, Kodo will use the detached state to determine the object's version and primary key values. In addition, this state will tell Kodo which fields were loaded at the time of detach, and in turn where to expect changes. Loaded detached fields with null values will set the attached instance's corresponding fields to null.
If the instance has an application visible version field, Kodo will consider the object detached if the version field has a non-default value, and new otherwise.
When attaching null fields in these cases, Kodo cannot distinguish between a field that was unloaded and one that was intentionally set to null. In this case, Kodo will use the current detach state setting to determine how to handle null fields: fields that would have been included in the detached state are treated as loaded, and will in turn set the corresponding attached field to null.
If neither of the above cases apply, Kodo will check to see if an instance with the same primary key values exists in the database. If so, the object is considered detached. Otherwise, it is considered new.
These strategies will be assigned on a per-instance basis, such that during the attachment of an object graph more than one of the above strategies may be used.
If you attempt to attach a versioned instance whose representation
has changed in the datastore since detachment, Kodo will throw an
optimistic concurrency exception upon commit or flush, just as if
a normal optimistic conflict was detected. When attaching an
instance whose database record has
been deleted since detaching, or when attaching a detached
instance into a manager that has a stale version of the object,
Kodo will throw an optimistic concurrency exception
from the attach method. In these cases, Kodo sets the
RollbackOnly
flag on the transaction.
When detached objects lose their association with the Kodo
runtime, they also lose the ability to load additional state
from the datastore. It is important, therefore, to populate objects
with all the persistent state you will need before detaching them.
While you are free to do this manually, Kodo includes
facilities for automatically populating objects when they detach.
The kodo.DetachState
configuration property determines which fields
and relations are detached by default. All settings are recursive.
They are:
loaded
: Detach all fields and relations
that are already loaded, but don't include unloaded fields
in the detached graph. This is the default.
fgs
: Detach all fields and relations in
the default fetch group, and any other fetch groups that
you have added to the current
fetch
configuration. For more information on custom
fetch groups, see Section 5.6, “Fetch Groups”.
all
: Detach all fields and relations.
Be very careful when
using this mode; if you have a highly-connected domain
model, you could end up bringing every object in the
database into memory!
Any field that is not included in the set determined by the detach mode is set to its Java default value in the detached instance.
The kodo.DetachState
option is actually a
plugin string (see Section 2.5, “Plugin Configuration”) that
allows you to also configure the following options related to
detached state:
DetachedStateField
: As described in
Section 11.1.2, “Attach Behavior” above, Kodo can
take advantage of a detached state field
to make the attach process more efficient.
This field is added by the enhancer and is not visible to
your application. Set this property to one of the
following values:
transient
: Use a transient
detached state field. This gives the benefits of
a detached state field to local objects that are
never serialized, but retains
serialization compatibility for client tiers without
access to the enhanced versions of your classes.
This is the default.
true
: Use a non-transient
detached state field so that objects crossing
serialization barriers can still be attached
efficiently. This requires, however, that your
client tier have the enhanced versions of your
classes and the Kodo libraries.
false
: Do not use a detached
state field.
You can override the setting of this property or declare your own detached state field on individual classes using Kodo's metadata extensions. See Section 11.1.3.1, “Detached State Field” below.
DetachedStateManager
: Whether to use a
detached state manager. A detached state manager makes
attachment much more efficient. Like a detached state
field, however, it breaks serialization compatibility with
the unenhanced class if it isn't transient.
This setting piggybacks on the DetachedStateField
setting above. If your detached state field is
transient, the detached state manager will also be
transient. If the detached state field is disabled, the
detached state manager will also be disabled. This is
typically what you'll want. By setting
DetachedStateField
to true (or transient) and
setting this property to false, however, you can use a
detached state field without
using a detached state manager. This may be
useful for debugging or for legacy Kodo users who find
differences between Kodo's behavior with a detached state
manager and Kodo's older behavior without one.
AccessUnloaded
: Whether to allow access
to unloaded fields of detached objects. Defaults to true.
Set to false to throw an exception whenever an unloaded
field is accessed. This option is only available when you
use detached state managers, as determined by the settings
above.
Example 11.1. Configuring Detached State
JPA XML format:
<property name="kodo.DetachState" value="fgs(DetachedStateField=true)"/>
JDO properties format:
kodo.DetachState: fgs(DetachStateFielded=true)
You can also alter the set of fields that will be included in the
detached graph at runtime.
KodoEntityManager
s expose the
following APIs for controlling detached state:
public static final int DETACH_LOADED; public static final int DETACH_FGS; public static final int DETACH_ALL; public int getDetachState (); public void setDetachState (int mode);
The JDO
FetchPlan
expose the
following APIs for controlling detached state:
public static final int DETACH_LOAD_FIELDS; public static final int DETACH_UNLOAD_FIELDS; public int getDetachmentOptions (); public void setDetachmentOptions (int options);
The JDO Overview covers these APIs in
Chapter 12, FetchPlan. In addition, the
The
KodoFetchPlan
extension adds
another option flag for detaching all fields:
public static final int DETACH_ALL_FIELDS;
When the detached state field is enabled, the Kodo enhancer
adds an additional field to the enhanced version of your class.
This field of type Object
. Kodo uses
this field for bookkeeping information, such as the versioning
data needed to detect optimistic concurrency violations when the
object is re-attached.
It is possible to define this detached state field yourself. Declaring this field in your class metadata prevents the enhancer from adding any extra fields to the class, and keeps the enhanced class serialization-compatible with the unenhanced version. The detached state field must not be persistent. See Section 6.4.1.3, “Detached State” for details on how to declare a detached state field.
JPA:
import kodo.persistence.*; @Entity public class Magazine implements Serializable { private String name; @DetachedState private Object state; ... }
JDO:
public class Magazine implements Serializable { private String name; private Object detachedState; ... } <?xml version="1.0"?> <jdo> <package name="org.mag"> <class name="Magazine" detachable="true"> <extension vendor-name="kodo" key="detached-state-field" value="detachedState"/> </class> </package> </jdo>
The JPA Overview describes JPA's automatic detach behavior in Section 7.3, “Persistence Context”. We describe Kodo's options for automatic detach in JDO below.
Detachable JDO objects automatically detach when they are
serialized. Kodo expands this automatic detach behavior with
optional automatic detachment on various events:
close, commit, and non-transactional read. On each configured
event, all managed objects in the PersistenceManager
cache become detached. Non-detachable objects become
transient.
close
: Detach all objects when the
PersistenceManager
closes.
commit
: Detach all objects when a
transaction ends.
nontx-read
: Reads outside
of a transaction will automatically detach instances before
returning them.
By using the proper set of these options, you can avoid unnecessary
detach
calls in your code. Some common use
cases for this functionality are:
Client/Server applications with
short-lived
PersistenceManager
s.
Clients request objects from the server, who returns
detached instances which can be modified and manipulated
without a local PersistenceManager
. Changes can then be re-attached later
through the server.
Servlets and JSPs.
A very common pattern in servlet and JSP architectures
is to allocate a PersistenceManager
at the beginning of a web request, then
close it at the end of the request. You can store
detached instances between requests in the HTTP
session, to maintain changes to an object over
several pages for example.
Session Beans. These beans can return a portion of the object graph which remain valid no matter what tier the bean is being called from.
No automatic detachment is performed in JDO by default. You can
turn on automatic detachment at runtime through the
KodoPersistenceManager.setDetachAllOn*
methods. You can also set detach detachment triggers
with the
kodo.AutoDetach
configuration property:
kodo.AutoDetach: close, commit, nontx-read
![]() ![]() |