db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject svn commit: r422216 [1/2] - in /db/ojb/trunk/src: test/org/apache/ojb/ test/org/apache/ojb/performance/ test/org/apache/ojb/quick-db/ xdoclet/test/xdoclet/modules/ojb/tests/
Date Sat, 15 Jul 2006 13:55:52 GMT
Author: arminw
Date: Sat Jul 15 06:55:51 2006
New Revision: 422216

URL: http://svn.apache.org/viewvc?rev=422216&view=rev
Log:
merge trunk with 1.0.x

Modified:
    db/ojb/trunk/src/test/org/apache/ojb/OJB-logging.properties
    db/ojb/trunk/src/test/org/apache/ojb/OJB.properties
    db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticle.java
    db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticleImpl.java
    db/ojb/trunk/src/test/org/apache/ojb/performance/PerfMain.java
    db/ojb/trunk/src/test/org/apache/ojb/performance/PerfTest.java
    db/ojb/trunk/src/test/org/apache/ojb/quick-db/OJB.script
    db/ojb/trunk/src/test/org/apache/ojb/repository.dtd
    db/ojb/trunk/src/test/org/apache/ojb/repository_database.xml
    db/ojb/trunk/src/test/org/apache/ojb/repository_junit.xml
    db/ojb/trunk/src/test/org/apache/ojb/repository_junit_inheritance.xml
    db/ojb/trunk/src/test/org/apache/ojb/repository_junit_odmg.xml
    db/ojb/trunk/src/test/org/apache/ojb/repository_junit_reference.xml
    db/ojb/trunk/src/test/org/apache/ojb/web.xml
    db/ojb/trunk/src/xdoclet/test/xdoclet/modules/ojb/tests/TestRowReader.java

Modified: db/ojb/trunk/src/test/org/apache/ojb/OJB-logging.properties
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/OJB-logging.properties?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/OJB-logging.properties (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/OJB-logging.properties Sat Jul 15 06:55:51 2006
@@ -64,6 +64,7 @@
 #
 # Logger for metadata classes, useful for debugging parsing of repository.xml!
 # persistence capable object metadata
+org.apache.ojb.broker.metadata.MetadataManager.LogLevel=WARN
 org.apache.ojb.broker.metadata.DescriptorRepository.LogLevel=WARN
 org.apache.ojb.broker.metadata.RepositoryXmlHandler.LogLevel=WARN
 org.apache.ojb.broker.metadata.ConnectionDescriptorXmlHandler.LogLevel=WARN
@@ -76,6 +77,7 @@
 org.apache.ojb.broker.accesslayer.RsIterator.LogLevel=WARN
 org.apache.ojb.broker.accesslayer.StatementsForClassImpl.LogLevel=WARN
 org.apache.ojb.broker.accesslayer.sql.SqlGeneratorDefaultImpl.LogLevel=WARN
+org.apache.ojb.broker.core.QueryReferenceBroker.LogLevel=WARN
 #
 # Jdbc Batch Handling
 org.apache.ojb.broker.accesslayer.batch.BatchManagerImpl.LogLevel=WARN
@@ -117,9 +119,11 @@
 org.apache.ojb.odmg.DatabaseImpl.LogLevel=WARN
 org.apache.ojb.odmg.ObjectEnvelopeTable.LogLevel=WARN
 org.apache.ojb.odmg.ObjectEnvelope.LogLevel=WARN
+org.apache.ojb.odmg.Image.LogLevel=WARN
 org.apache.ojb.odmg.ObjectEnvelopeOrdering.LogLevel=WARN
 org.apache.ojb.odmg.LocalTxManager.LogLevel=WARN
 org.apache.ojb.odmg.JTATxManager.LogLevel=WARN
+org.apache.ojb.odmg.locking.LockManagerFactory.LogLevel=WARN
 #
 #
 # Special Logger categories used in test suite

Modified: db/ojb/trunk/src/test/org/apache/ojb/OJB.properties
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/OJB.properties?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/OJB.properties (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/OJB.properties Sat Jul 15 06:55:51 2006
@@ -24,7 +24,7 @@
 # repository file settings
 #----------------------------------------------------------------------------------------
 # The repositoryFile entry tells OJB to use this file as as its standard mapping
-# repository. The file is looked up from the classpath.
+# repository. First OJB lookup the file as resource from classpath, second as ordinary file.
 #
 repositoryFile=repository.xml
 #
@@ -38,10 +38,10 @@
 #
 # If Repository serialization is used the entry serializedRepositoryPath defines the
 # directory where the Repository is written to and read from.
-# this entry is used only when the useSerializedRepository flag is set to true
-#
+# this entry is used only when the useSerializedRepository flag is set to 'true'
 serializedRepositoryPath=.
 #
+#
 #----------------------------------------------------------------------------------------
 # PersistenceBrokerFactory / PersistenceBroker
 #----------------------------------------------------------------------------------------
@@ -63,6 +63,21 @@
 # Using this implementation OJB works as a simple OODBMS
 #PersistenceBrokerClass=org.apache.ojb.broker.prevayler.PBPrevaylerImpl
 #
+#
+# This setting can be helpful during development if the PersistenceBroker transaction
+# demarcation was used (this is true in most cases). If set 'true' on PB#store(...)
+# and PB#delete(...) methods calls OJB check for active PB-tx and if no active tx is
+# found a error is logged. This can help to avoid store/delete calls without a running
+# PB-tx while development. Default setting is 'false'. (Note: When using OJB in a managed
+# environment *without* OJB-caching, it's valid to use store/delete calls without a running PB-tx)
+TxCheck=false
+#
+# This setting can be helpful during development to detect PersistenceBroker leaks
+# (PB instances which are not closed after use). If enabled an error message including
+# the caller stack trace is logged when garbage collector free unclosed PB instances.
+# Default setting is 'false'.
+BrokerLeakDetection=false
+#
 #----------------------------------------------------------------------------------------
 # PersistenceBroker pool
 #----------------------------------------------------------------------------------------
@@ -135,7 +150,7 @@
 #			can only be generated from classes that implement an interface, and the generated
 #			Proxy will implement all methods of that interface.
 #
-# NOTE: The IndirectionHandlerClass setting, if given, must coorespond with the ProxyFactoryClass
+# NOTE: The appropriate cooresponding IndirectionHandler must be choosen as well
 #
 ProxyFactoryClass=org.apache.ojb.broker.core.proxy.ProxyFactoryCGLIBImpl
 #ProxyFactoryClass=org.apache.ojb.broker.core.proxy.ProxyFactoryJDKImpl
@@ -174,7 +189,6 @@
 #
 CollectionProxyClass=org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl
 #
-#
 #----------------------------------------------------------------------------------------
 # StatementManager
 #----------------------------------------------------------------------------------------
@@ -213,6 +227,21 @@
 #
 #
 #----------------------------------------------------------------------------------------
+# LobHelper
+#----------------------------------------------------------------------------------------
+# Set the LobHelper implementation.
+LobHelperClass=org.apache.ojb.broker.lob.LobHelperImpl
+#
+# LOB-locator objects (Blob and Clob fields in persistence capable objects) are only
+# valid as long as the current PersistenceBroker transaction is active. After commit or
+# rollback the LOB-object will be invalidated and before next access to the LOB-locator
+# object it must be refreshed. Cached persistent objects with LOB-content need refresh
+# too. OJB will automatically refresh all objects requested by query or identity lookup.
+# Set this property to 'false' to disable this service.
+LobAutoRefresh=true
+#
+#
+#----------------------------------------------------------------------------------------
 # ObjectFactory
 #----------------------------------------------------------------------------------------
 # Specify implementation class for object factory used to instantiate persistent objects.
@@ -226,10 +255,6 @@
 # The concrete ObjectCache implementation has to specified in the repository file using
 # the 'object-cache' element. See documentation for more detailed info.
 #
-# NOTE: CacheFilters declaration was removed (since OJB 1.0.2). To exclude
-# an object or a whole packages from being cached use a specific property in
-# cache declaration - see caching guide in reference docs.
-#
 # The class used as first level cache. Each PersistenceBroker instance use its on
 # instance of this class.
 SessionCacheClass=org.apache.ojb.broker.cache.SessionCacheImpl
@@ -249,14 +274,15 @@
 #LockManagerClass=org.apache.ojb.broker.locking.LockManagerCommonsImpl
 LockManagerClass=org.apache.ojb.broker.locking.LockManagerInMemoryImpl
 #
+# The LockTimeout entry defines the maximum time in milliseconds
+# that a lock may be hold. Defaults to 120000 = 2 minutes
+LockTimeout=120000
+#
 # The LockServletUrl entry points to the Lockserver servlet.
-# This Servlet is addressed by all distributed JVMs if the RemoteLockMapImpl
+# This Servlet is addressed by all distributed JVMs if LockManagerRemoteImpl
 # is used.
 #LockServletUrl=http://127.0.0.1:8080/ojb-lockserver
 #
-# The LockTimeout entry defines the maximum time in milliseconds
-# that a lock may be hold. Defaults to 60000 = 1 minute
-LockTimeout=60000
 #
 #
 #----------------------------------------------------------------------------------------
@@ -330,16 +356,6 @@
 # This setting can be changed at runtime using OJB's ODMG extensions.
 Ordering=true
 #
-# Allows to influence the order of objects (used when the transaction commits).
-# If 'true' method calls like
-# - org.odmg.Transaction#lock(Object, int)
-# - org.odmg.Database#deletePersistent(Object)
-# - org.odmg.Database#makePersistent(Object)
-# determine the order of objects before commit.
-# Note: If OJB's ordering is enabled the order of objects may change
-# at commit of the transaction.
-# This setting can be changed at runtime using OJB's ODMG extensions.
-NoteUserOrder=false
 #
 #
 # Set the specific odmg-LockManager used in ODMG implementation
@@ -375,12 +391,16 @@
 # By default the best performing attribute/refection based implementation
 # is selected (PersistentFieldDirectAccessImpl).
 #
-# - PersistentFieldDirectAccessImpl
+# - PersistentFieldDirectImpl
 #   is a high-speed version of the access strategies.
 #   It does not cooperate with an AccessController,
 #   but accesses the fields directly. Persistent
 #   attributes don't need getters and setters
 #   and don't have to be declared public or protected
+# - PersistentFieldCGLibImpl
+#   A very fast beans compliant (getter/setter access based) PersistentField
+#   implementation (it's three times faster than the direct field access via reflection).
+#   Needs public getter/setter for all declared fields.
 # - PersistentFieldPrivilegedImpl
 #   Same as above, but does cooperate with AccessController and do not
 #   suppress the java language access check (but is slow compared with direct access).
@@ -394,15 +414,23 @@
 #   (Note: DynaBean implementation does not support nested fields)
 # - PersistentFieldAutoProxyImpl
 #   for each field determines upon first access how to access this particular field
-#   (directly, as a bean, as a dyna bean) and then uses that strategy
+#   (cglib based, directly, as a bean, as a dyna bean) and then uses that strategy.
+#   The order of field access testing goes from the fastest to slowest, so you will always
+#   get the best performance.
 #
-PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDirectImpl
+#PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDirectImpl
+PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldCGLibImpl
 #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldPrivilegedImpl
 #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldIntrospectorImpl
 #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDynaBeanImpl
 #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldAutoProxyImpl
 #
 #
+# Allows to extend class RepositoryPersistor used to read and write (write is deprecated)
+# OJB's metadata.
+RepositoryPersistorClass=org.apache.ojb.broker.metadata.RepositoryPersistor
+#
+#
 #----------------------------------------------------------------------------------------
 # Component Intercepting for Profiling and Tracing
 #----------------------------------------------------------------------------------------
@@ -413,6 +441,7 @@
 #
 #InterceptorClass=org.apache.ojb.broker.util.interceptor.TracingInterceptor
 #
+#
 #----------------------------------------------------------------------------------------
 # Transaction Management and assocation
 #----------------------------------------------------------------------------------------
@@ -436,6 +465,12 @@
 #JTATransactionManagerClass=org.apache.ojb.broker.transaction.tm.SunOneTransactionManagerFactory
 # JOnAs transaction manager factory
 #JTATransactionManagerClass=org.apache.ojb.broker.transaction.tm.JOnASTransactionManagerFactory
+# OC4J transaction manager factory
+#JTATransactionManagerClass=org.apache.ojb.broker.transaction.tm.OC4JTransactionManagerFactory
+# Resin transaction manager factory
+#JTATransactionManagerClass=org.apache.ojb.broker.transaction.tm.ResinTransactionManagerFactory
+# JRun transaction manager factory
+#JTATransactionManagerClass=org.apache.ojb.broker.transaction.tm.JRunTransactionManagerFactory
 #
 #
 #----------------------------------------------------------------------------------------

Modified: db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticle.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticle.java?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticle.java (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticle.java Sat Jul 15 06:55:51 2006
@@ -1,6 +1,6 @@
 package org.apache.ojb.performance;
 
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

Modified: db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticleImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticleImpl.java?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticleImpl.java (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/performance/PerfArticleImpl.java Sat Jul 15 06:55:51 2006
@@ -1,8 +1,10 @@
 package org.apache.ojb.performance;
 
 import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.EqualsBuilder;
 
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,9 +20,8 @@
  */
 
 /**
- * Implementation of {@link PerfArticle} interface.
+ * Implementation of the {@link PerfArticle} interface.
  *
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
  * @version $Id$
  */
 public class PerfArticleImpl implements PerfArticle
@@ -141,5 +142,33 @@
     public void setProductGroupId(int productGroupId)
     {
         this.productGroupId = productGroupId;
+    }
+
+    public int hashCode()
+    {
+        return new HashCodeBuilder().append(articleId).hashCode();
+    }
+
+    public boolean equals(Object obj)
+    {
+        if(obj == this)
+        {
+            return true;
+        }
+        if(obj instanceof PerfArticleImpl)
+        {
+            PerfArticleImpl o = (PerfArticleImpl) obj;
+            return new EqualsBuilder()
+                    .append(articleId, o.articleId)
+                    .append(articleName, o.articleName)
+                    .append(minimumStock, o.minimumStock)
+                    .append(price, o.price)
+                    .append(productGroupId, o.productGroupId)
+                    .append(stock, o.stock)
+                    .append(supplierId, o.supplierId)
+                    .append(unit, o.unit)
+                    .isEquals();
+        }
+        return false;
     }
 }

Modified: db/ojb/trunk/src/test/org/apache/ojb/performance/PerfMain.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/performance/PerfMain.java?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/performance/PerfMain.java (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/performance/PerfMain.java Sat Jul 15 06:55:51 2006
@@ -1,6 +1,6 @@
 package org.apache.ojb.performance;
 
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,35 +15,40 @@
  * limitations under the License.
  */
 
-import java.io.OutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.PrintStream;
+import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
-import java.util.Collections;
-import java.util.Comparator;
 
-import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.SystemUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.commons.lang.math.NumberUtils;
 
 /**
- * The OJB stress/performance test - a simple performance test framework for
- * testing multi-threaded environments.
+ * The OJB stress/performance test - a simple performance test application to
+ * run O/R mapper in a simulated single/multi-threaded environment.
  *
  * <p>
  * <b>You have two possibilities to run this test:</b>
  * </p>
  * <p>
- * - use the build script and call
+ * - use the OJB build script and call
  * <br/>
  * <code>ant perf-test</code>
  * </p>
  * <p>
- * - or perform the test class by yourself
+ * - or for standalone use perform the test class by yourself
  * <br/>
  * <code>
  * java -classpath CLASSPATH org.apache.ojb.performance.PerfMain
@@ -54,52 +59,70 @@
  * </code>
  * <br/>
  * <code>
- * [number of test loops]
+ * [number of test loops, default '5']
+ * </code>
+ * <br/>
+ * <code>
+ * [number of threads, default '10']
  * </code>
  * <br/>
  * <code>
- * [number of threads]
+ * [number of insert/fetch/delete loops per thread, default '100']
  * </code>
  * <br/>
  * <code>
- * [number of insert/fetch/delete loops per thread]
+ * [boolean - run in stress mode if set true, run in performance mode if set false, default 'false']
  * </code>
  * <br/>
  * <code>
- * [boolean - run in stress mode if set true, run in performance mode if set false, default false]
+ * [boolean - if 'true' all log messages will be print, else only a test summary, default 'true']
  * </code>
  * </p>
  * <p>
  * For example:
  * </p>
- * <code>java -classpath CLASSPATH my.MyPerfTest,myMyPerfTest2 3 10 2000 false</code>
+ * <code>java -classpath CLASSPATH my.MyPerfTest,myMyPerfTest2 3 10 200 false true</code>
  *
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
  * @version $Id$
  */
 public class PerfMain
 {
-    protected static final String EOL = System.getProperty("line.separator");
+    static final int TEST_INSERT = 0;
+    static final int TEST_FETCH = 1;
+    static final int TEST_FETCH_2 = 2;
+    static final int TEST_BY_IDENTITY = 3;
+    static final int TEST_UPDATE = 4;
+    static final int TEST_DELETE = 5;
+
+    static final short TIME_TOTAL = 0;
+    static final short TIME_INSERT = 1;
+    static final short TIME_FETCH = 2;
+    static final short TIME_FETCH_2 = 3;
+    static final short TIME_BY_IDENTITY = 4;
+    static final short TIME_UPDATE = 5;
+    static final short TIME_DELETE = 6;
 
     /**
-     * iterations per thread
-     */
-    private static int iterationsPerThread = 500;
-    /**
-     * number of concurrent threads
+     * The factor for get by Identity calls, e.g. 4 means handling 100 objects
+     * result in 100/4 getByIdentity calls.
      */
+    protected static final int BY_IDENTITY_FACTOR = 4;
+    protected static final String EOL = SystemUtils.LINE_SEPARATOR;
+
+    /** iterations per thread */
+    private static int iterationsPerThread = 100;
+    /** number of concurrent threads */
     private static int concurrentThreads = 10;
-    /**
-     * if false we use performance optimized delete/insert method
-     */
+    /** if false we use performance optimized delete/insert method */
     private static boolean useStressMode = false;
-    /**
-     * number of test loops
-     */
-    private static int testLoops = 1;
+    /** number of test loops */
+    private static int testLoops = 5;
+    /** if false only a test summary will be print*/
+    private static boolean logAll = true;
 
     private HashMap resultMap;
-    private Map exceptionMap;
+    private HashMap exceptionMap;
+    private static Printer printer;
 
 
     public static void main(String[] args)
@@ -111,27 +134,33 @@
             // start the test
             main.startPerfTest(args);
             // print the test results
-            main.printResult(System.out);
+            main.printResult();
             peroid = System.currentTimeMillis() - peroid;
-            System.out.println();
-            System.out.println("PerfTest takes " + peroid / 1000 + " [sec]");
+            if(logAll) printer().println();
+            if(logAll) printer().println("PerfTest takes " + peroid / 1000 + " [sec]");
         }
         catch (Exception e)
         {
             e.printStackTrace();
         }
-        System.exit(0);
     }
 
     public PerfMain()
     {
         this.resultMap = new HashMap();
-        this.exceptionMap = new Hashtable();
+        this.exceptionMap = new HashMap();
     }
 
-    /**
-     * Call this to begin the performance test.
-     */
+    public static Printer printer()
+    {
+        if(printer == null)
+        {
+            printer = new Printer();
+        }
+        return printer;
+    }
+
+    /** Call this to begin the performance test. */
     public void startPerfTest(String[] args) throws Exception
     {
         ArrayList testList = null;
@@ -171,6 +200,11 @@
             {
                 useStressMode = Boolean.valueOf(args[4]).booleanValue();
             }
+            // log mode
+            if (args.length > 5)
+            {
+                logAll = Boolean.valueOf(args[5]).booleanValue();
+            }
         }
         catch (Exception e)
         {
@@ -182,104 +216,75 @@
                     " [number of test loops]" +
                     " [number of threads]" +
                     " [number of insert/fetch/delete loops per thread]" +
-                    " [boolean - run in stress mode]");
+                    " [boolean - run in stress mode]" +
+                    " [boolean - if 'true' detailed log messages will be print]");
             System.err.println();
             System.err.println("Example: java -classpath" +
                     " CLASSPATH org.apache.ojb.performance.PerfMain org.MyPerfTest 3 10 500 false");
         }
 
-        System.out.println("####################################################" +
-                EOL + "# Start OJB performance-test framework - do " + testLoops + " loop #" +
-                EOL + "####################################################" + EOL);
+        if(logAll) printer().println("                                                    " +
+                EOL + "Start OJB Performance Test - running " + testLoops + " test loops" +
+                EOL + "---------------------------------------------------");
 
-        PerfTest test = null;
+        PerfRunner test;
+        ThreadGroup threadGroup = new ThreadGroup("PerfTest_Group_id=" + Math.random());
         for (int i = 0; i < testLoops; i++)
         {
             Runtime rt = Runtime.getRuntime();
-            long freeMem = 0;
-            System.out.println("==> perform test loop " + (i + 1));
+            long freeMem;
+            if(logAll) printer().println(" Loop " + (i + 1));
 
-            if(i%2 == 0)
+            for(int j = 0; j < testList.size(); j++)
             {
-                for(int j = 0; j < testList.size(); j++)
-                {
-                    String perfTest = (String) testList.get(j);
-                    test = (PerfTest) Class.forName(perfTest).newInstance();
-                    test.registerPerfMain(this);
-
-                    rt.gc();
-                    Thread.sleep(500);
-                    rt.freeMemory();
-                    rt.gc();
-                    Thread.sleep(500);
-                    freeMem = rt.freeMemory();
-                    test.performTest();
-                    freeMem = (freeMem - rt.freeMemory()) / 1024;
-                    System.out.println("allocated memory after test: " + freeMem + " kb");
-                    // rt.gc();
-                }
+                String perfTest = (String) testList.get(j);
+                Class testHandle = Class.forName(perfTest);
+                test = new PerfRunner(threadGroup, testHandle);
+                test.registerPerfMain(this);
+
+                rt.gc();
+                Thread.sleep(300);
+                rt.freeMemory();
+                rt.gc();
+                Thread.sleep(100);
+                freeMem = rt.freeMemory();
+                test.performTest();
+                freeMem = (freeMem - rt.freeMemory()) / 1024;
+                if(logAll) printer().println(" allocated memory=" + freeMem + "kb");
+                // rt.gc();
             }
-            else
+            ArrayList tmpList = new ArrayList(testList);
+            int size = tmpList.size();
+            Object last = tmpList.remove(size - 1);
+            tmpList.add(0, last);
+            testList = tmpList;
+        }
+
+        // should always be skipped, because we use 'thread.join'
+        while(threadGroup.activeCount() > 0)
+        {
+            PerfMain.printer().println("## active threads: " + threadGroup.activeCount());
+            try
             {
-                for(int j = (testList.size() - 1); j >= 0; j--)
-                {
-                    String perfTest = (String) testList.get(j);
-                    test = (PerfTest) Class.forName(perfTest).newInstance();
-                    test.registerPerfMain(this);
-
-                    rt.gc();
-                    Thread.sleep(500);
-                    rt.freeMemory();
-                    rt.gc();
-                    Thread.sleep(500);
-                    freeMem = rt.freeMemory();
-                    test.performTest();
-                    freeMem = (freeMem - rt.freeMemory()) / 1024;
-                    System.out.println("allocated memory after test: " + freeMem + " kb");
-                    // rt.gc();
-                }
+                Thread.sleep(200);
+            }
+            catch(InterruptedException ignore)
+            {
+                // ignore
             }
         }
-
-//        Iterator it = testList.iterator();
-//        while (it.hasNext())
-//        {
-//            String perfTest = (String) it.next();
-//            PerfTest test = (PerfTest) Class.forName(perfTest).newInstance();
-//            test.registerPerfMain(this);
-//            Runtime rt = Runtime.getRuntime();
-//            long freeMem = 0;
-//            for (int i = 0; i < testLoops; i++)
-//            {
-//                System.out.println("perform test loop " + (i + 1));
-//                freeMem = rt.freeMemory();
-//                test.performTest();
-//                freeMem = (freeMem - rt.freeMemory()) / 1024;
-//                System.out.println("allocated memory after test: " + freeMem + " kb");
-//                rt.gc();
-//            }
-//        }
     }
 
-    public void printResult(OutputStream out)
+    public void printResult()
     {
-        PrintStream print = new PrintStream(out);
-        print.println();
+        printer().println();
+        printer().println(buildTestSummary(prepareTestResults()));
+    }
 
-        if (!getExceptionMap().isEmpty())
-        {
-            StringBuffer buf = new StringBuffer();
-            buf.append(EOL + "Failures occured, test not valid:" + EOL);
-            Iterator it = getExceptionMap().keySet().iterator();
-            while (it.hasNext())
-            {
-                String causer = (String) it.next();
-                buf.append("Failure cause by " + causer + ", exception was " + exceptionMap.get(causer) + EOL);
-            }
-            print.println(buf.toString());
-        }
-        List results = new ArrayList(resultMap.values());
-        Collections.sort(results, new Comparator()
+    private PerfResult[] prepareTestResults()
+    {
+        List tmp = new ArrayList(resultMap.values());
+        Collections.sort(tmp, new Comparator()
         {
             public int compare(Object o1, Object o2)
             {
@@ -288,107 +293,248 @@
                 return new Long(r1.getTotalTime()).compareTo(new Long(r2.getTotalTime()));
             }
         });
-        print.println(buildTestSummary(results));
+
+        PerfResult[] results = (PerfResult[]) tmp.toArray(new PerfResult[tmp.size()]);
+        long[][] calibration = new long[6][results.length];
+        for(int k = 0; k < 6; k++)
+        {
+            for(int i = 0; i < results.length; i++)
+            {
+                PerfResult result = results[i];
+                if(k==TEST_INSERT) calibration[TEST_INSERT][i] = result.getInsertPeriod();
+                if(k==TEST_FETCH) calibration[TEST_FETCH][i] = result.getFetchPeriod();
+                if(k==TEST_FETCH_2) calibration[TEST_FETCH_2][i] = result.getFetchSecondPeriod();
+                if(k==TEST_BY_IDENTITY) calibration[TEST_BY_IDENTITY][i] = result.getByIdentityPeriod();
+                if(k==TEST_UPDATE) calibration[TEST_UPDATE][i] = result.getUpdatePeriod();
+                if(k==TEST_DELETE) calibration[TEST_DELETE][i] = result.getDeletePeriod();
+            }
+        }
+
+        for(int k = 0; k < 6; k++)
+        {
+            if(k==TEST_INSERT)
+            {
+                long[] resultArray = calibration[TEST_INSERT];
+                long minimum = NumberUtils.min(resultArray);
+                for(int i = 0; i < results.length; i++)
+                {
+                    results[i].setInsertMinimun(minimum);
+                }
+            }
+            if(k==TEST_FETCH)
+            {
+                long[] resultArray = calibration[TEST_FETCH];
+                long minimum = NumberUtils.min(resultArray);
+                for(int i = 0; i < results.length; i++)
+                {
+                    results[i].setFetchMinimun(minimum);
+                }
+            }
+            if(k==TEST_FETCH_2)
+            {
+                long[] resultArray = calibration[TEST_FETCH_2];
+                long minimum = NumberUtils.min(resultArray);
+                for(int i = 0; i < results.length; i++)
+                {
+                    results[i].setFetchSecondMinimun(minimum);
+                }
+            }
+            if(k==TEST_BY_IDENTITY)
+            {
+                long[] resultArray = calibration[TEST_BY_IDENTITY];
+                long minimum = NumberUtils.min(resultArray);
+                for(int i = 0; i < results.length; i++)
+                {
+                    results[i].setByIdentityMinimun(minimum);
+                }
+            }
+            if(k==TEST_UPDATE)
+            {
+                long[] resultArray = calibration[TEST_UPDATE];
+                long minimum = NumberUtils.min(resultArray);
+                for(int i = 0; i < results.length; i++)
+                {
+                    results[i].setUpdateMinimun(minimum);
+                }
+            }
+            if(k==TEST_DELETE)
+            {
+                long[] resultArray = calibration[TEST_DELETE];
+                long minimum = NumberUtils.min(resultArray);
+                for(int i = 0; i < results.length; i++)
+                {
+                    results[i].setDeleteMinimun(minimum);
+                }
+            }
+        }
+
+        return results;
     }
 
-    private String buildTestSummary(Collection results)
+    private String buildTestSummary(PerfResult[] results)
     {
-        int columnLength = 8;
+        int columnLength = 12;
         int columnNumbers = 8;
+        final String indent = "  ";
 
         StringBuffer buf = new StringBuffer();
         // table header
         buf.append(EOL);
         for (int i = 0; i < columnNumbers; i++)
         {
-            buf.append(getFilledUpToLength("", columnLength, "="));
+            buf.append(alignToLength(columnLength, "="));
         }
         buf.append(EOL);
-        buf.append(getFilledUpToLength("", columnLength, " "));
-        buf.append(getFilledUpToLength("OJB PERFORMANCE TEST SUMMARY", columnLength, " "));
+        buf.append(alignToLength(columnLength, " "));
+        String headline = "OJB PERFORMANCE TEST SUMMARY, " + new Date();
+        buf.append(alignLeft(headline, columnLength));
         buf.append(EOL);
-
-        buf.append(PerfMain.getConcurrentThreads() + " concurrent threads, handle " +
-                PerfMain.getIterationsPerThread() + " objects per thread");
+        for (int i = 0; i < columnNumbers; i++)
+        {
+            buf.append(alignToLength(columnLength, "-"));
+        }
         buf.append(EOL);
-        buf.append(getFilledUpToLength("", columnLength, " "));
-        buf.append("- " + (isUseStressMode() == false ? "performance mode" : "stress mode"));
-        buf.append(" - results per thread");
+        buf.append(indent).append(PerfMain.getConcurrentThreads());
+        buf.append(" concurrent threads, handle ");
+        buf.append(PerfMain.getIterationsPerThread());
+        buf.append(" objects per thread");
+        buf.append(EOL).append(indent).append(iterationsPerThread).append(" INSERT operations per test instance");
+        buf.append(EOL).append(indent + "FETCH collection of ").append(iterationsPerThread).append(" objects per test instance");
+        buf.append(EOL).append(indent + "Repeat FETCH collection of ").append(iterationsPerThread).append(" objects per test instance");
+        int byIdCalls = (iterationsPerThread / PerfMain.BY_IDENTITY_FACTOR);
+        buf.append(EOL).append(indent).append((byIdCalls == 0 ? 1: byIdCalls)).append(" get by Identity calls  per test instance");
+        buf.append(EOL).append(indent).append(iterationsPerThread).append(" UPDATE operations per test instance");
+        buf.append(EOL).append(indent).append(iterationsPerThread).append(" DELETE operations per test instance");
+        buf.append(EOL).append(indent);
+        buf.append("- ").append(!(isUseStressMode()) ? "performance mode" : "stress mode");
+        buf.append(" - results per test instance (average)");
         buf.append(EOL);
         for (int i = 0; i < columnNumbers; i++)
         {
-            buf.append(getFilledUpToLength("", columnLength, "="));
+            buf.append(alignToLength(columnLength, "="));
         }
         buf.append(EOL);
-        buf.append(getFilledUpToLength("API", columnLength, " "));
-        buf.append(getFilledUpToLength("Period", columnLength, " "));
-        buf.append(getFilledUpToLength("Total", columnLength, " "));
-        buf.append(getFilledUpToLength("Total", columnLength, " "));
-        buf.append(getFilledUpToLength("Insert", columnLength, " "));
-        buf.append(getFilledUpToLength("Fetch", columnLength, " "));
-        buf.append(getFilledUpToLength("Update", columnLength, " "));
-        buf.append(getFilledUpToLength("Delete", columnLength, " "));
+        buf.append(alignLeft("API", columnLength));
+        //buf.append(alignLeft("Period", columnLength, " "));
+        //buf.append(alignLeft("Total", columnLength, " "));
+        buf.append(alignLeft("Total", columnLength));
+
+        buf.append(alignLeft("Insert", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("Fetch", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("Fetch 2", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("by Id", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("Update", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("Delete", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+
         buf.append(EOL);
-        buf.append(getFilledUpToLength("", columnLength, " "));
-        buf.append(getFilledUpToLength("[sec]", columnLength, " "));
-        buf.append(getFilledUpToLength("[sec]", columnLength, " "));
-        buf.append(getFilledUpToLength("[%]", columnLength, " "));
-        buf.append(getFilledUpToLength("[msec]", columnLength, " "));
-        buf.append(getFilledUpToLength("[msec]", columnLength, " "));
-        buf.append(getFilledUpToLength("[msec]", columnLength, " "));
-        buf.append(getFilledUpToLength("[msec]", columnLength, " "));
+        buf.append(alignToLength(columnLength, " "));
+        //buf.append(alignLeft("[sec]", columnLength, " "));
+        //buf.append(alignLeft("[sec]", columnLength, " "));
+        buf.append(alignLeft("[%]", columnLength));
+
+        buf.append(alignLeft("[msec]", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("[msec]", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("[msec]", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("[msec]", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("[msec]", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
+        buf.append(alignLeft("[msec]", columnLength));
+        //buf.append(alignToLength(columnLength, " "));
         buf.append(EOL);
         for (int i = 0; i < columnNumbers; i++)
         {
-            buf.append(getFilledUpToLength("", columnLength, "-"));
+            buf.append(alignToLength(columnLength, "-"));
         }
 
-        List failures = new ArrayList();
         // fill table
-        Iterator it = results.iterator();
         int counter = 0;
         double calibrationMark = 0;
-        while (it.hasNext())
+        for(int i = 0; i < results.length; i++)
         {
+            PerfResult result = results[i];
             buf.append(EOL);
-            PerfResult res = (PerfResult) it.next();
-//            if(!res.isValid())
-//            {
-//                failures.add(res);
-//            }
             if(counter == 0)
             {
-                calibrationMark = (double) (((double) res.getTotalTime()) / 1000);
+                // the first one is the fastest
+                calibrationMark = result.getTotalTime();
             }
-            buf.append(getFilledUpToLength(res.getTestName(), columnLength, " "));
-            buf.append(getFilledUpToLength(new Double((double) (((double) res.getTestPeriod()) / 1000)).toString(), columnLength, " "));
-            Double totalTime = new Double((double) (((double) res.getTotalTime()) / 1000));
-            buf.append(getFilledUpToLength(totalTime.toString(), columnLength, " "));
-            buf.append(getFilledUpToLength(new Long(Math.round((totalTime.doubleValue() / calibrationMark) * 100)).toString(), columnLength, " "));
-            buf.append(getFilledUpToLength(new Long(res.getInsertPeriod()).toString(), columnLength, " "));
-            buf.append(getFilledUpToLength(new Long(res.getFetchPeriod()).toString(), columnLength, " "));
-            buf.append(getFilledUpToLength(new Long(res.getUpdatePeriod()).toString(), columnLength, " "));
-            buf.append(getFilledUpToLength(new Long(res.getDeletePeriod()).toString(), columnLength, " "));
+            //double period = (double) result.getTestPeriod() / 1000;
+            //double total = (double) Math.round((double) result.getTotalTime()) / 1000;
+            long percent = Math.round((result.getTotalTime() / calibrationMark) * 100);
+
+            buf.append(alignLeft(result.getTestName(), columnLength));
+            //buf.append(alignLeft(""+period, columnLength, " "));
+            //buf.append(alignLeft(""+total, columnLength, " "));
+            buf.append(alignLeft(""+percent, columnLength));
+
+            buf.append(alignLeft(result.getInsertResult()+result.getInsertResultPercent(), columnLength));
+            //buf.append(alignLeft(result.getInsertResultPercent(), columnLength, " "));
+            buf.append(alignLeft(result.getFetchResult()+result.getFetchResultPercent(), columnLength));
+            //buf.append(alignLeft(result.getFetchResultPercent(), columnLength, " "));
+            buf.append(alignLeft(result.getFetchSecondResult()+result.getFetchSecondResultPercent(), columnLength));
+            //buf.append(alignLeft(result.getFetchSecondResultPercent(), columnLength, " "));
+            buf.append(alignLeft(result.getByIdentityResult()+result.getByIdentityResultPercent(), columnLength));
+            //buf.append(alignLeft(result.getByIdentityResultPercent(), columnLength, " "));
+            buf.append(alignLeft(result.getUpdateResult()+result.getUpdateResultPercent(), columnLength));
+            //buf.append(alignLeft(result.getUpdateResultPercent(), columnLength, " "));
+            buf.append(alignLeft(result.getDeleteResult()+result.getDeleteResultPercent(), columnLength));
+            //buf.append(alignLeft(result.getDeleteResultPercent(), columnLength, " "));
             counter++;
         }
         buf.append(EOL);
+
+        if (!getExceptionMap().isEmpty())
+        {
+            buf.append(EOL).append("!! Failures occured, test not valid:").append(EOL);
+            Iterator it = getExceptionMap().entrySet().iterator();
+            while (it.hasNext())
+            {
+                Map.Entry entry = (Map.Entry) it.next();
+                buf.append("Failure cause by ").append(entry.getKey());
+                if(entry.getValue() != null)
+                {
+                    Throwable ex = ExceptionUtils.getRootCause((Exception) entry.getValue());
+                    if(ex == null) ex = (Exception) entry.getValue();
+                    buf.append(EOL).append("Exception was: ").append(EOL).append(ExceptionUtils.getStackTrace(ex));
+                }
+                buf.append(EOL);
+            }
+            printer().println(buf.toString());
+        }
+
         for (int i = 0; i < columnNumbers; i++)
         {
-            buf.append(getFilledUpToLength("", columnLength, "="));
+            buf.append(alignToLength(columnLength, "="));
         }
-//        if(failures.size() > 0)
-//        {
-//            buf.append(EOL + "Failures detected:" + EOL);
-//            for(int i = 0; i < failures.size(); i++)
-//            {
-//                PerfResult perfResult = (PerfResult) failures.get(i);
-//                buf.append("name=" + perfResult.getTestName() + ", isValid=" +perfResult.isValid() + EOL);
-//            }
-//        }
         return buf.toString();
     }
 
-    private String getFilledUpToLength(String target, int length, String fillCharacter)
+//    private String alignRight(String target, int length)
+//    {
+//        return alignToLength(target, length, " ", true);
+//    }
+
+    private String alignLeft(String target, int length)
+    {
+        return alignToLength(target, length, " ", false);
+    }
+
+    private String alignToLength(int length, String fillCharacter)
+    {
+        return alignToLength("", length, fillCharacter, false);
+    }
+
+    private String alignToLength(String target, int length, String fillCharacter, boolean right)
     {
         if (target.length() > length) return target;
 
@@ -398,17 +544,19 @@
         {
             blanks += fillCharacter;
         }
-        return blanks + target;
+        return right ? blanks + target : target + blanks;
     }
 
     /**
-     * resultArr[0] startTime/test length
-     * resultArr[1] inserting times
-     * resultArr[2] fetching times
-     * resultArr[3] updating times
-     * resultArr[4] deleting times
+     * testTimes[0] startTime/test length
+     * testTimes[1] inserting times
+     * testTimes[2] fetching times
+     * testTimes[3] fetching repeat times
+     * testTimes[4] get by Identity times
+     * testTimes[5] updating times
+     * testTimes[6] deleting times
      */
-    public void addPeriodResult(String testName, long[] resultArr)
+    public synchronized void addPeriodResult(String testName, long[] resultArr, boolean isValid)
     {
         PerfResult result = (PerfResult) resultMap.get(testName);
         if (result == null)
@@ -422,29 +570,45 @@
             resultMap.put(testName, result);
 
         }
-        result.addTestPeriod(resultArr[0]);
-        result.addInsertPeriod(resultArr[1]);
-        result.addFetchPeriod(resultArr[2]);
-        result.addUpdatePeriod(resultArr[3]);
-        result.addDeletePeriod(resultArr[4]);
+        result.setValid(isValid);
+        result.addTestPeriod(resultArr[TIME_TOTAL]);
+        result.addInsertPeriod(resultArr[TIME_INSERT]);
+        result.addFetchPeriod(resultArr[TIME_FETCH]);
+        result.addFetchSecondPeriod(resultArr[TIME_FETCH_2]);
+        result.addByIdentityPeriod(resultArr[TIME_BY_IDENTITY]);
+        result.addUpdatePeriod(resultArr[TIME_UPDATE]);
+        result.addDeletePeriod(resultArr[TIME_DELETE]);
 
-        StringBuffer buf = new StringBuffer();
-        buf.append("Test '").append(result.getTestName()).append("' [ms]")
-                .append(": testPeriod=").append(resultArr[0])
-                .append(" insert=").append(resultArr[1]/getConcurrentThreads())
-                .append(" read=").append(resultArr[2]/getConcurrentThreads())
-                .append(" update=").append(resultArr[3]/getConcurrentThreads())
-                .append(" delete=").append(resultArr[4]/getConcurrentThreads());
-        System.out.println(buf.toString());
+        if(logAll)
+        {
+            StringBuffer buf = new StringBuffer();
+            buf.append(" Test '").append(result.getTestName()).append("' [ms]")
+                .append(": testPeriod=").append(resultArr[TIME_TOTAL]/getConcurrentThreads())
+                .append(" insert=").append(resultArr[TIME_INSERT]/getConcurrentThreads())
+                .append(" read=").append(resultArr[TIME_FETCH]/getConcurrentThreads())
+                .append(" read2=").append(resultArr[TIME_FETCH_2]/getConcurrentThreads())
+                .append(" byIdentity=").append(resultArr[TIME_BY_IDENTITY]/getConcurrentThreads())
+                .append(" update=").append(resultArr[TIME_UPDATE]/getConcurrentThreads())
+                .append(" delete=").append(resultArr[TIME_DELETE]/getConcurrentThreads());
+            printer().print(buf.toString());
+        }
+        else
+        {
+            printer().print(".");
+        }
     }
 
-    public void addConsistentResult(String testName, int objectsBefore, int objectsAfter)
+    public synchronized void addConsistentResult(String testName, int objectsBefore, int objectsAfter)
     {
         ConsistentEntry ce = new ConsistentEntry(objectsBefore, objectsAfter);
         PerfResult result = (PerfResult) resultMap.get(testName);
         if(objectsBefore != objectsAfter)
         {
-            try{throw new Exception("Wrong object count, before=" + objectsBefore + ", after=" + objectsAfter);}catch(Exception e)
+            try
+            {
+                throw new Exception("Wrong object count, before=" + objectsBefore + ", after=" + objectsAfter);
+            }
+            catch(Exception e)
             {
                 registerException(testName, e);
             }
@@ -487,6 +651,25 @@
         return testLoops;
     }
 
+
+    Object newInstance(Class target, Class argType, Object argInstance)
+    {
+        try
+        {
+            Class[] types = new Class[]{argType};
+            Object[] args = new Object[]{argInstance};
+            Constructor con = target.getConstructor(types);
+            return con.newInstance(args);
+        }
+        catch(Exception e)
+        {
+            e.printStackTrace();
+            throw new RuntimeException("Can't create instance for class "
+                    + target + "using constructor argument " + argType + ", message is " + e.getMessage());
+        }
+    }
+
+
     //================================================================
     // inner class
     //================================================================
@@ -501,9 +684,17 @@
         private int iterationsPerThread;
 
         private long insertPeriod;
+        private long insertMinimun;
         private long fetchPeriod;
+        private long fetchMinimun;
+        private long fetchSecondPeriod;
+        private long fetchSecondMinimun;
+        private long byIdentityPeriod;
+        private long byIdentityMinimun;
         private long updatePeriod;
+        private long updateMinimun;
         private long deletePeriod;
+        private long deleteMinimun;
 
         private boolean valid;
 
@@ -518,17 +709,19 @@
         public String toString()
         {
             StringBuffer buf = new StringBuffer();
-            buf.append(EOL + "[" + this.getClass().getName());
-            buf.append(EOL + "testName=" + testName);
-            buf.append(EOL + "testPeriod=" + testPeriod);
-            buf.append(EOL + "testLoops=" + testLoops);
-            buf.append(EOL + "numberOfThreads=" + numberOfThreads);
-            buf.append(EOL + "iterationsPerThread=" + iterationsPerThread);
-            buf.append(EOL + "isValid=" + isValid());
-            buf.append(EOL + "insertPeriod=" + getInsertPeriod());
-            buf.append(EOL + "fetchPeriod=" + getFetchPeriod());
-            buf.append(EOL + "deletePeriod=" + getDeletePeriod());
-            buf.append(EOL + "consistentList: " + consistentList);
+            buf.append(EOL).append("[").append(this.getClass().getName());
+            buf.append(EOL).append("testName=").append(testName);
+            buf.append(EOL).append("testPeriod=").append(testPeriod);
+            buf.append(EOL).append("testLoops=").append(testLoops);
+            buf.append(EOL).append("numberOfThreads=").append(numberOfThreads);
+            buf.append(EOL).append("iterationsPerThread=").append(iterationsPerThread);
+            buf.append(EOL).append("isValid=").append(isValid());
+            buf.append(EOL).append("insertPeriod=").append(getInsertPeriod());
+            buf.append(EOL).append("fetchPeriod=").append(getFetchPeriod());
+            buf.append(EOL).append("fetchSecondPeriod=").append(getFetchSecondPeriod());
+            buf.append(EOL).append("byIdentity=").append(getByIdentityPeriod());
+            buf.append(EOL).append("deletePeriod=").append(getDeletePeriod());
+            buf.append(EOL).append("consistentList: ").append(consistentList);
             buf.append("]");
             return buf.toString();
         }
@@ -571,10 +764,10 @@
 
         public long getTestPeriod()
         {
-            return testPeriod / getTestLoops();
+            return testPeriod;
         }
 
-        public void addTestPeriod(long aTestPeriod)
+        public synchronized void addTestPeriod(long aTestPeriod)
         {
             this.testPeriod += aTestPeriod;
         }
@@ -611,7 +804,8 @@
 
         public long getTotalTime()
         {
-            return ((insertPeriod + fetchPeriod + updatePeriod + deletePeriod) / getTestLoops()) / getNumberOfThreads();
+            long result = ((insertPeriod + fetchPeriod + fetchSecondPeriod + byIdentityPeriod + updatePeriod + deletePeriod) / getTestLoops()) / getNumberOfThreads();
+            return result > 0 ? result : 1;
         }
 
         public long getInsertPeriod()
@@ -619,7 +813,7 @@
             return (insertPeriod / getTestLoops()) / getNumberOfThreads();
         }
 
-        public void addInsertPeriod(long anInsertPeriod)
+        public synchronized void addInsertPeriod(long anInsertPeriod)
         {
             this.insertPeriod += anInsertPeriod;
         }
@@ -629,17 +823,37 @@
             return (fetchPeriod / getTestLoops()) / getNumberOfThreads();
         }
 
-        public void addFetchPeriod(long aFetchPeriod)
+        public synchronized void addFetchPeriod(long aFetchPeriod)
         {
             this.fetchPeriod += aFetchPeriod;
         }
 
+        public long getFetchSecondPeriod()
+        {
+            return (fetchSecondPeriod / getTestLoops()) / getNumberOfThreads();
+        }
+
+        public synchronized void addFetchSecondPeriod(long secondPeriod)
+        {
+            this.fetchSecondPeriod += secondPeriod;
+        }
+
+        public long getByIdentityPeriod()
+        {
+            return (byIdentityPeriod / getTestLoops()) / getNumberOfThreads();
+        }
+
+        public synchronized void addByIdentityPeriod(long byIdentityPeriod)
+        {
+            this.byIdentityPeriod += byIdentityPeriod;
+        }
+
         public long getUpdatePeriod()
         {
             return (updatePeriod / getTestLoops()) / getNumberOfThreads();
         }
 
-        public void addUpdatePeriod(long aUpdatePeriod)
+        public synchronized void addUpdatePeriod(long aUpdatePeriod)
         {
             this.updatePeriod += aUpdatePeriod;
         }
@@ -649,10 +863,119 @@
             return (deletePeriod / getTestLoops()) / getNumberOfThreads();
         }
 
-        public void addDeletePeriod(long aDeletePeriod)
+        public synchronized void addDeletePeriod(long aDeletePeriod)
         {
             this.deletePeriod += aDeletePeriod;
         }
+
+
+
+        public void setInsertMinimun(long insertMinimun)
+        {
+            this.insertMinimun = insertMinimun > 1 ? insertMinimun : 1;
+        }
+
+        public void setFetchMinimun(long fetchMinimun)
+        {
+            this.fetchMinimun = fetchMinimun > 1 ? fetchMinimun : 1;
+        }
+
+        public void setFetchSecondMinimun(long fetchSecondMinimun)
+        {
+            this.fetchSecondMinimun = fetchSecondMinimun > 1 ? fetchSecondMinimun : 1;
+        }
+
+        public void setByIdentityMinimun(long byIdentityMinimun)
+        {
+            this.byIdentityMinimun = byIdentityMinimun > 1 ? byIdentityMinimun : 1;
+        }
+
+        public void setUpdateMinimun(long updateMinimun)
+        {
+            this.updateMinimun = updateMinimun > 1 ? updateMinimun : 1;
+        }
+
+        public void setDeleteMinimun(long deleteMinimun)
+        {
+            this.deleteMinimun = deleteMinimun > 1 ? deleteMinimun : 1;
+        }
+
+
+
+        public String getInsertResult()
+        {
+            long result = getInsertPeriod();
+            return "" + result;
+        }
+
+        public String getFetchResult()
+        {
+            long result = getFetchPeriod();
+            return "" + result;
+        }
+
+        public String getFetchSecondResult()
+        {
+            long result = getFetchSecondPeriod();
+            return "" + result;
+        }
+
+        public String getByIdentityResult()
+        {
+            long result = getByIdentityPeriod();
+            return "" + result;
+        }
+
+        public String getUpdateResult()
+        {
+            long result = getUpdatePeriod();
+            return "" + result;
+        }
+
+        public String getDeleteResult()
+        {
+            long result = getDeletePeriod();
+            return "" + result;
+        }
+
+
+
+
+        public String getInsertResultPercent()
+        {
+            long result = getInsertPeriod();
+            return "(" + (int) ((result * 100)/insertMinimun) + "%)";
+        }
+
+        public String getFetchResultPercent()
+        {
+            long result = getFetchPeriod();
+            return "(" + (int) ((result * 100)/fetchMinimun) + "%)";
+        }
+
+        public String getFetchSecondResultPercent()
+        {
+            long result = getFetchSecondPeriod();
+            return "(" + (int) ((result * 100)/fetchSecondMinimun) + "%)";
+        }
+
+        public String getByIdentityResultPercent()
+        {
+            long result = getByIdentityPeriod();
+            return  "(" + (int) ((result * 100)/byIdentityMinimun) + "%)";
+        }
+
+        public String getUpdateResultPercent()
+        {
+            long result = getUpdatePeriod();
+            return "(" + (int) ((result * 100)/updateMinimun) + "%)";
+        }
+
+        public String getDeleteResultPercent()
+        {
+            long result = getDeletePeriod();
+            return "(" + (int) ((result * 100)/deleteMinimun) + "%)";
+        }
     }
 
     //================================================================
@@ -687,11 +1010,56 @@
         public String toString()
         {
             StringBuffer buf = new StringBuffer();
-            buf.append("[" + this.getClass().getName()).
-                    append(": objectsBefore=" + getObjectsBefore()).
-                    append(" objectsAfter=" + objectsAfter).
-                    append(" isPassed=" + isPassed());
+            buf.append("[").append(this.getClass().getName())
+                    .append(": objectsBefore=")
+                    .append(getObjectsBefore())
+                    .append(" objectsAfter=")
+                    .append(objectsAfter)
+                    .append(" isPassed=")
+                    .append(isPassed());
             return buf.toString();
+        }
+    }
+
+    static class Printer
+    {
+        PrintStream console;
+        PrintStream file;
+
+        public Printer()
+        {
+            console = System.out;
+            try
+            {
+                file = new PrintStream(new FileOutputStream(new File("OJB-Performance-Result.txt")));
+            }
+            catch(FileNotFoundException e)
+            {
+                e.printStackTrace();
+            }
+        }
+
+        void print(String str)
+        {
+            console.print(str);
+            if(file != null) file.print(str);
+        }
+
+        void print(String str, boolean consoleOnly)
+        {
+            console.print(str);
+            if(file != null && !consoleOnly) file.print(str);
+        }
+
+        void println(String str)
+        {
+            console.println(str);
+            if(file != null) file.println(str);
+        }
+
+        void println()
+        {
+            print("");
         }
     }
 }

Modified: db/ojb/trunk/src/test/org/apache/ojb/performance/PerfTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/performance/PerfTest.java?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/performance/PerfTest.java (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/performance/PerfTest.java Sat Jul 15 06:55:51 2006
@@ -1,6 +1,6 @@
 package org.apache.ojb.performance;
 
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,38 +15,22 @@
  * limitations under the License.
  */
 
+import java.util.Collection;
+import java.util.Iterator;
+
 /**
- * Derivate this class to implement a test instance for the performance test.
+ * Derivate this class to implement a test client for the performance test.
  *
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>.
  * @version $Id$
  */
-public abstract class PerfTest
+public abstract class PerfTest implements Runnable
 {
-    private final String PREFIX_LOG = "[" + this.getClass().getName() + "] ";
-
-    /**
-     * testTimes[0] startTime/test length
-     * testTimes[1] inserting times
-     * testTimes[2] fetching times
-     * testTimes[3] updating times
-     * testTimes[4] deleting times
-     */
-    private long[] testTimes;
-    private ThreadGroup threadGroup;
-    private PerfMain perfMain;
-    private long perfTestId;
-    private boolean checked;
-    /**
-     * The threads that are executing.
-     */
-    private Thread threads[] = null;
+    private String PREFIX_LOG = "[" + this.getClass().getName() + "] ";
+    private PerfRunner test;
+    private String objectName;
 
     public PerfTest()
     {
-        threadGroup = new ThreadGroup(testName() + "_Group");
-        perfTestId = System.currentTimeMillis();
-        checked = false;
     }
 
     /**
@@ -55,11 +39,6 @@
     public abstract String testName();
 
     /**
-     * Returns a new instance of a {@link PerfHandle} implementation.
-     */
-    public abstract PerfHandle newPerfHandle(PerfTest test);
-
-    /**
      * Returns the count of all found {@link PerfArticle}
      * in database.
      * This method is not involved in the performance test
@@ -68,139 +47,325 @@
      */
     public abstract int articleCount();
 
+    /**
+     * Init the test. do setup stuff here
+     */
+    public abstract void init() throws Exception;
+
+    /**
+     * Do clean up.
+     */
+    public abstract void tearDown() throws Exception;
+
+    /**
+     * Store the given articles to database. Do optimize
+     * performance.
+     */
+    public abstract void insertNewArticles(PerfArticle[] arr) throws Exception;
+
+    /**
+     * Store the given articles to database. Implement a really
+     * resource stressing way.
+     */
+    public abstract void insertNewArticlesStress(PerfArticle[] arr) throws Exception;
+
+    /**
+     * Read all stored articles from the database and return the
+     * result as collection of <code>PerfArticles</code>.
+     * Do optimize performance.
+     * @param articleName article name used for all {@link PerfArticle} created
+     * by this instance/thread. Use this name in your query to match all belonging articles
+     */
+    public abstract Collection readArticlesByCursor(String articleName) throws Exception;
+
+    /**
+     * Read all stored articles from the database and return the
+     * result as collection of <code>PerfArticles</code>.
+     * Do optimize performance.
+     * @param articleId the primary key of a {@link PerfArticle} instance
+     * @return The matching {@link PerfArticle} instance or <em>null</em> if not found.
+     */
+    public abstract PerfArticle getArticleByIdentity(Long articleId) throws Exception;
 
-    private void checkApi() throws Exception
+    /**
+     * Delete all given article from the database.
+     * Do optimize performance.
+     */
+    public abstract void deleteArticles(PerfArticle[] arr) throws Exception;
+
+    /**
+     * Delete all given article from the database in a really resource
+     * sressing way.
+     */
+    public abstract void deleteArticlesStress(PerfArticle[] arr) throws Exception;
+
+    /**
+     * Update the given articles. Do optimize
+     * performance.
+     */
+    public abstract void updateArticles(PerfArticle[] arr) throws Exception;
+
+    /**
+     * Update the given articles. Implement a really
+     * resource stressing way.
+     */
+    public abstract void updateArticlesStress(PerfArticle[] arr) throws Exception;
+
+    /**
+     * Called to get a new instance class of the {@link org.apache.ojb.performance.PerfArticle}
+     * interface, override this method if you need your own implementation
+     * (with default constructor) of the PerfArticle-Interface.
+     * <br/>
+     * By default this method returns a new instance of the
+     * {@link org.apache.ojb.performance.PerfArticleImpl} class.
+     *
+     */
+    public PerfArticle newPerfArticle()
     {
-        String name = testName() + "_Pre_Test_Object";
-        PerfHandle handle = newPerfHandle(this);
-        PerfArticle article = handle.getPreparedPerfArticle(name);
-        PerfArticle[] arr = new PerfArticle[]{article};
-        handle.init();
-        handle.insertNewArticles(arr);
-        handle.readArticlesByCursor(name);
-        handle.updateArticles(arr);
-        handle.deleteArticles(arr);
-        handle.tearDown();
-        checked = true;
+        return new PerfArticleImpl();
     }
 
     /**
-     * Interrupt the running threads.
+     * The returned name was used as 'articleName' for all
+     * created <code>PerfArticles</code> for this thread.
+     * This allows an easy build of the query statement
+     * to match the created {@link PerfArticle} for this
+     * instance/thread.
      */
-    protected void interruptThreads()
+    public String getTestObjectName()
     {
-        if (threads != null)
-        {
-            for (int i = 0; i < threads.length; i++)
-            {
-                threads[i].interrupt();
-            }
-        }
-        System.err.println("## Test failed! ##");
-        System.err.println("## Test failed! ##");
+        if (objectName == null)
+            objectName = testName() + "_" +
+                    Thread.currentThread().toString() + "_" + test.getPerfTestId();
+        return objectName;
     }
 
     /**
-     * Run the threads.
+     * Factory method that creates an {@link org.apache.ojb.performance.PerfArticle}
+     * using the {@link org.apache.ojb.performance.PerfArticleImpl} class,
+     * override this method if you need your own implementation
+     * of the PerfArticle-Interface.
+     *
+     * @param articleName set the 'articleName'
+     * @return the created PerfArticle object
      */
-    protected void runTestHandles(final PerfHandle[] runnables)
+    public PerfArticle getPreparedPerfArticle(String articleName)
     {
-        if (runnables == null)
-        {
-            throw new IllegalArgumentException("runnables is null");
-        }
-        threads = new Thread[runnables.length];
-        for (int i = 0; i < threads.length; i++)
-        {
-            threads[i] = new Thread(threadGroup, runnables[i]);
-        }
-        for (int i = 0; i < threads.length; i++)
+        PerfArticle a = newPerfArticle();
+        a.setArticleName(articleName);
+        a.setMinimumStock(100);
+        a.setPrice(0.45);
+        a.setProductGroupId(1);
+        a.setStock(234);
+        a.setSupplierId(4);
+        a.setUnit("bottle");
+        return a;
+    }
+
+    void setPerfRunner(PerfRunner test)
+    {
+        this.test = test;
+    }
+
+    /**
+     * Runnable implementation method.
+     */
+    public void run()
+    {
+        PerfArticle[] m_arr = new PerfArticle[PerfMain.getIterationsPerThread()];
+        for (int i = 0; i < PerfMain.getIterationsPerThread(); i++)
         {
-            threads[i].start();
+            m_arr[i] = getPreparedPerfArticle(getTestObjectName());
         }
+
         try
         {
-            for (int i = 0; i < threads.length; i++)
+            long totalTime = 0;
+            long period;
+            init();
+
+            // insert objects
+            if (PerfMain.isUseStressMode())
             {
-                threads[i].join();
+                period = System.currentTimeMillis();
+                insertNewArticlesStress(m_arr);
+                period = System.currentTimeMillis() - period;
+                test.addTime(PerfMain.TIME_INSERT, period);
+                totalTime+=period;
             }
-        }
-        catch (InterruptedException ignore)
-        {
-            System.out.println(PREFIX_LOG + "Thread join interrupted.");
-        }
+            else
+            {
+                period = System.currentTimeMillis();
+                insertNewArticles(m_arr);
+                period = System.currentTimeMillis() - period;
+                test.addTime(PerfMain.TIME_INSERT, period);
+                totalTime+=period;
+                // System.out.println("I=" + period);
+            }
+            checkInsertResult(m_arr);
 
-        // should always be skipped, because we use 'thread.join'
-        while(threadGroup.activeCount() > 0)
-        {
-            System.out.println("## active threads: " + threadGroup.activeCount());
-        }
+            // read objects
+            period = System.currentTimeMillis();
+            Collection col = readArticlesByCursor(objectName);
+            try
+            {
+                checkQueryResult(col, m_arr);
+            }
+            catch (Exception e)
+            {
+                test.registerException(PREFIX_LOG
+                        + "(Something wrong with query result or with object insert operation) ", e);
+            }
+            period = System.currentTimeMillis() - period;
+            test.addTime(PerfMain.TIME_FETCH, period);
+            totalTime+=period;
+            // System.out.println("R=" + period);
 
-        threads = null;
-    }
 
-    public void performTest()
-    {
-        try
-        {
-            if (!checked)
+            // read objects 2
+            period = System.currentTimeMillis();
+            col = readArticlesByCursor(objectName);
+            try
             {
-                checkApi();
-                System.out.println("# Start PerfTest: " + testName() + " #");
+                checkQueryResult(col, m_arr);
             }
+            catch (Exception e)
+            {
+                test.registerException(PREFIX_LOG
+                        + "(Something wrong with query result or with object insert operation) ", e);
+            }
+            period = System.currentTimeMillis() - period;
+            test.addTime(PerfMain.TIME_FETCH_2, period);
+            totalTime+=period;
+            // System.out.println("R2=" + period);
 
-            int objectCount;
-            int objectCountAfter;
 
-            testTimes = new long[5];
+            // get by Identity
+            period = System.currentTimeMillis();
+            PerfArticle result;
+            for(int i = 0; i < m_arr.length; i++)
+            {
+                if(i%4==0)
+                {
+                    PerfArticle perfArticle = m_arr[i];
+                    result = getArticleByIdentity(perfArticle.getArticleId());
+                    if(result == null)
+                    {
+                        test.registerException("Unexpected result: Get by Identity is 'null' for "
+                                + PerfArticle.class.getName() + " with primary key "
+                                + perfArticle.getArticleId(), null);
+                    }
+                }
+            }
+            period = (System.currentTimeMillis() - period);
+            test.addTime(PerfMain.TIME_BY_IDENTITY, period);
+            totalTime+=period;
+            // System.out.println("B=" + period);
 
-            objectCount = articleCount();
 
-            // now we start the test threads
-            PerfHandle[] perfHandles = new PerfHandle[PerfMain.getConcurrentThreads()];
-            for (int i = 0; i < PerfMain.getConcurrentThreads(); i++)
+            // update objects
+            modifyPerfArticle(m_arr);
+            if (PerfMain.isUseStressMode())
+            {
+                period = System.currentTimeMillis();
+                updateArticlesStress(m_arr);
+                period = System.currentTimeMillis() - period;
+                test.addTime(PerfMain.TIME_UPDATE, period);
+                totalTime+=period;
+            }
+            else
             {
-                perfHandles[i] = newPerfHandle(this);
+                period = System.currentTimeMillis();
+                updateArticles(m_arr);
+                period = System.currentTimeMillis() - period;
+                test.addTime(PerfMain.TIME_UPDATE, period);
+                totalTime+=period;
+                // System.out.println("U=" + period);
             }
-            testTimes[0] = System.currentTimeMillis();
-            runTestHandles(perfHandles);
-            testTimes[0] = System.currentTimeMillis() - testTimes[0];
-            // end of test threads
 
-            objectCountAfter = articleCount();
-            perfMain.addPeriodResult(testName(), testTimes);
-            perfMain.addConsistentResult(testName(), objectCount, objectCountAfter);
+            // delete objects
+            if (PerfMain.isUseStressMode())
+            {
+                period = System.currentTimeMillis();
+                deleteArticlesStress(m_arr);
+                period = System.currentTimeMillis() - period;
+                test.addTime(PerfMain.TIME_DELETE, period);
+                totalTime+=period;
+            }
+            else
+            {
+                period = System.currentTimeMillis();
+                deleteArticles(m_arr);
+                period = System.currentTimeMillis() - period;
+                test.addTime(PerfMain.TIME_DELETE, period);
+                totalTime+=period;
+                // System.out.println("D=" + period);
+            }
+            test.addTime(PerfMain.TIME_TOTAL, totalTime);
+            tearDown();
         }
         catch (Exception e)
         {
             e.printStackTrace();
-            perfMain.registerException(PREFIX_LOG, e);
+            test.registerException(PREFIX_LOG + "(Unexpected behaviour) ", e);
+            test.interruptThreads();
         }
     }
 
-    public void registerException(String causer, Exception e)
-    {
-        perfMain.registerException(causer, e);
-    }
-
-    public synchronized void addTime(int position, long time)
-    {
-        if(position < 1) throw new RuntimeException("Illegal position set");
-        testTimes[position] += time;
-    }
-
-    public void registerPerfMain(PerfMain aPerfMain)
+    private void modifyPerfArticle(PerfArticle[] m_arr)
     {
-        this.perfMain = aPerfMain;
+        PerfArticle article;
+        String prefix = "updated_";
+        for (int i = 0; i < m_arr.length; i++)
+        {
+            article = m_arr[i];
+            article.setArticleName(prefix + article.getArticleName());
+        }
     }
 
-    public ThreadGroup getThreadGroup()
+    private void checkQueryResult(Collection col, PerfArticle[] m_arr) throws Exception
     {
-        return threadGroup;
+        if(col.size() > 0)
+        {
+            Iterator it = col.iterator();
+            while(it.hasNext())
+            {
+                Object obj = it.next();
+                if(!(obj instanceof PerfArticle))
+                {
+                    throw new Exception("Wrong object type found. Expected instance of"+
+                        PerfArticle.class.getName() + ", found " + obj.getClass().getName());
+                }
+                else
+                {
+                    PerfArticle article = (PerfArticle) obj;
+                    article.getArticleId();
+                    article.getArticleName();
+                    article.getMinimumStock();
+                    article.getPrice();
+                    article.getProductGroupId();
+                    article.getStock();
+                    article.getSupplierId();
+                    article.getUnit();
+                }
+            }
+        }
+        if (col.size() != m_arr.length)
+        {
+            throw new Exception("Read objects: Wrong number of objects found. Expected " +
+                    (m_arr.length) + ", found " + col.size());
+        }
     }
 
-    public long getPerfTestId()
+    private void checkInsertResult(PerfArticle[] m_arr) throws Exception
     {
-        return perfTestId;
+        for(int i = 0; i < m_arr.length; i++)
+        {
+            PerfArticle perfArticle = m_arr[i];
+            if(perfArticle.getArticleId() == null)
+            {
+                throw new Exception("Insert objects: Object with 'null' PK found");
+            }
+        }
     }
 }

Modified: db/ojb/trunk/src/test/org/apache/ojb/quick-db/OJB.script
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/quick-db/OJB.script?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
Binary files - no diff available.

Modified: db/ojb/trunk/src/test/org/apache/ojb/repository.dtd
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/repository.dtd?rev=422216&r1=422215&r2=422216&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/repository.dtd (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/repository.dtd Sat Jul 15 06:55:51 2006
@@ -18,7 +18,6 @@
 <!--
   ObJectRelationalBridge - Bridging Java objects and relational dabatases
   This DTD describes the grammar of the Descriptor repository
-  Author: Thomas Mahler, (c) 2000-2005
   -->
 
 <!--
@@ -28,8 +27,8 @@
 
   The attribute element allows to add custom attributes.
 
-  The jdbc-connection-descriptor element specifies the default and optional
-  jdbc connections for the repository.
+  The jdbc-connection-descriptor element specifies the default jdbc
+  connection for the repository.
 
   class-descriptor elements specify o/r mapping information for
   persistent classes.
@@ -50,7 +49,7 @@
 <!ATTLIST descriptor-repository
   version (1.1) #REQUIRED
   isolation-level (read-uncommitted | read-committed | repeatable-read |
-                   serializable | optimistic | no-lock) "read-uncommitted"
+	                 serializable | optimistic | none) "read-uncommitted"
   proxy-prefetching-limit CDATA "50"
 >
 
@@ -81,12 +80,12 @@
 
 <!--
   The jcdAlias attribute is a shortcut name for the defined connection
-  descriptor. OJB uses jcdAlias as key for the defined connections.
+    descriptor. OJB use jcdAlias as key for the defined connections.
   
   The default-connection attribute used to define if this connection
   should used as default connection with OJB. You could define only
   one connection as default connection. It is also possible to set
-  the default connection at runtime using the
+    the default connection at runtime using
   PersistenceBrokerFactory#setDefaultKey(...) method.
   If set to 'true' you can use on PB-api a shortcut-method of the
   PersistenceBrokerFactory to lookup a PersistenceBroker instances.
@@ -106,22 +105,22 @@
   OJB switch off batch modus, thus you have to do '...setBatchMode(true)' on each
   obtained PB instance.
   
-  The useAutoCommit attribute allows to set how OJB uses
+    The useAutoCommit attribute allow to set how OJB uses
   the autoCommit state of the used connections. The default mode
-  is 1.
-  0 - OJB ignores the autoCommit setting of the connection and does not
-      try to change it. This mode could be helpful if the
-      connection doesn't let you set the autoCommit state
-      (e.g. using datasources from an application server).
-  1 - [default mode] set the connection's autoCommit state temporary to 'false'
-      if needed (when using transactions) and restore the old state after use. In
-      OJB versions before 1.0.4 the autoCommit state was explicit set 'true'
-      when a connection was created, now OJB expect that this was done by
-      the jdbc-driver configuration. To enable the old behavior set the custom
-      attribute 'initializationCheck' to 'true'.
-  2 - this setting sets autoCommit explicit 'false' when a connection is created.
+    was 1.
+    0 - OJB ignores the autoCommit setting of the connection and do not
+        try to change it. This mode could be helpfully if the
+        connection don't let you set the autoCommit state
+        (e.g. using datasources from application server).
+    1 - [default mode] set the connection's autoCommit state temporary to 'false' if needed
+        (when using transaction) and restore the old state after use. In
+        versions before OJB 1.0.4 the autoCommit state was explicit set 'true'
+        when connection was created, now OJB expect that this was done by
+        the jdbc-driver configuration. To enable old behavior set a custom attribute
+        'initializationCheck' to 'true'.
+    2 - this setting set autoCommit explicit 'false' when connection was created.
   
-  If the ignoreAutoCommitExceptions attribute is set to 'true', all
+    If the ignoreAutoCommitExceptions attribute is set 'true', all
   exceptions caused by setting autocommit state, will be ignored.
   Default mode 'false'.
 
@@ -134,7 +133,7 @@
   for obtaining a jdbc connections.
   If users don't want to keep this information the
   repository.xml file, they could pass user/password
-  using PBKey.java while obtaining a PersistenceBroker instance.
+    using PBKey.java to obtain a PersistenceBroker
   -->
 <!ATTLIST jdbc-connection-descriptor
   jcd-alias CDATA #REQUIRED
@@ -311,8 +310,9 @@
   class.
 
   The isolation-level attribute defines the locking isolation level of the
-  specified class (used by OJB's pessimistic locking api). Default is "global"
-  to signal the use of the isolation-level defined on "descriptor-repository" level.
+  specified class (used by OJB's pessimistic locking api). Use attribute "global"
+  or "empty string ("or skip this attribute) to signal the use of the isolation-level
+  defined on "descriptor-repository" level.
   Note: This does NOT touch the jdbc-level of the connection.
 
   If the proxy attribute is set, proxies are used for all loading operations
@@ -339,7 +339,7 @@
   The extends attribute is deprecated and will be removed or reintroduced
   with changed funcitonality in future. DON'T USE IT!
 
-  The accept-locks attribute specifies whether implicit locking should
+  DEPRECATED. The accept-locks attribute specifies whether implicit locking should
   propagate to this class.  Currently relevant for the ODMG layer only.
 
   The optional initialization-method specifies a no-argument instance
@@ -367,7 +367,7 @@
 <!ATTLIST class-descriptor
   class ID #REQUIRED
   isolation-level (read-uncommitted | read-committed | repeatable-read |
-                   serializable | optimistic | no-lock | global) "global"
+                   serializable | optimistic | none) #IMPLIED
   proxy CDATA #IMPLIED
   proxy-prefetching-limit CDATA #IMPLIED
   schema CDATA #IMPLIED
@@ -527,6 +527,12 @@
   A FieldConversion can be used to implement conversions between Java-
   attributes and database columns.
 
+	The null-check attribute contains a fully qualified class name.
+	This class must implement the interface
+	org.apache.ojb.broker.accesslayer.NullCheck.
+	A NullCheck can be used to implement special requirements for
+	the definitions of a field's 'null' value as Java representation.
+
   The length attribute can be used to specify a length setting, if
   required by the jdbc-type of the underlying database column.
 
@@ -554,7 +560,7 @@
              FLOAT | REAL | NUMERIC | DECIMAL | CHAR | VARCHAR |
              LONGVARCHAR | DATE | TIME | TIMESTAMP | BINARY |
              VARBINARY | LONGVARBINARY | CLOB | BLOB | STRUCT |
-             ARRAY | REF | BOOLEAN | DATALINK) #IMPLIED
+               ARRAY | REF | BOOLEAN | DATALINK | JAVA_OBJECT) #IMPLIED
   primarykey (true | false) "false"
   nullable (true | false) "true"
   indexed (true | false) "false"
@@ -564,6 +570,7 @@
   update-lock (true | false) "true"
   default-fetch (true | false) "false"
   conversion CDATA #IMPLIED
+	null-check CDATA #IMPLIED
   length CDATA #IMPLIED
   precision CDATA #IMPLIED
   scale CDATA #IMPLIED
@@ -721,7 +728,8 @@
   As this is an IDREF there must be a class-descriptor for this class
   in the repository too.
 
-  The orderby attribute may specify a field of the element class.
+	DEPRECATED, please use the 'orderby'-element. The orderby attribute may
+	specify a field of the element class.
   The Collection or Array will be sorted according to the specified attribute.
   The sort attribute may be used to specify ascending or descending order for
   this operation.
@@ -749,12 +757,12 @@
   The auto-update attribute specifies whether OJB automatically stores
   the referenced objects on storing the persistent object or not or only link.
   This attribute must be set to 'false' if using the OTM or JDO layer.
-  For ODMG it must be 'none' (since OJB 1.0.2). More info see OJB documentation.
+    Allowed ODMG settings please see OJB documentation.
 
   The auto-delete attribute specifies whether OJB automatically deletes
   the referenced objects on deleting the persistent object or not.
   This attribute must be set to 'false' if using the OTM or JDO layer.
-  For ODMG it must be 'none' (since OJB 1.0.2). More info see OJB documentation.
+    Allowed ODMG settings please see OJB documentation.
 
   The otm-dependent attribute specifies whether the OTM layer automatically
   creates collection elements that were included into the collectionelements



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Mime
View raw message