adds a cache benchmark
diff --git a/cache/.classpath b/cache/.classpath
new file mode 100644
index 0000000..aa09bbf
--- /dev/null
+++ b/cache/.classpath
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry excluding="META-INF/" kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="lib" path="persistence.jar"/>
+	<classpathentry kind="lib" path="eclipselink.jar" sourcepath="/org.eclipse.persistence.jpa"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.persistence.core"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.persistence.jpa"/>
+	<classpathentry kind="output" path="classes"/>
+</classpath>
diff --git a/cache/.project b/cache/.project
new file mode 100644
index 0000000..c7b003b
--- /dev/null
+++ b/cache/.project
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.persistence.example.jpa.cache</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+	</natures>
+</projectDescription>
diff --git a/cache/benchmark.zip b/cache/benchmark.zip
new file mode 100644
index 0000000..1e21071
--- /dev/null
+++ b/cache/benchmark.zip
Binary files differ
diff --git a/cache/build.xml b/cache/build.xml
new file mode 100644
index 0000000..fe96a74
--- /dev/null
+++ b/cache/build.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir="." default="build" name="org.eclipse.persistence.example.jpa.cache">
+    <property environment="env"/>
+    <!--property name="JDBC_LIB" value="./mysql-connector-java-5.0.7-bin.jar"/-->
+    <property name="JDBC_LIB" value="./ojdbc6.jar"/>
+    <property name="JPA_LIB" value="./persistence.jar"/>
+    <property name="ECLIPSELINK_LIB" value="./eclipselink.jar"/>
+    <property name="AGENT" value="-javaagent:${ECLIPSELINK_LIB}"/>
+    <property name="debuglevel" value="source,lines,vars"/>
+    <path id="base.classpath">
+        <pathelement location="classes"/>
+        <pathelement location="${JDBC_LIB}"/>
+        <pathelement location="${JPA_LIB}"/>
+    </path>
+    <path id="eclipselink.classpath">
+        <pathelement location="classes"/>
+        <pathelement location="${JDBC_LIB}"/>
+        <pathelement location="${JPA_LIB}"/>
+        <pathelement location="${ECLIPSELINK_LIB}"/>
+    </path>
+    <target name="init" depends="clean">
+        <mkdir dir="classes"/>
+    </target>
+    <target name="clean">
+        <delete dir="classes"/>
+    </target>
+
+    <target depends="init" name="build">
+        <echo message="${ant.project.name}: ${ant.file}"/>
+        <javac debug="true" debuglevel="${debuglevel}" destdir="classes">
+            <src path="src"/>
+            <exclude name="**/.svn/**"/>
+            <classpath refid="base.classpath"/>
+        </javac>
+        <copy todir="classes/META-INF">
+			<fileset dir="src/META-INF">
+				<include name="*.xml"/>
+			</fileset>
+		</copy>
+    </target>
+
+    <target name="find-test" depends="build">
+        <java classname="example.FindTest"
+                maxmemory="512m"
+                fork="true">
+            <jvmarg value="${AGENT}"/>
+            <classpath refid="eclipselink.classpath"/>
+        </java>
+    </target>
+
+    <target name="query-test" depends="build">
+        <java classname="example.QueryTest"
+                maxmemory="512m"
+                fork="true">
+            <jvmarg value="${AGENT}"/>
+            <classpath refid="eclipselink.classpath"/>
+        </java>
+    </target>
+    
+</project>
diff --git a/cache/src/META-INF/data-cache.xml b/cache/src/META-INF/data-cache.xml
new file mode 100644
index 0000000..9226e52
--- /dev/null
+++ b/cache/src/META-INF/data-cache.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.4"
+    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <entity class="model.Order">
+        <cache isolation="PROTECTED"/>
+        <attributes>
+            <many-to-one name="customer" fetch="LAZY">
+                <cascade>
+                    <cascade-persist/>
+                </cascade>
+                <noncacheable/>
+            </many-to-one>
+            <one-to-many name="orderLines" fetch="LAZY" mapped-by="order" orphan-removal="true">
+                <cascade>
+                    <cascade-all/>
+                </cascade>
+                <noncacheable/>
+            </one-to-many>
+        </attributes>
+    </entity>
+    <entity class="model.OrderLine">
+        <cache isolation="PROTECTED"/>
+    </entity>
+    <entity class="model.Customer">
+        <cache isolation="PROTECTED"/>
+    </entity>
+
+</entity-mappings>
diff --git a/cache/src/META-INF/in-memory.xml b/cache/src/META-INF/in-memory.xml
new file mode 100644
index 0000000..fa5bebb
--- /dev/null
+++ b/cache/src/META-INF/in-memory.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.4"
+    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <named-query name="findOrdersByCustomer">
+        <query>Select o from Order o where o.customer.id = :customerId</query>
+        <hint name="eclipselink.cache-usage" value="CheckCacheOnly"/>
+    </named-query>
+    <entity class="model.Order">
+        <cache type="FULL"/>
+    </entity>
+    <entity class="model.OrderLine">
+        <cache type="FULL"/>
+    </entity>
+    <entity class="model.Customer">
+        <cache type="FULL"/>
+    </entity>
+
+</entity-mappings>
diff --git a/cache/src/META-INF/persistence.xml b/cache/src/META-INF/persistence.xml
new file mode 100644
index 0000000..fceaccd
--- /dev/null
+++ b/cache/src/META-INF/persistence.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd"
+                version="1.0">
+    <persistence-unit name="database" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>        
+        <shared-cache-mode>NONE</shared-cache-mode>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <!--property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:derby:test;create=true" />
+            <property name="javax.persistence.jdbc.user" value="" />
+            <property name="javax.persistence.jdbc.password" value="" /-->
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="cache" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="protected" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <mapping-file>META-INF/protected.xml</mapping-file>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="data-cache" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <mapping-file>META-INF/data-cache.xml</mapping-file>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="read-only" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <mapping-file>META-INF/read-only.xml</mapping-file>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="read-only-protected" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <mapping-file>META-INF/read-only-protected.xml</mapping-file>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="query-cache" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <mapping-file>META-INF/query-cache.xml</mapping-file>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+    <persistence-unit name="in-memory" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+        <class>model.Order</class>
+        <class>model.OrderLine</class>
+        <class>model.Customer</class>
+        <mapping-file>META-INF/in-memory.xml</mapping-file>
+        <properties>
+            <!-- Change this to access your own database. -->
+            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+            <property name="javax.persistence.jdbc.user" value="scott" />
+            <property name="javax.persistence.jdbc.password" value="tiger" />
+            <property name="eclipselink.ddl-generation" value="create-tables" />
+            <property name="eclipselink.jdbc.cache-statements" value="true" />
+            <property name="eclipselink.logging.level" value="off" />
+            <property name="eclipselink.orm.validate.schema" value="true"/>
+            <!--property name="eclipselink.logging.level" value="FINE" /-->
+        </properties>
+    </persistence-unit>
+</persistence>
diff --git a/cache/src/META-INF/protected.xml b/cache/src/META-INF/protected.xml
new file mode 100644
index 0000000..e410d8a
--- /dev/null
+++ b/cache/src/META-INF/protected.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.4"
+    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <entity class="model.Order">
+        <cache isolation="PROTECTED"/>
+    </entity>
+    <entity class="model.OrderLine">
+        <cache isolation="PROTECTED"/>
+    </entity>
+    <entity class="model.Customer">
+        <cache isolation="PROTECTED"/>
+    </entity>
+
+</entity-mappings>
diff --git a/cache/src/META-INF/query-cache.xml b/cache/src/META-INF/query-cache.xml
new file mode 100644
index 0000000..a876a8f
--- /dev/null
+++ b/cache/src/META-INF/query-cache.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.4"
+    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <named-query name="findOrdersByCustomer">
+        <query>Select o from Order o where o.customer.id = :customerId</query>
+        <hint name="eclipselink.query-results-cache" value="true"/>
+    </named-query>
+
+</entity-mappings>
diff --git a/cache/src/META-INF/read-only-protected.xml b/cache/src/META-INF/read-only-protected.xml
new file mode 100644
index 0000000..ee4022a
--- /dev/null
+++ b/cache/src/META-INF/read-only-protected.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.4"
+    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <named-query name="findOrdersByCustomer">
+        <query>Select o from Order o where o.customer.id = :customerId</query>
+        <hint name="eclipselink.readonly" value="true"/>
+    </named-query>
+    <entity class="model.Order" read-only="true">
+        <cache isolation="PROTECTED"/>
+    </entity>
+    <entity class="model.OrderLine" read-only="true">
+        <cache isolation="PROTECTED"/>
+    </entity>
+    <entity class="model.Customer" read-only="true">
+        <cache isolation="PROTECTED"/>
+    </entity>
+
+</entity-mappings>
diff --git a/cache/src/META-INF/read-only.xml b/cache/src/META-INF/read-only.xml
new file mode 100644
index 0000000..49b40af
--- /dev/null
+++ b/cache/src/META-INF/read-only.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.4"
+    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <named-query name="findOrdersByCustomer">
+        <query>Select o from Order o where o.customer.id = :customerId</query>
+        <hint name="eclipselink.read-only" value="true"/>
+    </named-query>
+    <entity class="model.Order" read-only="true"/>
+    <entity class="model.OrderLine" read-only="true"/>
+    <entity class="model.Customer" read-only="true"/>
+
+</entity-mappings>
diff --git a/cache/src/example/FindTest.java b/cache/src/example/FindTest.java
new file mode 100644
index 0000000..08642e2
--- /dev/null
+++ b/cache/src/example/FindTest.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+import model.Order;
+
+/**
+ * Test the performance of reading an Order object model.
+ * @author James Sutherland
+ */
+public class FindTest extends Test {
+
+    public static void main(String[] args) throws Exception {
+        try {
+            FindTest test = new FindTest();
+            test.setup();
+            test.test();
+        } catch (Exception error) {
+            error.printStackTrace();
+        }
+        System.exit(0);
+    }
+
+    public void runTest(EntityManagerFactory factory) {
+        EntityManager em = factory.createEntityManager();
+        int index = this.random.nextInt(this.orderIds.length);
+        Order order = em.find(Order.class, this.orderIds[index]);
+        order.getCustomer().toString();
+        order.getOrderLines().size();
+        em.close();
+    }
+}
diff --git a/cache/src/example/PerformanceResult.java b/cache/src/example/PerformanceResult.java
new file mode 100644
index 0000000..f3a717e
--- /dev/null
+++ b/cache/src/example/PerformanceResult.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import java.io.StringWriter;
+
+/**
+ * Generic performance result.
+ */
+public class PerformanceResult {
+    String testName;
+    int runRepeats;
+    int runTime;
+    double average;
+    long min;
+    long max;
+    double standardDeviation;
+    
+    public String toString() {
+        StringWriter writer = new StringWriter();
+        writer.write(this.testName + " Results");
+        writer.write("\nRun repeats:" + this.runRepeats);
+        writer.write("\nRun time:" + this.runTime + "ms");
+        writer.write("\nAverage result:" + this.average);
+        writer.write("\nMax result:" + this.max);
+        writer.write("\nMin result:" + this.min);
+        writer.write("\n% standard deviation:" + this.standardDeviation);
+        return writer.toString();
+    }
+}
diff --git a/cache/src/example/PerformanceTest.java b/cache/src/example/PerformanceTest.java
new file mode 100644
index 0000000..efa91f9
--- /dev/null
+++ b/cache/src/example/PerformanceTest.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Generic performance test.
+ * This allows executing a timed run and measures and logs the performance.
+ * Logs the executions per run (minute), logs average and % stdev.
+ */
+public class PerformanceTest {
+
+    public static int REPEATS = 5;
+    public static int RUN_TIME = 10000; //10 seconds.
+
+    /**
+     * Measure the performance of the run.
+     * Repeat the run REPEATS (5) times,
+     * and measure the number of execution in RUN_TIME (60s).
+     */
+    public static PerformanceResult executeRun(String name, Runnable runnable) {
+        System.out.println("Starting run: " + name);
+        
+        List<Integer> results = new ArrayList<Integer>();
+        // Repeat the test and baseline for the number of repeats.
+        for (int index = 0; index < REPEATS; index++) {
+            long startTime, endTime;
+            int executions = 0;
+            System.gc();
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException ignore) {}
+            startTime = System.currentTimeMillis();
+            endTime = startTime;
+            // Count how many times the test can be invoked in the run time.
+            // This allows for the test run time to be easily changed.
+            while ((startTime + RUN_TIME) >= endTime) {
+                runnable.run();
+                executions++;
+                endTime = System.currentTimeMillis();
+            }
+            results.add(executions);
+            System.out.println("Done run: " +  index + " for: " + name);
+        }
+        
+        System.out.println("Completed run: " + name);
+
+        PerformanceResult result = new PerformanceResult();
+        result.testName = name;
+        result.runRepeats = REPEATS;
+        result.runTime = RUN_TIME;
+        result.average = averageResults(results);
+        result.max = maxResults(results);
+        result.min = minResults(results);
+        result.standardDeviation = standardDeviationResults(results);
+        
+        System.out.println("");
+        System.out.println(result);
+        System.out.println("");
+        System.out.println("");
+        
+        return result;
+    }
+
+    /**
+     * Compute the max of the results.
+     */
+    public static int maxResults(List<Integer> times) {
+        int testMax = 0;
+        for (int index = 0; index < times.size(); index++) {
+            int time = (int)times.get(index);
+            if (time > testMax) {
+                testMax = time;
+            }
+        }
+        return testMax;
+    }
+
+    /**
+     * Compute the min of the results.
+     */
+    public static int minResults(List<Integer> times) {
+        int testMin = 0;
+        for (int index = 0; index < times.size(); index++) {
+            int time = (int)times.get(index);
+            if ((testMin == 0) || (time < testMin)) {
+                testMin = time;
+            }
+        }
+        return testMin;
+    }
+
+    /**
+     * Filter max and min from results.
+     */
+    public static List<Integer> filterMaxMinResults(List<Integer> times) {
+        List filteredTimes = new ArrayList(times);
+        if (filteredTimes.size() > 3) {
+            filteredTimes.remove((Integer)maxResults(times));
+            filteredTimes.remove((Integer)minResults(times));
+        }
+        return filteredTimes;
+    }
+
+    /**
+     * Compute the average of the results rejecting the min and max.
+     */
+    public static double averageResults(List<Integer> allTimes) {
+        // Compute the average reject the min and max to improve consistency.
+        List<Integer> times = filterMaxMinResults(allTimes);
+        double testAverage = 0;
+        for (int index = 0; index < times.size(); index++) {
+            int time = (int)times.get(index);
+            testAverage = testAverage + time;
+        }
+        testAverage = testAverage / times.size();
+        return testAverage;
+    }
+
+    /**
+     * Compute the standard deviation of the results rejecting the min and max.
+     */
+    public static double standardDeviationResults(List<Integer> allTimes) {
+        // Compute the average reject the min and max to improve consistency.
+        double testAverage = averageResults(allTimes);
+
+        // Compute the standard deviation reject the min and max to improve consistency.
+        List<Integer> times = filterMaxMinResults(allTimes);
+        double testStandardDeviation = 0;
+        for (int index = 0; index < times.size(); index++) {
+            int time = (int)times.get(index);
+            testStandardDeviation = testStandardDeviation + Math.pow(time - testAverage, 2);
+        }
+        testStandardDeviation = testStandardDeviation / times.size();
+        testStandardDeviation = Math.sqrt(testStandardDeviation);
+        // As percent of average
+        testStandardDeviation = (testStandardDeviation / testAverage) * 100;
+        return testStandardDeviation;
+    }
+}
diff --git a/cache/src/example/QueryTest.java b/cache/src/example/QueryTest.java
new file mode 100644
index 0000000..8bcffac
--- /dev/null
+++ b/cache/src/example/QueryTest.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Query;
+
+import model.Order;
+
+/**
+ * Test the performance of reading an Order object model.
+ * @author James Sutherland
+ */
+public class QueryTest extends Test {
+
+    public static void main(String[] args) throws Exception {
+        try {
+            QueryTest test = new QueryTest();
+            test.setup();
+            test.test();
+        } catch (Exception error) {
+            error.printStackTrace();
+        }
+        System.exit(0);
+    }
+
+    public void runTest(EntityManagerFactory factory) {
+        EntityManager em = factory.createEntityManager();
+        Query query = em.createNamedQuery("findOrdersByCustomer");
+        int index = this.random.nextInt(this.customerIds.length);
+        query.setParameter("customerId", this.customerIds[index]);
+        List<Order> result = query.getResultList();
+        for (Order order : result) {
+            order.getCustomer().toString();
+            order.getOrderLines().size();
+        }
+        em.close();
+    }
+}
diff --git a/cache/src/example/Test.java b/cache/src/example/Test.java
new file mode 100644
index 0000000..6208983
--- /dev/null
+++ b/cache/src/example/Test.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import model.Customer;
+import model.Order;
+import model.OrderLine;
+
+/**
+ * Test the performance of reading an Order object model.
+ * @author James Sutherland
+ */
+public abstract class Test extends PerformanceTest {
+    public static int SIZE = 1000;
+    
+    long[] orderIds = new long[SIZE];
+    long[] customerIds = new long[SIZE/10];
+    Random random = new Random();
+    Map<String, EntityManagerFactory> factories = new HashMap<String, EntityManagerFactory>();
+
+    public void setup() {
+        System.out.println("Begin setup");
+        EntityManagerFactory factory = Persistence.createEntityManagerFactory("database");
+        EntityManager em = factory.createEntityManager();
+        em.getTransaction().begin();
+        Order order = null;
+        em.createQuery("Delete from OrderLine").executeUpdate();
+        em.createQuery("Delete from Order").executeUpdate();
+        em.createQuery("Delete from Customer").executeUpdate();
+        int index = 0;
+        for (int customerIndex = 0; customerIndex < (SIZE /10); customerIndex++) {
+            Customer customer = new Customer();
+            customer.setName("Customer-" + index);
+            em.persist(customer);
+            this.customerIds[customerIndex] = customer.getId();
+            for (int orderIndex = 0; orderIndex < 10; orderIndex++) {
+                order = new Order();
+                order.setDescription("Order-" + index);
+                order.setCustomer(customer);
+                order.addOrderLine(new OrderLine("line1", new BigDecimal(10)));
+                order.addOrderLine(new OrderLine("line2", new BigDecimal(5)));
+                order.addOrderLine(new OrderLine("line3", new BigDecimal(99)));
+                em.persist(order);
+                this.orderIds[index] = order.getId();
+                index++;
+            }
+        }
+        em.getTransaction().commit();
+        em.close();
+        this.factories.put("database", factory);
+
+        factory = Persistence.createEntityManagerFactory("cache");
+        factory.createEntityManager().close();;
+        this.factories.put("cache", factory);
+
+        factory = Persistence.createEntityManagerFactory("protected");
+        factory.createEntityManager().close();;
+        this.factories.put("protected", factory);
+
+        factory = Persistence.createEntityManagerFactory("data-cache");
+        factory.createEntityManager().close();;
+        this.factories.put("data-cache", factory);
+
+        factory = Persistence.createEntityManagerFactory("read-only");
+        factory.createEntityManager().close();;
+        this.factories.put("read-only", factory);
+        
+        factory = Persistence.createEntityManagerFactory("read-only-protected");
+        factory.createEntityManager().close();;
+        this.factories.put("read-only-protected", factory);
+        
+        factory = Persistence.createEntityManagerFactory("query-cache");
+        factory.createEntityManager().close();;
+        this.factories.put("query-cache", factory);
+        
+        factory = Persistence.createEntityManagerFactory("in-memory");
+        em = factory.createEntityManager();
+        List<Order> results = em.createQuery("Select o from Order o").getResultList();
+        for (Order result : results) {
+            result.getCustomer().toString();
+            result.getOrderLines().size();
+        }
+        em.close();
+        this.factories.put("in-memory", factory);
+    }
+    
+    public void test() {
+        System.out.println("Begin benchmark");
+        this.executeRun("Database", new Runnable() {
+            public void run() {
+                runTest(factories.get("database"));
+            }
+        });
+        this.executeRun("Cache", new Runnable() {
+            public void run() {
+                runTest(factories.get("cache"));
+            }
+        });
+        this.executeRun("Protected", new Runnable() {
+            public void run() {
+                runTest(factories.get("protected"));
+            }
+        });
+        this.executeRun("DataCache", new Runnable() {
+            public void run() {
+                runTest(factories.get("data-cache"));
+            }
+        });
+        this.executeRun("ReadOnly", new Runnable() {
+            public void run() {
+                runTest(factories.get("read-only"));
+            }
+        });
+        this.executeRun("ProtectedReadOnly", new Runnable() {
+            public void run() {
+                runTest(factories.get("read-only-protected"));
+            }
+        });
+        this.executeRun("QueryCache", new Runnable() {
+            public void run() {
+                runTest(factories.get("query-cache"));
+            }
+        });
+        this.executeRun("InMemoryCache", new Runnable() {
+            public void run() {
+                runTest(factories.get("in-memory"));
+            }
+        });
+        System.out.println("End benchmark");
+    }
+
+    public abstract void runTest(EntityManagerFactory factory);
+}
diff --git a/cache/src/model/Customer.java b/cache/src/model/Customer.java
new file mode 100644
index 0000000..c1c0e90
--- /dev/null
+++ b/cache/src/model/Customer.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+
+import javax.persistence.*;
+
+/**
+ * Customer
+ * @author James Sutherland
+ */
+@Entity
+@Table(name="PERF_CUSTOMER")
+public class Customer implements Serializable {
+    @Id
+    @GeneratedValue(strategy=GenerationType.TABLE)
+    private long id;
+    @Basic
+    private String name;
+
+    public Customer() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+}
diff --git a/cache/src/model/Order.java b/cache/src/model/Order.java
new file mode 100644
index 0000000..e880d47
--- /dev/null
+++ b/cache/src/model/Order.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.*;
+
+/**
+ * Order
+ * @author James Sutherland
+ */
+@Entity(name="Order")
+@Table(name="PERF_ORDER")
+@NamedQueries({
+    @NamedQuery(name="findOrdersByCustomer",
+            query="Select o from Order o where o.customer.id = :customerId")
+})
+public class Order implements Serializable {
+    @Id
+    @GeneratedValue(strategy=GenerationType.TABLE)
+    @Column(name="ORDER_ID")
+    private long id;
+    
+    @Basic
+    private String description;
+    
+    @Basic
+    private BigDecimal totalCost = BigDecimal.valueOf(0);
+    
+    @OneToMany(mappedBy="order", cascade=CascadeType.ALL, orphanRemoval=true)
+    @OrderBy("lineNumber")
+    private List<OrderLine> orderLines = new ArrayList<OrderLine>();
+    
+    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
+    private Customer customer;
+
+    public Order() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public BigDecimal getTotalCost() {
+        return totalCost;
+    }
+
+    public void setTotalCost(BigDecimal totalCost) {
+        this.totalCost = totalCost;
+    }
+
+    public List<OrderLine> getOrderLines() {
+        return orderLines;
+    }
+
+    public void setOrderLines(List<OrderLine> orderLines) {
+        this.orderLines = orderLines;
+    }
+
+    public Customer getCustomer() {
+        return customer;
+    }
+
+    public void setCustomer(Customer customer) {
+        this.customer = customer;
+    }
+    
+    /**
+     * Add the order line to the order, and set the back reference and update the order cost.
+     */
+    public void addOrderLine(OrderLine orderLine) {
+        orderLine.setOrder(this);
+        getOrderLines().add(orderLine);
+        orderLine.setLineNumber(getOrderLines().size());
+        setTotalCost(getTotalCost().add(orderLine.getCost()));
+    }
+}
diff --git a/cache/src/model/OrderLine.java b/cache/src/model/OrderLine.java
new file mode 100644
index 0000000..9254d56
--- /dev/null
+++ b/cache/src/model/OrderLine.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.*;
+
+/**
+ * OrderLine, help by Order.
+ * @author James Sutherland
+ */
+@Entity
+@Table(name="PERF_ORDERLINE")
+public class OrderLine implements Serializable {
+    @Id
+    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
+    @JoinColumn(name="ORDER_ID")
+    private Order order;
+    
+    @Id
+    private int lineNumber;
+    
+    @Basic
+    private String description;
+    
+    @Basic
+    private BigDecimal cost = BigDecimal.valueOf(0);
+
+    public OrderLine() {
+    }
+    
+    public OrderLine(String description, BigDecimal cost) {
+        this.description = description;
+        this.cost = cost;
+    }
+
+    public Order getOrder() {
+        return order;
+    }
+
+    public void setOrder(Order order) {
+        this.order = order;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public BigDecimal getCost() {
+        return cost;
+    }
+
+    public void setCost(BigDecimal cost) {
+        this.cost = cost;
+    }
+    
+}
diff --git a/cache/src/model/OrderLineID.java b/cache/src/model/OrderLineID.java
new file mode 100644
index 0000000..1521dcc
--- /dev/null
+++ b/cache/src/model/OrderLineID.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the 
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
+ * which accompanies this distribution. 
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at 
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *      Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+
+/**
+ * OrderLine Id class.
+ * @author James Sutherland
+ */
+public class OrderLineID implements Serializable {
+
+    private long order;
+    private int lineNumber;
+    
+    public long getOrder() {
+        return order;
+    }
+    public void setOrder(long order) {
+        this.order = order;
+    }
+    public int getLineNumber() {
+        return lineNumber;
+    }
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }    
+}