You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2003/12/02 02:52:33 UTC
cvs commit: db-ojb/contrib readme.txt
arminw 2003/12/01 17:52:33
Modified: xdocs sequencemanager.xml objectcache.xml jdbc-types.xml
howto-work-with-clustering.xml
Added: contrib/src ObjectCacheOSCacheImpl.java
contrib readme.txt
Log:
- add Jason McKerr's clustering-howto update
- update documentation
- add readme file to contib directory
Revision Changes Path
1.16 +91 -21 db-ojb/xdocs/sequencemanager.xml
Index: sequencemanager.xml
===================================================================
RCS file: /home/cvs/db-ojb/xdocs/sequencemanager.xml,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- sequencemanager.xml 5 Sep 2003 22:06:59 -0000 1.15
+++ sequencemanager.xml 2 Dec 2003 01:52:32 -0000 1.16
@@ -24,6 +24,7 @@
<li><a href="#Oracle-style sequencing">Oracle-style sequencing using stored procedure</a></li>
<li><a href="#Microsoft SQL Server 'uniqueidentifier' type (GUID) sequencing">
Microsoft SQL Server 'uniqueidentifier' type (GUID) sequencing</a></li>
+ <li><a href="#nativeSequenceManager">Identity based sequence manager</a></li>
</ul>
</li>
<li><a href="#How to write my own sequence manager?">How to write my own sequence manager?</a></li>
@@ -164,7 +165,7 @@
<subsection name="SequenceManager implementations">
<p>
-Source code of all <code>SequenceManager</code> implementations could be
+Source code of all <code>SequenceManager</code> implementations can be
found in <code>org.apache.ojb.broker.util.sequence</code> package.
<br/>
If you still think something is missing you can just write your <a href="#howToWrite">own</a>
@@ -188,7 +189,7 @@
If you ask for an uid using an interface with several
implementor classes, or a baseclass with several subclasses the returned
uid have to be unique accross all tables representing objects of the
-extent in question.
+extent in question (more see <a href="#extentAware">here</a>).
<br/>
It's also possible to use this implementation in a <i>global mode</i>, generate
global unique id's.
@@ -237,8 +238,9 @@
<br/>- do not use in managed environments when connections were enlisted
in running transactions, e.g. when using DataSources of an application server
<br/>- if set connection-pool attribute 'whenExhaustedAction' to 'block' (wait for
-connection), under heavy load the this SM could block application.
-<br/>- superfluously to mention, do not use if other applications insert objects
+connection if connection-pool is exhausted), under heavy load this sequence manager
+implementation can block application.
+<br/>- superfluously to mention, do not use if other non-OJB applications insert objects too
</p>
<br/>
@@ -271,8 +273,8 @@
This is the fastest standard sequence manager implementation, but
has some Limitations:
<br/>- do not use in clustered environments
-<br/>- do not use if other entities use database based sequencing
-or database will be updated by other applications
+<br/>- superfluously to mention, do not use (or handle with care) if other non-OJB
+ applications insert objects too
</p>
@@ -363,7 +365,8 @@
</p>
<p>
Limitations:
-<br/>- do not use if other entities use database based sequencing
+<br/>- superfluously to mention, do not use (or handle with care) if other non-OJB
+ applications insert objects too
</p>
@@ -440,8 +443,6 @@
<p>
Limitations:
<br/>- currently none known
-<br/>(- do not use if database will be updated by other
-applications)
</p>
@@ -503,6 +504,60 @@
guarantee) that there will be no collisions between the Guids generated.
</p>
+
+<br/>
+<p>
+<a name="nativeSequenceManager"/>
+<b>Identity based sequence manager</b><br/>
+This sequence manager implementation supports database Identity columns
+(supported by MySQL, MsSQL, HSQL, ...). When using identity columns we have to do
+a trick to make the sequence manager work.
+<br/>
+OJB identify each persistence capable object by a unique
+ojb-Identity object. These ojb-Identity
+objects were created using the sequence manager instance to
+get UID's. Often these ojb-Identity objects were created before
+the persistence capable object was written to database.
+<br/>
+When using Identity columns it is not possible to retrieve the next
+valid UID before the object was written to database. As recently as
+the real object was written to database, you can ask the DB for the last
+generated UID. Thus in SequenceManagerNativeImpl we have to do a trick and use
+a 'temporary' UID till the object was written to database.
+<br/>
+So, if it's possible try to avoid using Identity columns in your
+database model. If not use this sequence manager implementation to
+as a workaround for the Identity problem.
+</p>
+
+To enable this sequence manager implementation set in your
+<code>jdbc-connection-descriptor</code>:
+<source><![CDATA[
+<sequence-manager className="org.apache.ojb.broker.util.
+ sequence.SequenceManagerNativeImpl">
+</sequence-manager>
+]]></source>
+
+To declare the identity column in the repository.xml file add <code>primarykey="true"</code>,
+<code>autoincrement="true"</code> and <code>access="readonly"</code> to the field-descriptor
+for your table's primary key identity column.
+<source><![CDATA[
+<field-descriptor
+ name="identifier"
+ column="NATIVE_ID"
+ jdbc-type="BIGINT"
+ primarykey="true"
+ autoincrement="true"
+ access="readonly"/>
+]]></source>
+
+<p>
+Limitations:
+<br/>- The Identity columns have to <b>start with value >= 1</b> and should
+never be negative.
+<br/>- Use of Identity columns is <b>not extent aware</b> (This may change in further versions).
+More info <a href="#extentAware">here</a>.
+</p>
</subsection>
@@ -544,7 +599,7 @@
</p>
<p>
-Of course I'm interested in your solutions! If you have
+Of course we interested in your solutions! If you have
implemented something interesting, just contact us.
</p>
@@ -559,7 +614,8 @@
Most <code>SequenceManager</code> implementations based on sequence names.
If you want retain control of sequencing use your own <code>sequence-name</code> attribute
in the <code>field-descriptor</code>. In that case you are reponsible to use the same name
-across extents (extent <a href="tutorial3.html#extents and polymorphism">see more info</a>).
+across extents (see more info about <a href="tutorial3.html">extents
+and polymorphism</a>).
Per default the sequence manager build its own <i>extent aware</i> sequence name with an
simple algorithm
(see <code>org.apache.ojb.broker.util.sequence.SequenceManagerHelper#buildSequenceName</code>)
@@ -575,22 +631,36 @@
<p>
<a name="extentAware"/>
<br/><b>What to hell does <i>extent aware</i> mean?</b><br/>
-Say we have a abstract base class <code>animals</code> and two classes <code>dogs</code> and <code>cats</code>
-(with e.g. two different tables in database) which extend <code>animals</code>.
+Say we have a abstract base class <code>Animal</code> and two classes <code>Dog</code> and <code>Cat</code>
+which extend <code>Animal</code>. For each non-abstract class we create a separate
+database table.
+<br/>
We will be able to do a query like <i>give me all animals</i>. Thus
-the uid's of <code>dogs</code> and <code>cats</code> must be unique across the
-tables of both classes or else you never get a vaild query result.
+the uid's of <code>Dog</code> and <code>Cat</code> objects must be unique across the
+tables of both classes or else you may not get a vaild query result.
+<br/>
+The reason for this behaviour is the <code>org.apache.ojb.broker.Identity</code>
+class implementation (this may change in further versions).
</p>
<p>
<a name="noAutoBuild"/>
<br/><b>How could I prevent auto-build of the sequence-name?</b><br/>
-Most of the shipped <code>SequenceManager</code> implementations support by default
-auto-build (autoNaming) of the sequence names if none was found in the <code>field-descriptor</code>.
-To prevent this all relevant implementations (see docs here and javadocs)
-support a <code>autoNaming</code> attribute. If set <code>false</code> OJB doesn't
+All shipped <code>SequenceManager</code> implementations which using sequence names
+for UID generation, support by default auto-build (autoNaming) of the sequence name
+if none was found in the <code>field-descriptor</code>.
+<br/>
+To prevent this, all relevant SM implementations support a <code>autoNaming</code>
+property - set via <code>attribute</code> element. If set <code>false</code> OJB doesn't
try to build sequence names automatic.
+<source><![CDATA[
+<sequence-manager className="XYZ">
+...
+ <attribute attribute-name="autoNaming" attribute-value="true"/>
+...
+</sequence-manager>
+]]></source>
</p>
@@ -628,8 +698,8 @@
UID in your object model.
<br/>
[NOTE: Don't use SequenceManagerFactory#getSequenceManager(PersistenceBroker broker), this
-returns a new sequence manager instance for the given broker instance, not the current
-used of the given broker instance]
+method returns a new sequence manager instance for the given broker instance and not the current
+used SM instance of the given PersistenceBroker instance]
</p>
1.7 +211 -102 db-ojb/xdocs/objectcache.xml
Index: objectcache.xml
===================================================================
RCS file: /home/cvs/db-ojb/xdocs/objectcache.xml,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- objectcache.xml 3 Sep 2003 18:51:35 -0000 1.6
+++ objectcache.xml 2 Dec 2003 01:52:32 -0000 1.7
@@ -13,13 +13,11 @@
<section name="Object cache">
<ul>
- <li><a href="#Why a cache?">Why a cache?</a></li>
- <li><a href="#How it works">How it works</a></li>
+ <li><a href="#Why a cache and how it works?">Why a cache and how it works?</a></li>
<li><a href="#How to change the used ObjectCache implementation">How to change the used ObjectCache implementation</a></li>
- <li><a href="#Alternative cache implementations">Alternative cache implementations</a></li>
+ <li><a href="#Shipped cache implementations">Shipped cache implementations</a></li>
+ <li><a href="#Distributed ObjectCache?">Distributed ObjectCache?</a></li>
<li><a href="#Implement your own cache">Implement your own cache</a></li>
- <li><a href="#Distributed ObjectCache implementations">Distributed ObjectCache implementations</a></li>
- <li><a href="#"></a></li>
<li><a href="#CacheFilter feature">CacheFilter feature</a>
<ul>
<li><a href="#What does cache filtering mean">What does cache filtering mean</a></li>
@@ -27,10 +25,28 @@
<li><a href="#Implement your own filter">Implement your own filter</a></li>
</ul>
</li>
+ <li><a href="#Future prospects">Future prospects</a></li>
</ul>
+
<p>
-All classes belonging to the <code>Object Cache</code> part of OJB you will find under the
-<code>org.apache.ojb.broker.cache</code>-package.
+ OJB was shipped with several <code>ObjectCache</code> implementations. All
+ implementations can be found in <code>org.apache.ojb.broker.cache</code> package.
+ To classify the different implementations we differ
+ <i>local cache</i> and
+ <i>shared/global cache</i> (we use both terms synonymous) implementations.
+ <br/>
+ <ul>
+ <li>
+ Local cache implementation mean that each instance use its own object map to
+ manage cached objects.
+ </li>
+ <li>
+ Shared/global cache implementations share one
+ (in most cases static) map to manage cached objects.
+ </li>
+ </ul>
+ A distributed object cache implementation supports caching of objects
+ across different JVM.
</p>
@@ -39,101 +55,81 @@
</P>
-<subsection name="Why a cache?">
-<p>
-OJB provides a pluggable Object Cache that
-holds Objects previously loaded or stored by the PersistenceBroker.
-Using a Cache has several advantages:
-<ul>
- <li>it increases performance as it reduces database
- lookups. If an object is looked up by the
- PersistenceBroker, it does not perform a <code>SELECT</code> against the database
- immediately but first looks up the
- cache if the requested object is already loaded. If the object is
- cached it is returned as the lookup result. If it is not cached a
- <code>SELECT</code> is performed.
- </li>
- <li>it maintains the uniqueness of objects. If several queries
- ask for an object with the same Identity (OID) they will receive one
- and the same object from the cache. This will prevent your
- applications from working with divergent copies of objects with the
- same Identity.
- </li>
- <li>it allows to perform circular lookups (as by crossreferenced
- objects) that would result in non-terminating loops without such a
- cache.
- </li>
-</ul>
-</p>
-</subsection>
-
-
-
-<subsection name="How it works">
+<subsection name="Why a cache and how it works?">
<p>
-The OJB Cache provides the following interface to allow caching,
-lookup and removal of objects:
-<source>
+ OJB provides a pluggable object cache provided by the <code>ObjectCache</code>
+ interface.
+ <source>
public interface ObjectCache
{
/**
- * makes object obj persistent to the Objectcache
- * under the key oid.
+ * Write to cache.
*/
public void cache(Identity oid, Object obj);
-
/**
- * Lookup object with Identity oid in objectTable.
- * returns null if no matching id is found
+ * Lookup object from cache.
*/
public Object lookup(Identity oid);
-
/**
- * removes an Object from the cache.
- * @param obj the Object (or the Identity of the object)
- * to be removed.
+ * Removes an Object from the cache.
*/
public void remove(Identity oid);
/**
- * clear the ObjectCache.
+ * Clear the ObjectCache.
*/
public void clear();
}
</source>
-The OJB default <code>ObjectCache</code> implementation resides in the class
-<code>ojb.broker.accesslayer.ObjectCacheDefaultImpl</code>. This implementation
-uses a static hashtable to hold all cached objects:
-<source>
-...
-public void cache(Identity oid, Object obj)
-{
- if ((obj != null))
- {
- SoftReference ref = new SoftReference(obj);
- objectTable.put(oid.toString(), ref);
- }
-}
-...
-</source>
-As you will have noticed, OJB uses SoftReferences. A SoftReference is
-not treated as a ordinary java reference. That is: if an object is
-not longer referenced by your application but only by the cache it
-can be reclaimed by the garbage collector (gc). The OJB cache does
-not provide its own memory management but lets the JVM gc do the job.
+ Each PersistenceBroker instance using its own <code>ObjectCache</code>
+ instance. The <code>ObjectCache</code> instances are created by the
+ <code>ObjectCacheFactory</code> class.
+ </p>
+ <p>
+ Each cache implementation holds Objects previously loaded or stored
+ by the PersistenceBroker - dependend on the implementation.
+ <br/>
+ Using a Cache has several advantages:
+<ul>
+ <li>
+ It increases performance as it reduces database
+ lookups or/and object materialization. If an object is looked up
+ by Identity the associated PersistenceBroker instance, does not perform
+ a <code>SELECT</code> against the database immediately but first looks
+ up the cache if the requested object is already loaded. If the object is
+ cached it is returned as the lookup result. If it is not cached a
+ <code>SELECT</code> is performed.
+ <br/>
+ Other queries were performed against the database, but before an object
+ from the ResultSet was materialized the object identity was looked up
+ in cache. If not found the whole object was materialized.
+ </li>
+ <li>
+ It allows to perform circular lookups (as by crossreferenced
+ objects) that would result in non-terminating loops without such a
+ cache.
+ </li>
+</ul>
+
+
</p>
</subsection>
+
+
<subsection name="How to change the used ObjectCache implementation">
<p>
-To change the used <code>ObjectCache</code> implementation you only
-need to set the property <code>ObjectCacheClass</code> in <a href="OJB.properties.txt">
-OJB.properties</a> file:
-<source>
-
+The <code>object-cache</code> element/property can be used to specify the ObjectCache
+implementation used by OJB. There are three levels of
+declaration:
+<ul>
+ <li>
+ in <a href="OJB.properties.txt">OJB.properties</a> file, to declare the standard
+ (default) ObjectCache implementation.
+ <source>
#-------------------------------------------------------------------
# Object cache
#-------------------------------------------------------------------
@@ -141,26 +137,65 @@
# implementation is to be used.
ObjectCacheClass=org.apache.ojb.broker.cache.ObjectCacheDefaultImpl
#
-</source>
-</p>
-</subsection>
+ </source>
+ <br/>
+ </li>
+ <li>on jdbc-connection-descriptor level, to declare ObjectCache implementation
+ on a per connection/user level, e.g.
+ <source><![CDATA[
+<jdbc-connection-descriptor ...>
+...
+ <object-cache class="org.apache.ojb.broker.cache.ObjectCachePerBrokerImpl">
+ </object-cache>
+...
+</jdbc-connection-descriptor>
+ ]]></source>
+ <br/>
+ </li>
-<subsection name="Alternative cache implementations">
+ <li>on class-descriptor level, to declare ObjectCache implementation
+ on a per class level, e.g.
+ <source><![CDATA[
+<class-descriptor
+ class="org.apache.ojb.broker.util.sequence.HighLowSequence"
+ table="OJB_HL_SEQ"
+ >
+ <object-cache class="org.apache.ojb.broker.cache.ObjectCacheEmptyImpl">
+ </object-cache>
+...
+</class-descriptor>
+ ]]></source>
+ <br/>
+ </li>
+</ul>
+
+The priority of the declared object-cache elements are:
<p>
-OJB was shipped with several <code>ObjectCache</code> implementations. All
-implementations can be found in <code>org.apache.ojb.broker.cache</code> package.
+<i>per class > per jdbc descriptor > standard</i>
</p>
+E.g. if you declare ObjectCache 'DefaultCache' as standard and set
+ObjectCache 'CacheA' in class-descriptor for class A and class B
+does not declare an object-cache element. Then OJB use 'CacheA'
+as ObjectCache for class A and 'DefaultCache' for class B.
+</p>
+</subsection>
+
+
+
+<subsection name="Shipped cache implementations">
+
<p>
<b>ObjectCacheDefaultImpl</b><br/>
-Per default OJB use a global reference based <code>ObjectCache</code>
-implementation. It's a fast and simple cache but has some drawbacks.
+Per default OJB use a shared reference based <code>ObjectCache</code>
+implementation. It's a really fast cache but there are a few drawbacks.
There is no transaction isolation, when thread one modify an object,
thread two will see the modification when lookup the same object.
-If you rollback/abort a transaction the corrupted objects will not
-be removed from the cache. You have to do this using
+If you rollback/abort a transaction the corrupted objects will <b>not</b>
+be removed from the cache (when using PB-api, top-level api may support
+automatic cache synchronization). You have to do this using
<source>
broker.removeFromCache(obj);
@@ -171,22 +206,70 @@
</source>
by your own.
</p>
+<p>
+ This implementation use <code>SoftReference</code> to wrap
+ all cached objects. If the cached object was not longer referenced by your application
+ but only by the cache, it can be reclaimed by the garbage collector.
+ <br/>
+ As we don't know when the garbage collector reclaims the freed objects, it is
+ possible to set a <code>timeout</code> property. So an cached object was
+ only returned from cache if it was not garbage collected and was not timed out.
+</p>
+To enable this <code>ObjectCache</code> implementation
+<source><![CDATA[
+<object-cache class="org.apache.ojb.broker.cache.ObjectCacheDefaultImpl">
+ <attribute attribute-name="timeout" attribute-value="600"/>
+</object-cache>
+]]></source>
+<p>
+Implementation configuration properties:
+<table>
+<tr>
+ <td><b>Property Key</b></td>
+ <td><b>Property Values</b></td>
+</tr>
+<tr>
+ <td>timeout</td>
+ <td>
+ Lifetime of the cached objects in seconds.
+ If expired, the cached object was discarded - default was 900 sec.
+ </td>
+</tr>
+</table>
+</p>
<p>
+ Recommendation:
+ <br/>If you take care of cache synchronization and be aware of dirty
+ reads, this implementation is useful for read-only or less insert/update
+ centric classes.
+</p>
+
+<br/><p>
<b>ObjectCachePerBrokerImpl</b><br/>
-This local cache implementation allows to have dedicated caches per broker.
-All calls are delegated to the cache associated with the currentBroker.
-When the broker was closed (returned to pool) the cache was cleared.
+This local cache implementation allows to have dedicated caches per PersistenceBroker instance.
+All calls are delegated to the cache associated with the current broker instance.
+When the broker
+<ul>
+ <li>does commit a transaction</li>
+ <li>does abort/rollback a transaction</li>
+ <li>was closed (returned to pool)</li>
+</ul>
+the cache was cleared. So no dirty reads will occur, because each thread use it's own PersistenceBroker
+instance. No corrupted objects will be found in cache, because the cache was cleared after use.
</p>
-<p>
+
+
+<br/><p>
<b>ObjectCacheJCSImpl</b><br/>
-A global <code>ObjectCache</code> implementation using JCS region for
+A shared <code>ObjectCache</code> implementation using a JCS region for
each classname. More info see <a href="http://jakarta.apache.org/turbine/jcs/index.html">
turbine-JCS</a>.
</p>
-<p>
+
+<br/><p>
<b>ObjectCacheEmptyImpl</b><br/>
This is an 'empty' ObjectCache implementation.
Useful when caching was not desired.
@@ -194,6 +277,32 @@
use a temporary map while store and delete operation
(this may change in further versions).
</p>
+
+
+<br/><p>
+<b>ObjectCacheOSCacheImpl</b><br/>
+
+<br/>
+A implementation using OpenSymphony's OSCache. More
+info see <a href="howto-work-with-clustering.html">here</a>.
+</p>
+
+
+<br/><p>
+In <code>cache</code> package you can find some more implementations.
+</p>
+<br/>
+
+</subsection>
+
+
+
+<subsection name="Distributed ObjectCache?">
+<p>
+ If OJB was used in a clustered enviroment it is mandatory to
+ distribute all shared cached objects across different JVM. More information how to
+ realize such a cache <a href="howto-work-with-clustering.html">see here</a>.
+</p>
</subsection>
@@ -211,21 +320,13 @@
property. <a href="#change">See more</a>.
</p>
-<p>Of course I'm interested in your solutions! If you have
-implemented something interesting, just contact me.</p>
+<p>Of course we interested in your solutions! If you have
+implemented something interesting, just contact us.</p>
</subsection>
- <subsection name="Distributed ObjectCache implementations">
- <p>
-
- </p>
- </subsection>
-
-
-
<subsection name="CacheFilter feature">
<a name="What does cache filtering mean"/><b>What does cache filtering mean</b><br/>
@@ -239,6 +340,14 @@
</p>
<a name="Implement your own filter"/><b>Implement your own filter</b><br/>
+<p>
+TODO
+</p>
+
+</subsection>
+
+
+<subsection name="Future prospects">
<p>
TODO
</p>
1.9 +10 -2 db-ojb/xdocs/jdbc-types.xml
Index: jdbc-types.xml
===================================================================
RCS file: /home/cvs/db-ojb/xdocs/jdbc-types.xml,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- jdbc-types.xml 8 Aug 2003 14:57:40 -0000 1.8
+++ jdbc-types.xml 2 Dec 2003 01:52:32 -0000 1.9
@@ -12,7 +12,7 @@
<section name="mapping of JDBC types to Java types">
<p>
OJB implements the mapping conventions for JDBC and Java types as specified by
- the JDBC 2.0 specification. <br/>
+ the JDBC 3.0 specification. <br/>
See the table below for details.
</p>
@@ -46,6 +46,10 @@
<td>boolean</td>
</tr>
<tr>
+ <td>BOOLEAN</td>
+ <td>boolean</td>
+ </tr>
+ <tr>
<td>TINYINT</td>
<td>byte</td>
</tr>
@@ -120,6 +124,10 @@
<tr>
<td>REF</td>
<td>Ref</td>
+ </tr>
+ <tr>
+ <td>DATALINK</td>
+ <td>java.net.URL</td>
</tr>
<tr>
<td>JAVA_OBJECT</td>
1.3 +176 -104 db-ojb/xdocs/howto-work-with-clustering.xml
Index: howto-work-with-clustering.xml
===================================================================
RCS file: /home/cvs/db-ojb/xdocs/howto-work-with-clustering.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- howto-work-with-clustering.xml 20 Jun 2003 07:29:59 -0000 1.2
+++ howto-work-with-clustering.xml 2 Dec 2003 01:52:32 -0000 1.3
@@ -2,128 +2,182 @@
<document>
<properties>
- <author email="mckerrj@nacse.org">Jason McKerr</author>
- <title>Using Tangosol Coherence Clustered Cache with OJB</title>
+ <author email="jason@osuosl.org">Jason McKerr</author>
+ <title>OJB - Using Open Symphony's OScache for clustering/distributing the Cache in OJB</title>
</properties>
<body>
<section name="How to use OJB in clustered environments">
-Editorial note: This howto is derived from an entry in Jason McKerr's
-<a href="http://www.freeroller.net/page/jmckerr">BLOG</a>.
- <subsection name="three steps to cluster OJB">
- A number of people, myself included, were wondering how to do distributed
- caching in Object Relational Bridge (OJB).
- For those of you that haven't used it, OJB is an Object Relational Mapping
- framework for database persistence; allowing you to seemlessly persist your
- plain old java objects to any database. I've been working with it for sometime,
- and it's really robust now. You can find it at Jakarta OJB. <br/>
-
- Tangosol Coherence is a high-performance, and very nice caching product.
- I've only just begun using it, but already it seems excellent.
- You can download a 30-day evaluation license. <br/>
-
- I'm regurgitating some stuff that Thomas Mahler put on the mailing list,
- and then adding more that is specific to using Tangosol coherence.
- <a href="http://www.mail-archive.com/ojb-user@db.apache.org/msg01228.html">That mail is here</a>.<br/>
-
- Back to the Topic: There are a few things that you should do in order
+ <br/>Object/Relational Bridge will work fine in environments that require robustness features such as load-balancing,
+ failover, and clustering. However, there are some important steps that you need to take in order for your data to be secure,
+ and to prevent isolation failures. These steps are outlined below.<br/><br/>
+ I have tested this in a number of environments, and with Servlet engines and J2EE environments. If you run into problems,
+ please post questions to the OJB users mail list.<br/><br/>
+ This outline for clustering is based on an email from the OJB Users Mail List:
+ <a href="http://www.mail-archive.com/ojb-user@db.apache.org/msg01228.html">This is that mail.</a>
+ <br/><br/>
+
+ <subsection name="Four steps to clustering your OJB application">
+ A lot of people keep asking for robust ways to run their OJB engines
+ in multi-VM or clustered environments. This email covers how to do that
+ safely and securely using Open Symphony's OSCache caching product.<br/><br/>
+
+ OSCache is a high-performance, robust caching product that supports clustering.
+ I've been using it for a while in production and it is excellent. <br/><br/>
+
+ Back to the Topic: There are four main things that you should do in order
to make your OJB application ready for using a cache in a multi-VM or distributed environment.<br/><br/>
-
- <b>First:</b> You need to trash the default sequence manager
- that you define in your repository.xml file.
- That sequence manager grabs sequences in blocks from an OJB defined table
- that keeps track of the information. However, in a clustered/distributed
- environment you'll get conflicts using that.
- The default is "SequenceManagerHighLowImpl."
- With this, you'll then need to add the "sequence-name" to your primary key definition.
- Here's a sample primary key column:
-
+
+ <b>First: Take care of the sequence manager</b>
+ that you define in your repository.xml file. The default sequence manager
+ (<code>SequenceManagerHighLowImpl</code>) grabs sequences in blocks
+ from an OJB defined table that keeps track of the information.
+ However, in a clustered/distributed environment you'll get conflicts using that.
+ <code>SequenceManagerHighLowImpl</code> (>= 1.0rc5) use optimistic locking to be suiteable in clustered
+ environments - see detailed information in api-doc of the used implementation.
+ <br/><br/>If your database supports database based sequence key generation (like PostgreSQL, Oracle, ...)
+ it's recommended to use <code>SequenceManagerNextValImpl</code> (supports database based sequence keys).
+ Using this sequence manager will prevent conflicts in multi-vm or clustered environments.
+ More about <a href="sequencemanager.html">sequence manager here</a>.<br/><br/>
+
+ <b>Second: If you are using <code>SequenceManagerNextValImpl</code> </b>you have two possibilities:
+ <ul>
+ <li>Let OJB define the sequence name (it's also possible to define a <code>sequence-name</code>
+ in the field-descriptor) and auto-creating the sequence
+ </li>
+ <li>Do it by your own:
+ <ul>
+ <li>Create a sequence object in your database.
+ <ul>
+ <li>An Oracle sequence lookslike: "create sequence ackSequence increment by 1 start with 1;"</li>
+ <li>A Postgres sequence looks like: "CREATE SEQUENCE ackSequence START 1";</li>
+ </ul>
+ </li>
+ <li>For other databases you're on your own.</li>
+ <li>Define an <code>sequence-name</code> attribute in your field-descriptor - see below</li>
+ </ul>
+ </li>
+ </ul>
+ <br/>
+
+
+To tell OJB to use that sequence for your table add in your repository.xml the sequence
+name to the field-descriptor for your table's primary key field:
+
<source><![CDATA[
-<field-descriptor
- name="ackID"
- column="ACKID"
- jdbc-type="INTEGER"
- primarykey="true"
+<field-descriptor
+ name="ackID"
+ column="ACKID"
+ jdbc-type="INTEGER"
+ primarykey="true"
autoincrement="true"
- sequence-name="ackSeq"
+ sequence-name="ackSequence"
/>
]]></source>
-
- This will use a database defined sequence that is on your database.
- Currently, according to Armin Waibel who developed a bunch of this stuff,
- if the sequence that you've created in the database does not match to the name given here,
- you will not get an exception.
- OJB will create the sequence for you, I'll have to confirm that though.
- I can confirm that the application kept working.
- I just didn't check to see if it was using a new sequence or if it failed-over
- to the SequenceManagerHighLowImpl or something else.<br/><br/>
-
- <b>Second:</b> You need to secure the data at the database.
- Thomas Mahler (lead OJB developer and considerable ORM guru)
- recommended in one email that you use optimistic locking that is provided by OJB.
- Sounds good to me. To add optimistic locking to an OJB application,
- just add a TimeStamp or Integer column to your table.
- Then add a mapping in your repository file that adds locking="true". Example:
- <source><![CDATA[
- <field-descriptor
- name="ackOptLock"
- column="ACKOPTLOCK"
- jdbc-type="INTEGER"
- locking="true"
- />]]></source>
- OJB will then handle the locking for you. No explicit transactional code necessary.<br/><br/>
-
- <b>Third: </b>Do The Cache: You're basically in good shape at this point.
- OJB comes with JCS (Also from Jakarta as part of the Turbine project).
- I really didn't like the JCS implementation, which is why I'm writing this.
- You can, at this point, use any caching; role your own, buy one, use JCS.
- I'm not going to talk about JCS setup here.<br/>
- </subsection>
-
-
- <subsection name="Using the Tangosol Coherence cache as distributed cache in OJB">
- For Coherence: You need to download Coherence and add the coherence jar's to your classpath.
- Then you need to create a class that uses Coherence as your caching mechanism.
- Included at the end of this is a class called ObjectCacheCoherenceImpl.
- You'd need to edit your OJB.properties file to use this class.
- Here's mine (with packages)
- <source>ObjectCacheClass=org.nacse.jlib.ObjectCacheCoherenceImpl</source>
-
- Here's the sample class. Just add it, maybe change the package names, and go.
- I used Orion and JRun to do testing.
- Just deploy your app to two instances of the app-server and start-em up.
- You might want to add host and port number configs for Coherence:
-
- <source>-Dtangosol.coherence.localport=8089 and -Dtangosol.coherence.localhost=192.168.0.101</source>
-
- Source for <code>org.nacse.jlib.ObjectCacheCoherenceImpl</code>.
-
-<source><![CDATA[
-package org.nacse.jlib;
-import com.tangosol.net.CacheFactory;
+ <br/>
+
+ <b>Third: You need to secure the data at the database.</b>
+ Thomas Mahler (lead OJB developer and considerable ORM guru)
+ recommended in one email that you use the Optimistic Locking feature that is provided by OJB.
+ Sounds good to me. To do this you need to do three small steps:
+ <ul>
+ <li>Add a database column to your table that is either an INTEGER or a TIMESTAMP</li><br/>
+ <li>Add the field to your java class, and getter/setter methods:
+ <source><![CDATA[
+private Integer ackOptLock;
+
+public Integer getAckOptLock()
+{
+return ackOptLock;
+}
+
+public void setAckOptLock(Integer ackOptLock)
+{
+this.ackOptLock = ackOptLock;
+}]]>
+ </source><br/>
+ </li>
+ <li>Add the column to your table in your repository:
+ <source><![CDATA[
+<field-descriptor
+ name="ackOptLock"
+ column="ACKOPTLOCK"
+ jdbc-type="INTEGER"
+ locking="true"/>]]>
+ </source>
+ </li>
+ </ul>
+
+
+
+ Now OJB will handle the locking for you. No explicit transactional code necessary!<br/><br/>
+
+ <b>Fourth: Do The Cache.</b> You're basically in good shape at this point.
+ Now you've just got to set up OSCache to work with OJB. Here are the steps for that:<br/>
+
+ <ul>
+ <li>
+ Download OSCache from <a href="http://www.opensymphony.com/oscache/">OSCache</a>. Add the oscache-2.0.x.jar to
+ your project so that it is in your classpath (for Servlet/J2EE users place in your WEB-INF/lib directory).
+ You will also need commons-collections.jar and commons-logging.jar, if you don't already have them.
+ </li><br/>
+ <li>
+ Download JavaGroups from <a href="http://www.jgroups.org/javagroupsnew/docs/index.html">JavaGroups</a>. Add the
+ javagroups-all.jar to your classpath (for Servlet/J2EE users place in your WEB-INF/lib directory).
+ </li><br/>
+ <li>
+ In your OJB.properties file change the ObjectCacheClass property to be the following:
+ <source>ObjectCacheClass=org.nacse.jlib.ObjectCacheOSCacheImpl</source><br/>
+ To make OSCache the default used cache implementation. More info
+ about <a href="objectcache.html">object caching here</a>.
+ </li><br/>
+ <li>
+ Add oscache.properties from your OSCache distribution to your project so that it is in the classpath
+ (for Servlet/J2EE users place in your WEB-INF/classes directory). Open the file and make the following changes:<br/><br/>
+ <ol>
+ <li>
+ Add the following line to the CACHE LISTENERS section of your oscache.properties file:
+ <source>cache.event.listeners=com.opensymphony.oscache.plugins.
+ clustersupport.JavaGroupsBroadcastingListener</source><br/>
+ </li>
+ <li>
+ Add the following line at the end of the oscache.properties file (your network must support multicast):<br/>
+ <source>cache.cluster.multicast.ip=231.12.21.132</source><br/>
+ </li>
+ </ol>
+ </li>
+ <li>Add the following class to your project (feel free to change package name, but make sure
+ that you specify the full qualified class name in OJB.properties file).
+ You can find source of this class under <code>db-ojb/contrib/src/ObjectCacheOSCacheImpl</code>.
+ <br/><br/>
+ Source for <code>ObjectCacheOSCacheImpl</code>:
+
+<source><![CDATA[
import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.cache.ObjectCache;
import org.apache.ojb.broker.cache.RuntimeCacheException;
-import java.util.Map;
+import com.opensymphony.oscache.base.CacheEntry;
+import com.opensymphony.oscache.general.GeneralCacheAdministrator;
-public class ObjectCacheCoherenceImpl implements ObjectCache {
+public class ObjectCacheOSCacheImpl implements ObjectCache {
- private Map mapCache;
+ private static GeneralCacheAdministrator admin = new GeneralCacheAdministrator();
+ private static final int NO_REFRESH = CacheEntry.INDEFINITE_EXPIRY;
- public ObjectCacheCoherenceImpl() {
+ public ObjectCacheOSCacheImpl() {
}
- public ObjectCacheCoherenceImpl(PersistenceBroker broker) {
- mapCache = CacheFactory.getDistributedCache();
+ public ObjectCacheOSCacheImpl(PersistenceBroker broker) {
}
public void cache(Identity oid, Object obj) {
try {
- mapCache.put(oid.toString(), obj);
+ this.remove(oid);
+ admin.putInCache(oid.toString(), obj);
}
catch (Exception e) {
throw new RuntimeCacheException(e.getMessage());
@@ -131,12 +185,18 @@
}
public Object lookup(Identity oid) {
- return mapCache.get(oid.toString());
+ try {
+ return admin.getFromCache(oid.toString(), NO_REFRESH);
+ }
+ catch (Exception e) {
+ admin.cancelUpdate(oid.toString());
+ return null;
+ }
}
public void remove(Identity oid) {
try {
- mapCache.remove(oid.toString());
+ admin.flushEntry(oid.toString());
}
catch (Exception e) {
throw new RuntimeCacheException(e.getMessage());
@@ -144,9 +204,9 @@
}
public void clear() {
- if (mapCache != null) {
+ if (admin != null) {
try {
- mapCache.clear();
+ admin.flushAll();
}
catch (Exception e) {
throw new RuntimeCacheException(e);
@@ -155,10 +215,22 @@
}
}
]]></source>
-
- </subsection>
+ </li>
+ </ul>
+ <b>You're ready to go!</b> Now just create two instances of your application and see how they communicate at the cache level. Very cool.<br/><br/>
+ <b>Notes:</b>
+ <ul>
+ <li>For J2EE/Servlet users: I have tested this on a number of different application servers. If you're having
+ problems with your engine, post an email to the OJB Users mail list.</li><br/>
+ <li>OSCache also supports JMS for clustering here, which I haven't covered. If you either don't have access to
+ a multicast network, or just plain like JMS, please refer to the OSCache documentation for help with that
+ (<a href="http://www.opensymphony.com/oscache/clustering.html">OSCache Clustering with JMS</a>).</li><br/>
+ <li>I have also tested this with Tangosol Coherence. Please refer to this Blog entry for that setup:
+ <a href="http://www.freeroller.net/page/jmckerr">Coherence Setup</a></li><br/>
+ <li>OJB also has ships with JCS. Feel free to try that one out on your own.</li><br/>
+ </ul>
+ </subsection>
</section>
-
</body>
</document>
1.1 db-ojb/contrib/src/ObjectCacheOSCacheImpl.java
Index: ObjectCacheOSCacheImpl.java
===================================================================
import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.cache.ObjectCache;
import org.apache.ojb.broker.cache.RuntimeCacheException;
import com.opensymphony.oscache.base.CacheEntry;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
public class ObjectCacheOSCacheImpl implements ObjectCache {
private static GeneralCacheAdministrator admin = new GeneralCacheAdministrator();
private static final int NO_REFRESH = CacheEntry.INDEFINITE_EXPIRY;
public ObjectCacheOSCacheImpl() {
}
public ObjectCacheOSCacheImpl(PersistenceBroker broker) {
}
public void cache(Identity oid, Object obj) {
try {
this.remove(oid);
admin.putInCache(oid.toString(), obj);
}
catch (Exception e) {
throw new RuntimeCacheException(e.getMessage());
}
}
public Object lookup(Identity oid) {
try {
return admin.getFromCache(oid.toString(), NO_REFRESH);
}
catch (Exception e) {
admin.cancelUpdate(oid.toString());
return null;
}
}
public void remove(Identity oid) {
try {
admin.flushEntry(oid.toString());
}
catch (Exception e) {
throw new RuntimeCacheException(e.getMessage());
}
}
public void clear() {
if (admin != null) {
try {
admin.flushAll();
}
catch (Exception e) {
throw new RuntimeCacheException(e);
}
}
}
}
1.1 db-ojb/contrib/readme.txt
Index: readme.txt
===================================================================
===================================================================
contrib - The Contribution Directory
===================================================================
-------------------
db-ojb/contrib
-------------------
The 'db-ojb/contrib' directory contains documents, proposals
and tools relating to OJB.
-------------------
db-ojb/contrib/src
-------------------
Under 'db-ojb/contrib/src' you can find contribution classes and implementations,
extensions of OJB classes with e.g. non-distributable dependencies.
---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org