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