Java Object Persistence with OpenBase & Cayenne
Introduction
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
database

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="Movies.map.xml"/>
<node name="MoviesDataNode"
datasource="MoviesDataNode.driver.xml"
adapter="org.objectstyle.cayenne.dba.openbase.OpenBaseAdapter"
factory="org.objectstyle.cayenne.conf.DriverDataSourceFactory">
<map-ref name="Movies"/>
</node>
</domain>
</domains>
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
relationship
• 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
application
• 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
DataNode
• Connects to the database
• Converts Query objects into SQL statements
• Converts JDBC ResultSets into object snapshots
• Generates primary keys
DataDomain
• 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
DataContext
• 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
javax.sql.DataSource
• 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
DataObject
• Stored by instances of ObjectStore
• Associated with a particular DataContext
DataRow
• Snapshots of database table rows
• Stored by instances of DataRowStore
• Primarily used internally by Cayenne for:
– Optimistic Locking
– Caching
– Creation of DataObjects
Caching
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
Transactions
Transaction Options
• Cayenne Implementation
• Container Managed
Behavior
• 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"
classname="org.objectstyle.cayenne.tools.CayenneGenerator">
<classpath refid="classpath"/>
</taskdef>
<cgen map="src/datamap.xml" destDir="src/java/dobj"
usepkgpath="false"/>
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();
while(e.hasNext()){
current = (Movie)e.next();
System.out.println(current.getName());
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);
Configuration.initializeSharedConfiguration(conf);
Application Deployment
Subclassing Configuration
import my.package.conf.MyPackageConfiguration;
...
MyPackageConfiguration myConf = new MyPackageConfiguration();
Configuration.initializeSharedConfiguration(myConf);
Application Deployment
Configuring Logging with Log4J
# General Log4J stuff
log4j.rootLogger=WARN, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
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
#log4j.logger.org.objectstyle.cayenne = INFO
# This is the logger that controls SQL output
# Setting the level to INFO or DEBUG will turn the logs on
log4j.logger.org.objectstyle.cayenne.access.QueryLogger = INFO





