Java Object Persistence with OpenBase & Cayenne


Reading/Writing Java Objects From/To OpenBase
• Object Relational Mapping (ORM)
• Cayenne Architecture
• Cayenne In Practice
• Code Examples

What You'll Learn

• Where Cayenne originated
• The Cayenne Architecture
• How to get started with your own applications
• Similarities between Cayenne & WebObjects
• How to use Cayenne from Cocoa Java

Java —> Cayenne (ORM) —> OpenBase
• Saving Java Objects beyond the VM lifecycle

What is Cayenne?

Open Source Project

• Java community-driven
• Started in 2001
• Andrei Adamchik & Michael Shengaout
• ObjectStyle Group

Object Relational Mapping (ORM) Tool

• Maps Java attributes to database columns
• Tracks changes to Java attributes at runtime
• Commits appropriate inserts, updates, and deletes to the

XML Runtime Library

• Cayenne Engine Configuration
• Object to Relational Mappings
• Editable with a simple text editor

<?xml version="1.0" encoding="utf-8"?>
<domains project-version="1.1">
<domain name="CompanyDomain">
<map name="Movies" location=""/>
<node name="MoviesDataNode"
<map-ref name="Movies"/>

Integrated Suite of GUI Tools

• Object Relational Mapping Modeler
• DataView Modeler

Cayenne Architecture

Object Relational Mapping

• Java Class to Database Schema Mappings
– “simple” class property —> database column
– “complex” class property —> related table via a database
• Java Object to Database Row Mappings
– “simple” object property value —> value of a column in a row
– “complex” object property value —> one or more other objects
• 2 Layer Mapping
– Java Layer
– Database Layer

Cayenne Mapping Layers

Loose coupling of database metadata and java class

The Object Graph

• All operations on the object graph are controllable by the
• Initial set of objects is created by running SelectQuery or
creating new DataObjects
• Most objects related to the initial objects can be obtained via
simple method calls on initial objects
• Discarding all changes since the last commit can be done
with a simple method call

Data Objects

All Objects that represent persistent data in Cayenne must
implement the DataObject interface
• The CayenneDataObject class is the default implementation
provided for you

Access Classes

• Connects to the database
• Converts Query objects into SQL statements
• Converts JDBC ResultSets into object snapshots
• Generates primary keys
• Combines physical datasources (DataNodes) into a single
logical datasource.
• Allows creation of DataSource groups
• Serves as a factory for both lower level DataNodes as well
as higher level DataContexts
• Highest layer controller class
• Directly accessed by users in most cases
• Isolates in-memory data object changes
• Commits all changes with one line of code
• Caches DataObjects

Access Classes Diagram

DataContext is the Primary Manipulator

Cayenne DataSource

• Accesses persistent data store via JDBC
• Database connections are obtained via Java’s
• Connections are pooled via Cayenne’s PoolManager
• Configuration is done as part of your Cayenne mappings
and is not normally accessed in user code

Primary Key Generation

Meaningful Primary Keys
• Social Security Numbers
• Usernames
Primary Keys Derived From Relationships
• Derived from foreign keys
• Are often compound primary keys
• Used for many-to-many relationships
Generated Primary Keys
• Conceptual in nature
• Users OpenBase’s NEWID function

Information Storage

• Stored by instances of ObjectStore
• Associated with a particular DataContext
• Snapshots of database table rows
• Stored by instances of DataRowStore
• Primarily used internally by Cayenne for:
– Optimistic Locking
– Caching
– Creation of DataObjects


Class Participants
• DataObject
• DataRow
• ObjectStore
• DataRowStore
Levels of Caching
• Level 1 - No Cache Sharing
• Level 2 - Local VM Cache Sharing
• Level 3 - Cross VM Cache Sharing


Transaction Options
• Cayenne Implementation
• Container Managed
• Application Level via DataContext
• Database Level via DataNode
User Control
• Explicit Transactions
• Explicit Transactions Made Simple
• Transaction Delegate

Event Notification

• Can be used in any application, persistent or not
• EventManager handles dispatching details
• Listeners do not have to implement a specific interface
• No explicit unregistering of listeners
• Supports local and remote dispatches
• Supports both synchronous and asynchronous dispatching
• Listeners can register as blocking or non-blocking

Getting Started

Writing a Cayenne Application

• Create a Cayenne Project and Data Model - A set of xml
configuration files generally created with Cayenne Modeler
• Generate Java Classes - Translate Entities to Java class
files using Cayenne Modeler or the Cgen Ant task
• Write an Actual Application - Write an application that takes
advantage of Cayenne. The DataContext is normally your
access point to Cayenne
• Configure Deployment Environment - Possible deployment
scenarios include a standalone application, a web
application, or and EJB application

Create Project


Generating Java Classes

Using Cayenne Modeler
• From the Tools menu, select ‘Generate Classes’
• Generate classes all at once, or one at a time

Generating Java Classes

Using the Cgen Ant Task
• Generates and maintains DataObject source files
• Superclass/subclass pairs are generated by default
• Example Ant configuration:

<taskdef name="cgen"
<classpath refid="classpath"/>
<cgen map="src/datamap.xml" destDir="src/java/dobj"

Generating Java Classes

Available Cgen Attributes

Write an Application

A Simple Java Tool

import org.objectstyle.cayenne.query.SelectQuery;
import org.objectstyle.cayenne.access.DataContext;
import java.util.List;
DataContext ctxt = DataContext.createDataContext();
SelectQuery query = new SelectQuery(Movie.class);
// The query would fetch *ALL* rows from the MOVIE
// table. The list returned contains Movie objects,
// one object per row
List movies = ctxt.performQuery(query);
Movie current = null;
Iterator i = movies.iterator();
current = (Movie);

Application Deployment

Finding the configuration
• DefaultConfiguration - searches classpaths

import org.objectstyle.cayenne.conf.Configuration;
Configuration conf = Configuration.getSharedConfiguration();

• FileConfiguration - you specify a specific file
import org.objectstyle.cayenne.conf.FileConfiguration;
String fileName = "/some/path/to/my-cayenne.xml";
File file = new File(fileName);
FileConfiguration conf = new FileConfiguration(file);

Application Deployment

Subclassing Configuration

import my.package.conf.MyPackageConfiguration;
MyPackageConfiguration myConf = new MyPackageConfiguration();

Application Deployment

Configuring Logging with Log4J

# General Log4J stuff
log4j.rootLogger=WARN, A1
log4j.appender.A1.layout.ConversionPattern=cayenne %-5p [%t
%d{MM-dd HH:mm:ss}] %c{1}: %m%n
# indiv. packages configuration - turning on the packages that
we care about = INFO
# This is the logger that controls SQL output
# Setting the level to INFO or DEBUG will turn the logs on = INFO
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License