Bug 361016: Temporal Example
- moved to dedicated repo @ git.eclipse.org/eclipselink/examples/temporal.git
diff --git a/Temporal Entity Example/.classpath b/Temporal Entity Example/.classpath
new file mode 100644
index 0000000..1cfcb7b
--- /dev/null
+++ b/Temporal Entity Example/.classpath
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry excluding="**/.svn/**" kind="src" path="src"/>
+	<classpathentry excluding="**/.svn/**" kind="src" path="test-src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
+	<classpathentry kind="con" path="org.eclipse.datatools.connectivity.jdt.DRIVERLIBRARY/MySQL JDBC Driver"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+		<attributes>
+			<attribute name="owner.project.facets" value="java"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/EclipseLink 2.3.1">
+		<attributes>
+			<attribute name="owner.project.facets" value="jpt.jpa"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="classes"/>
+</classpath>
diff --git a/Temporal Entity Example/.project b/Temporal Entity Example/.project
new file mode 100644
index 0000000..60ac656
--- /dev/null
+++ b/Temporal Entity Example/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>Temporal Entity Example</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>
+	</natures>
+</projectDescription>
diff --git a/Temporal Entity Example/.settings/oracle.eclipse.tools.common.services.prefs b/Temporal Entity Example/.settings/oracle.eclipse.tools.common.services.prefs
new file mode 100644
index 0000000..439794d
--- /dev/null
+++ b/Temporal Entity Example/.settings/oracle.eclipse.tools.common.services.prefs
@@ -0,0 +1,3 @@
+#Mon Jan 30 12:56:04 EST 2012
+eclipse.preferences.version=1
+oracle.eclipse.tools.common.services\:disable=true
diff --git a/Temporal Entity Example/.settings/org.eclipse.jdt.core.prefs b/Temporal Entity Example/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..37edcdc
--- /dev/null
+++ b/Temporal Entity Example/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,77 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=ignore
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/Temporal Entity Example/.settings/org.eclipse.jdt.ui.prefs b/Temporal Entity Example/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..30f4dee
--- /dev/null
+++ b/Temporal Entity Example/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,4 @@
+#Tue Oct 25 14:28:25 EDT 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.ui.javadoc=false
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return the ${bare_field_name}\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} the ${bare_field_name} to set\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*******************************************************************************\r\n * Copyright (c) 2011 Oracle. All rights reserved.\r\n * This program and the accompanying materials are made available under the \r\n * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 \r\n * which accompanies this distribution. \r\n * The Eclipse Public License is available at http\://www.eclipse.org/legal/epl-v10.html\r\n * and the Eclipse Distribution License is available at \r\n * http\://www.eclipse.org/org/documents/edl-v10.php.\r\n *\r\n * Contributors\:\r\n *      dclarke - Bug 361016\: Future Versions Examples\r\n ******************************************************************************/\r\n</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * TODO\r\n *\r\n * @author dclarke\r\n * @since EclipseLink 2.3.1\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\r\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\r\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\r\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/Temporal Entity Example/.settings/org.eclipse.jpt.core.prefs b/Temporal Entity Example/.settings/org.eclipse.jpt.core.prefs
new file mode 100644
index 0000000..a5084b0
--- /dev/null
+++ b/Temporal Entity Example/.settings/org.eclipse.jpt.core.prefs
@@ -0,0 +1,7 @@
+#Wed Feb 22 11:41:54 EST 2012
+eclipse.preferences.version=1
+org.eclipse.jpt.core.platform=eclipselink2_3
+org.eclipse.jpt.jpa.core.discoverAnnotatedClasses=false
+problem.JPQL_QUERY_VALIDATION=warning
+problem.PROJECT_INACTIVE_CONNECTION=info
+workspace_preferences_overriden=true
diff --git a/Temporal Entity Example/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/Temporal Entity Example/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..4862680
--- /dev/null
+++ b/Temporal Entity Example/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+<root>
+  <facet id="jpt.jpa">
+    <node name="libprov">
+      <attribute name="provider-id" value="jpa-user-library-provider"/>
+    </node>
+  </facet>
+</root>
diff --git a/Temporal Entity Example/.settings/org.eclipse.wst.common.project.facet.core.xml b/Temporal Entity Example/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..1e72272
--- /dev/null
+++ b/Temporal Entity Example/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <fixed facet="java"/>
+  <fixed facet="jpt.jpa"/>
+  <installed facet="jpt.jpa" version="2.0"/>
+  <installed facet="java" version="1.7"/>
+</faceted-project>
diff --git a/Temporal Entity Example/about.txt b/Temporal Entity Example/about.txt
new file mode 100644
index 0000000..3bb7a44
--- /dev/null
+++ b/Temporal Entity Example/about.txt
@@ -0,0 +1,15 @@
+EclipseLink JPA: Temporal Entity Example
+
+
+This example implements an interpretation of the temporal object pattern (Fowler). In this example entities have current and future planned editions.
+
+CURRENT
+
+EDITION (Effective)
+
+CONTINUITY: The continuity refers to the current or first future edition where this object exists. 
+			In this example the continuity edition will have the same CID and OID.
+
+References
+- http://martinfowler.com/eaaDev/TemporalObject.html
+
diff --git a/Temporal Entity Example/docs/wiki/TemporalEntity.mediawiki b/Temporal Entity Example/docs/wiki/TemporalEntity.mediawiki
new file mode 100644
index 0000000..cef09c0
--- /dev/null
+++ b/Temporal Entity Example/docs/wiki/TemporalEntity.mediawiki
@@ -0,0 +1,238 @@
+{{bug|361016}}
+__NOTOC__
+== EclipseLink JPA Futures Example ==
+
+This example is intended to illustrate how entity versions can be stored and queried in a database. Unlike the history functionality of EclipseLink this example is focused on creating versions of an entity that may take effect in the future. 
+
+'''Requirements'''
+* Optimize queries against current version. Queries against future versions 
+* Allow versions for the future to be created with a time they are expected to become the current
+* When a future version is promoted to current its temporal storage is not required (no history remains)
+* Allow multiple future versions and support changing when a future version takes effect
+* Support defining a new entity that does not yet exist but may exist in the future
+
+== Software ==
+
+This example is being built using EclipseLink 2.3.1. To access the source of the example check it out of SVN at:
+
+/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.futures
+
+== How it Works ==
+
+Coming Soon...
+
+== Examples ==
+
+The following examples are from test cases.
+
+=== Schema Generation ===
+
+At the start of each test suite the schema is replaced. The resulting CREATE TABLE operations are:
+
+<source lang="sql">
+CREATE TABLE TPERSON (OID NUMBER(10) NOT NULL, 
+                      END_TS NUMBER(19) NULL, 
+                      F_NAME VARCHAR2(255) NULL, 
+                      L_NAME VARCHAR2(255) NULL, 
+                      START_TS NUMBER(19) NULL, 
+                      CID NUMBER(10) NULL, 
+                      ADDRESS_OID NUMBER(10) NULL, 
+                      PRIMARY KEY (OID))
+
+CREATE TABLE TADDRESS (OID NUMBER(10) NOT NULL, 
+                       CITY VARCHAR2(255) NULL, 
+                       END_TS NUMBER(19) NULL, 
+                       START_TS NUMBER(19) NULL, 
+                       STATE VARCHAR2(255) NULL, 
+                       STREET VARCHAR2(255) NULL, 
+                       CID NUMBER(10) NULL, 
+                       PRIMARY KEY (OID))
+
+ALTER TABLE TPERSON ADD CONSTRAINT FK_TPERSON_ADDRESS_OID FOREIGN KEY (ADDRESS_OID) REFERENCES TADDRESS (OID)
+
+ALTER TABLE TPERSON ADD CONSTRAINT FK_TPERSON_CID FOREIGN KEY (CID) REFERENCES TPERSON (OID)
+
+ALTER TABLE TADDRESS ADD CONSTRAINT FK_TADDRESS_CID FOREIGN KEY (CID) REFERENCES TADDRESS (OID)
+
+</source>
+
+=== Create Current Person ===
+
+<source lang="java">
+Person p = new Person();
+p.setFirstName("Doug");
+p.setLastName("Clarke");
+
+Address a = new Address();
+a.setStreet("45 O'Connor Street");
+a.setCity("Ottawa");
+a.setState("Ontario");
+
+p.setAddress(a);
+em.persist(a);
+em.persist(p);
+</source>
+
+Resulting SQL:
+<source lang="sql">
+[EL Fine]: INSERT INTO TADDRESS (OID, CITY, END_TS, START_TS, STATE, STREET, CID) VALUES (?, ?, ?, ?, ?, ?, ?)
+	bind => [1, Ottawa, 9223372036854775807, 0, Ontario, 45 OConnor Street, null]
+[EL Fine]: UPDATE TADDRESS SET STATE = ?, STREET = ?, CID = ?, CITY = ? WHERE (OID = ?)
+	bind => [Ontario, 45 OConnor Street, 1, Ottawa, 1]
+[EL Fine]: INSERT INTO TPERSON (OID, END_TS, F_NAME, L_NAME, START_TS, CID, ADDRESS_OID) VALUES (?, ?, ?, ?, ?, ?, ?)
+	bind => [2, 9223372036854775807, Doug, Clarke, 0, null, null]
+[EL Fine]: UPDATE TPERSON SET CID = ?, ADDRESS_OID = ?, F_NAME = ?, L_NAME = ? WHERE (OID = ?)
+	bind => [2, 1, Doug, Clarke, 2]
+</source>
+
+''Note: The INSERT followed by the UPDATE statement are to populate the self-referencing FK values. Optimized solution being investigated''
+
+=== Create Person Edition ===
+
+This example creates an edition of a current Person (id={currentPersonId}) which is set to take effect at T2 and be deleted or replaced at T4. The current version of the person is updated accordingly to end at T2.
+
+<source lang="java">
+Person currentPerson = em.find(Person.class, currentPersonId);
+
+Person p = TemporalHelper.createEdition(em, currentPerson);
+p.setFirstName("Dougie");
+p.setStart(T2);
+currentPerson.setEnd(T2);
+p.setEnd(T4);
+em.persist(p);
+</source>
+
+SQL:
+<source lang="sql">
+...
+</source>
+
+=== Create Future Person ===
+
+This creates a new Person that does not currently exist but will exist as of T3.
+
+<source lang="java">
+Person p = new Person();
+p.setFirstName("John");
+p.setLastName("Doe");
+p.setStart(T3);
+em.persist(p);
+</source>
+
+SQL:
+<source lang="sql">
+[EL Fine]: INSERT INTO TPERSON (OID, END_TS, F_NAME, L_NAME, START_TS, CID, ADDRESS_OID) VALUES (?, ?, ?, ?, ?, ?, ?)
+	bind => [1, 9223372036854775807, John, Doe, 3, null, null]
+[EL Fine]: UPDATE TPERSON SET CID = ?, START_TS = ?, F_NAME = ?, L_NAME = ? WHERE (OID = ?)
+	bind => [1, 3, John, Doe, 1]
+</source>
+
+=== Query for Current Person ===
+
+<source lang="java">
+EntityManager em = createEntityManager();
+
+Person person = em.createQuery("SELECT p From Person p WHERE p.id = " + currentPersonId, Person.class).getSingleResult();
+Address address = person.getAddress();
+
+Assert.assertNotNull(person);
+
+System.out.println("FIND CURRENT: " + person);
+</source>
+
+OUTPUT:
+<source lang="sql">
+[EL Fine]: SELECT OID, END_TS, F_NAME, L_NAME, START_TS, CID, ADDR_ID FROM TPERSON WHERE ((OID = ?) AND (START_TS = ?))
+	bind => [2, 0]
+[EL Fine]: SELECT OID, CITY, END_TS, START_TS, STATE, STREET, CID FROM TADDRESS WHERE ((OID = ?) AND (START_TS = ?))
+	bind => [1, 0]
+FIND CURRENT: Person(2)::Doug @ 0-2
+</source>
+
+=== Query for Current Person Joining Address ===
+
+<source lang="java">
+EntityManager em = createEntityManager();
+
+Person person = em.createQuery("SELECT p From Person p JOIN FETCH p.address WHERE p.id = " + currentPersonId, Person.class).getSingleResult();
+Address address = person.getAddress();
+
+System.out.println("FIND CURRENT: " + person);
+</source>
+
+OUTPUT:
+<source lang="sql">
+[EL Fine]: SELECT t1.OID, t1.END_TS, t1.F_NAME, t1.L_NAME, t1.START_TS, t1.CID, t1.ADDR_ID, t0.OID, t0.CITY, t0.END_TS, t0.START_TS, t0.STATE, t0.STREET, t0.CID 
+                  FROM TADDRESS t0, TPERSON t1 
+                  WHERE (((t1.OID = ?) AND (t1.START_TS = ?)) AND ((t0.OID = t1.ADDR_ID) AND (t0.START_TS = ?)))
+	bind => [2, 0, 0]
+FIND CURRENT: Person(2)::Doug @ 0-2
+</source>
+
+=== Find Current Person ===
+
+<source lang="java">
+Person person = em.find(Person.class, currentPersonId);
+System.out.println("FIND CURRENT: " + person);
+</source>
+
+OUTPUT:
+<source lang="sql">
+[EL Fine]: SELECT OID, CITY, END_TS, START_TS, STATE, STREET, CID FROM TADDRESS WHERE ((OID = ?) AND (START_TS = ?))
+	bind => [1, 0]
+FIND CURRENT: model.Person(2)::Doug @ 0-2
+</source>
+
+=== Query all Current Persons ===
+<source lang="java">
+List<Person> results = em.createQuery("SELECT p From Person p", Person.class).getResultList();
+</source>
+
+LOG:
+<source lang="sql">
+[EL Fine]: SELECT OID, END_TS, F_NAME, L_NAME, START_TS, CID, ADDRESS_OID FROM TPERSON WHERE (START_TS = ?)
+	bind => [0]
+</source>
+
+=== Find Person edition @ T3 ===
+
+<source lang="java">
+Map<String, Object> props = new HashMap<String, Object>();
+props.put("EFF_TS", T3);
+EntityManager em = emf.createEntityManager(props);
+
+Person personEdition = em.createQuery("SELECT p From PersonEdition p WHERE p.cid = " + currentPersonId, Person.class).getSingleResult();
+
+System.out.println("QUERY EFFECTIVE @ T3: " + personEdition);
+</source>
+
+Log Output:
+<source lang="sql">
+[EL Fine]: SELECT OID, END_TS, F_NAME, L_NAME, START_TS, CID, ADDRESS_OID FROM TPERSON WHERE ((CID = ?) AND ((? >= START_TS) AND (? < END_TS)))
+	bind => [2, 3, 3]
+QUERY EFFECTIVE @ T3:
+Person(3)::Dougie @ 2-4
+</source>
+
+=== Query Future Edition Person @ T2 with Address Joined ===
+
+<source lang="java">
+EntityManager em = createEntityManager();
+em.setProperty("EFF_TS", T2);
+
+Person person = em.createQuery("SELECT p From PersonEdition p JOIN FETCH p.address WHERE p.cid = " + currentPersonId, Person.class).getSingleResult();
+Address address = pEdition.getAddress();
+
+System.out.println("QUERY EDITION @ T2: " + person);
+System.out.println("\t> " + address);
+</source>
+
+OUTPUT:
+<source lang="sql">
+[EL Fine]: SELECT t1.OID, t1.END_TS, t1.F_NAME, t1.L_NAME, t1.START_TS, t1.CID, t1.ADDR_ID, t0.OID, t0.CITY, t0.END_TS, t0.START_TS, t0.STATE, t0.STREET, t0.CID 
+                  FROM TADDRESS t0, TPERSON t1 
+                  WHERE (((t1.CID = ?) AND ((? >= t1.START_TS) AND (? < t1.END_TS))) AND ((t0.CID = t1.ADDR_ID) AND ((? >= t0.START_TS) AND (? < t0.END_TS))))
+	bind => [2, 2, 2, 2, 2]
+QUERY EDITION @ T2: model.PersonEdition(3 @ 2::4)
+	> model.AddressEdition(4 @ 2::9223372036854775807)
+</source>
\ No newline at end of file
diff --git "a/Temporal Entity Example/run-configs/AllTests \0501\051.launch" "b/Temporal Entity Example/run-configs/AllTests \0501\051.launch"
new file mode 100644
index 0000000..c812275
--- /dev/null
+++ "b/Temporal Entity Example/run-configs/AllTests \0501\051.launch"
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/AllTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.AllTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/ApplySimpleEditionSetTests.launch b/Temporal Entity Example/run-configs/ApplySimpleEditionSetTests.launch
new file mode 100644
index 0000000..7e2ac48
--- /dev/null
+++ b/Temporal Entity Example/run-configs/ApplySimpleEditionSetTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/ApplySimpleEditionSetTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.ApplySimpleEditionSetTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/CreateEditionSetTests.launch b/Temporal Entity Example/run-configs/CreateEditionSetTests.launch
new file mode 100644
index 0000000..21675b3
--- /dev/null
+++ b/Temporal Entity Example/run-configs/CreateEditionSetTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/CreateEditionSetTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.CreateEditionSetTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/CreateEditionSetTests.verifyEditionSetAtT2.launch b/Temporal Entity Example/run-configs/CreateEditionSetTests.verifyEditionSetAtT2.launch
new file mode 100644
index 0000000..269c9f8
--- /dev/null
+++ b/Temporal Entity Example/run-configs/CreateEditionSetTests.verifyEditionSetAtT2.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/CreateEditionSetTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value="verifyEditionSetAtT2"/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.CreateEditionSetTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/CreateEditionSetTests.verifyEditionSetAtT4.launch b/Temporal Entity Example/run-configs/CreateEditionSetTests.verifyEditionSetAtT4.launch
new file mode 100644
index 0000000..e680401
--- /dev/null
+++ b/Temporal Entity Example/run-configs/CreateEditionSetTests.verifyEditionSetAtT4.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/CreateEditionSetTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value="verifyEditionSetAtT4"/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.CreateEditionSetTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/DeleteTests.launch b/Temporal Entity Example/run-configs/DeleteTests.launch
new file mode 100644
index 0000000..29497db
--- /dev/null
+++ b/Temporal Entity Example/run-configs/DeleteTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/DeleteTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.DeleteTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/DuplicateInsertOnCreateMerge.launch b/Temporal Entity Example/run-configs/DuplicateInsertOnCreateMerge.launch
new file mode 100644
index 0000000..f51c47c
--- /dev/null
+++ b/Temporal Entity Example/run-configs/DuplicateInsertOnCreateMerge.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/DuplicateInsertOnCreateMerge.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.DuplicateInsertOnCreateMerge"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/EditionSetConfigTests.launch b/Temporal Entity Example/run-configs/EditionSetConfigTests.launch
new file mode 100644
index 0000000..608f52b
--- /dev/null
+++ b/Temporal Entity Example/run-configs/EditionSetConfigTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/EditionSetConfigTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.EditionSetConfigTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/EditionSetTests.launch b/Temporal Entity Example/run-configs/EditionSetTests.launch
new file mode 100644
index 0000000..cb19a38
--- /dev/null
+++ b/Temporal Entity Example/run-configs/EditionSetTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.EditionSetTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/FullPersonWithEditions.launch b/Temporal Entity Example/run-configs/FullPersonWithEditions.launch
new file mode 100644
index 0000000..4d06fdb
--- /dev/null
+++ b/Temporal Entity Example/run-configs/FullPersonWithEditions.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/FullPersonWithEditions.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.FullPersonWithEditions"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/FullPersonWithEditions.queryAllCurrent.launch b/Temporal Entity Example/run-configs/FullPersonWithEditions.queryAllCurrent.launch
new file mode 100644
index 0000000..0b0fef2
--- /dev/null
+++ b/Temporal Entity Example/run-configs/FullPersonWithEditions.queryAllCurrent.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/FullPersonWithEditions.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value="queryAllCurrent"/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.FullPersonWithEditions"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/FuturePersonTests.launch b/Temporal Entity Example/run-configs/FuturePersonTests.launch
new file mode 100644
index 0000000..1849c24
--- /dev/null
+++ b/Temporal Entity Example/run-configs/FuturePersonTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/FuturePersonTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.FuturePersonTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/MultipleEditionQueries.launch b/Temporal Entity Example/run-configs/MultipleEditionQueries.launch
new file mode 100644
index 0000000..00b388a
--- /dev/null
+++ b/Temporal Entity Example/run-configs/MultipleEditionQueries.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/MultipleEditionQueries.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.MultipleEditionQueries"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/PropagateChangesTests.launch b/Temporal Entity Example/run-configs/PropagateChangesTests.launch
new file mode 100644
index 0000000..ca077c7
--- /dev/null
+++ b/Temporal Entity Example/run-configs/PropagateChangesTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/editionsets/PropagateChangesTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.editionsets.PropagateChangesTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/ProxyWrapperUpdateTests.launch b/Temporal Entity Example/run-configs/ProxyWrapperUpdateTests.launch
new file mode 100644
index 0000000..6cd320d
--- /dev/null
+++ b/Temporal Entity Example/run-configs/ProxyWrapperUpdateTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/ProxyWrapperUpdateTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.ProxyWrapperUpdateTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/Temporal Entity Example - AllTests.launch b/Temporal Entity Example/run-configs/Temporal Entity Example - AllTests.launch
new file mode 100644
index 0000000..55f51cf
--- /dev/null
+++ b/Temporal Entity Example/run-configs/Temporal Entity Example - AllTests.launch
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/AllTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.AllTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/TemporalEntityManagerTests.launch b/Temporal Entity Example/run-configs/TemporalEntityManagerTests.launch
new file mode 100644
index 0000000..5885286
--- /dev/null
+++ b/Temporal Entity Example/run-configs/TemporalEntityManagerTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/internal/TemporalEntityManagerTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.internal.TemporalEntityManagerTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/TemporalHelperTests.launch b/Temporal Entity Example/run-configs/TemporalHelperTests.launch
new file mode 100644
index 0000000..a66f00f
--- /dev/null
+++ b/Temporal Entity Example/run-configs/TemporalHelperTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/internal/TemporalHelperTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.internal.TemporalHelperTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/TemporalQueryRedirectorTests.launch b/Temporal Entity Example/run-configs/TemporalQueryRedirectorTests.launch
new file mode 100644
index 0000000..ee7aad1
--- /dev/null
+++ b/Temporal Entity Example/run-configs/TemporalQueryRedirectorTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/TemporalQueryRedirectorTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.TemporalQueryRedirectorTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/VerifyConfigTests.launch b/Temporal Entity Example/run-configs/VerifyConfigTests.launch
new file mode 100644
index 0000000..ef2e044
--- /dev/null
+++ b/Temporal Entity Example/run-configs/VerifyConfigTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/internal/VerifyConfigTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.internal.VerifyConfigTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/VerifySchemaManager.launch b/Temporal Entity Example/run-configs/VerifySchemaManager.launch
new file mode 100644
index 0000000..04cfc02
--- /dev/null
+++ b/Temporal Entity Example/run-configs/VerifySchemaManager.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/internal/VerifySchemaManager.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.internal.VerifySchemaManager"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/run-configs/WrapperPolicyTests.launch b/Temporal Entity Example/run-configs/WrapperPolicyTests.launch
new file mode 100644
index 0000000..d6b4e0d
--- /dev/null
+++ b/Temporal Entity Example/run-configs/WrapperPolicyTests.launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/Temporal Entity Example/test-src/tests/internal/WrapperPolicyTests.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="tests.internal.WrapperPolicyTests"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Temporal Entity Example"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-javaagent:${eclipselink_2.3.2}\eclipselink\jlib\eclipselink.jar"/>
+</launchConfiguration>
diff --git a/Temporal Entity Example/sql b/Temporal Entity Example/sql
new file mode 100644
index 0000000..af0e5b3
--- /dev/null
+++ b/Temporal Entity Example/sql
@@ -0,0 +1,17 @@
+SELECT t1.OID, t1.P_NAMES, t1.VERSION, t1.END_TS, t1.START_TS, t1.CID, t1.ADDR_ID 
+	FROM TADDRESS t0, TPERSON t1 
+	WHERE (((t0.CITY = 't2') AND ((100 >= t1.START_TS) AND (100 < t1.END_TS))) 
+	AND ((t0.CID = t1.ADDR_ID) AND ((100 >= t0.START_TS) AND (100 < t0.END_TS))))
+	
+	bind => [t2, 100, 100, 100, 100]
+
+
+SELECT t1.OID, t1.P_NAMES, t1.VERSION, t1.END_TS, t1.START_TS, t1.CID, t1.ADDR_ID 
+	FROM TADDRESS t0, TPERSON t1 
+	WHERE (((t0.CITY = 'now') AND ((200 >= t1.START_TS) AND (200 < t1.END_TS))) 
+	AND ((t0.OID = t1.ADDR_ID) AND ((200 >= t0.START_TS) AND (200 < t0.END_TS))))
+
+	bind => [t2, 200, 200, 200, 200]
+	
+SELECT * FROM TPERSON
+SELECT * FROM TADDRESS
\ No newline at end of file
diff --git a/Temporal Entity Example/src/META-INF/orm.xml b/Temporal Entity Example/src/META-INF/orm.xml
new file mode 100644
index 0000000..8529b84
--- /dev/null
+++ b/Temporal Entity Example/src/META-INF/orm.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
+	
+	<mapped-superclass class="temporal.BaseEntity" />
+	<mapped-superclass class="temporal.BaseTemporalEntity" />
+	
+	<entity class="model.entities.PersonEntity">
+		<attributes>
+			<many-to-one name="continuity" fetch="LAZY" target-entity="model.entities.PersonEntity">
+				<join-column name="CID" />
+			</many-to-one>
+			<many-to-one name="previousEdition" fetch="LAZY" target-entity="model.entities.PersonEntity">
+				<join-column name="PREVIOUS_ID" />
+			</many-to-one>
+			<one-to-many name="phones" mapped-by="person" target-entity="model.entities.PhoneEntity">
+				<map-key name="type" />
+				<cascade>
+					<cascade-all />
+				</cascade>
+			</one-to-many>
+		</attributes>
+	</entity>
+	<entity class="model.entities.AddressEntity">
+		<attributes>
+			<many-to-one name="continuity" fetch="LAZY" target-entity="model.entities.AddressEntity">
+				<join-column name="CID" />
+			</many-to-one>
+			<many-to-one name="previousEdition" fetch="LAZY" target-entity="model.entities.AddressEntity">
+				<join-column name="PREVIOUS_ID" />
+			</many-to-one>
+		</attributes>
+	</entity>
+	<entity class="model.entities.PhoneEntity">
+		<attributes>
+			<many-to-one name="person" target-entity="model.entities.PersonEntity" fetch="LAZY">
+				<join-column name="PERSON_ID" referenced-column-name="CID"/>
+			</many-to-one>
+			<many-to-one name="continuity" fetch="LAZY" target-entity="model.entities.PhoneEntity">
+				<join-column name="CID" />
+			</many-to-one>
+			<many-to-one name="previousEdition" fetch="LAZY" target-entity="model.entities.PhoneEntity">
+				<join-column name="PREVIOUS_ID" />
+			</many-to-one>
+		</attributes>
+	</entity>
+	<embeddable class="temporal.Effectivity"></embeddable>
+</entity-mappings>
diff --git a/Temporal Entity Example/src/META-INF/persistence.xml b/Temporal Entity Example/src/META-INF/persistence.xml
new file mode 100644
index 0000000..edcd25c
--- /dev/null
+++ b/Temporal Entity Example/src/META-INF/persistence.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="2.0" 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 http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
+	<persistence-unit name="example" transaction-type="RESOURCE_LOCAL">
+		<mapping-file>META-INF/orm.xml</mapping-file>
+		<class>temporal.EditionSetEntry</class>
+		<class>temporal.EditionSet</class>
+		<class>model.PersonHobby</class>
+		<class>model.Hobby</class>
+		<properties>
+			<!-- Database Connection config -->
+			<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
+			<property name="javax.persistence.jdbc.user" value="root"/>
+			<property name="javax.persistence.jdbc.password" value="password"/>
+			<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
+			<property name="eclipselink.jdbc.read-connections.min" value="1"/>
+			<property name="eclipselink.jdbc.write-connections.min" value="1"/>
+			
+			<!-- Logging Config -->
+			<property name="eclipselink.logging.level" value="FINE"/>
+			<property name="eclipselink.logging.timestamp" value="false"/>
+			<property name="eclipselink.logging.thread" value="false"/>
+			<property name="eclipselink.logging.session" value="false"/>
+			<property name="eclipselink.logging.exceptions" value="true"/>
+			<property name="eclipselink.logging.connection" value="true"/>
+			<property name="eclipselink.logging.level.ejb_or_metadata" value="WARNING"/>
+
+			<!-- Use a customizer to configure temporal type's descriptors -->
+			<property name="eclipselink.session.customizer" value="temporal.persistence.ConfigureTemporalDescriptors"/>
+			<property name="eclipselink.weaving" value="true"/>
+		</properties>
+	</persistence-unit>
+</persistence>
diff --git a/Temporal Entity Example/src/example/PersonModelExample.java b/Temporal Entity Example/src/example/PersonModelExample.java
new file mode 100644
index 0000000..64298e1
--- /dev/null
+++ b/Temporal Entity Example/src/example/PersonModelExample.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package example;
+
+import java.sql.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import model.Address;
+import model.Hobby;
+import model.Person;
+import model.entities.AddressEntity;
+import model.entities.PersonEntity;
+
+import org.eclipse.persistence.jpa.JpaHelper;
+import org.eclipse.persistence.sessions.server.Server;
+import org.eclipse.persistence.tools.schemaframework.SchemaManager;
+
+import temporal.Effectivity;
+import temporal.TemporalEntityManager;
+
+/**
+ * This test case performs current and edition queries on a simple
+ * Person-Address-Phones model both illustrating and verifying query operations.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1 
+ */
+public class PersonModelExample {
+
+    public Person simplePerson;
+
+    public Person fullPerson;
+
+    public Person futurePerson;
+
+    public Map<String, Hobby> hobbies = new HashMap<String, Hobby>();
+
+    public static final long T1 = 100;
+    public static final long T2 = 200;
+    public static final long T3 = 300;
+    public static final long T4 = 400;
+    public static final long T5 = 500;
+    public static final long T6 = 600;
+    public static final long T7 = 700;
+    public static final long T8 = 800;
+    public static final long T9 = 900;
+    public static final long T10 = 1000;
+
+    public static final String GOLF = "Golfing";
+    public static final String SKI = "Skiing";
+    public static final String SWIM = "Swimming";
+    public static final String RUN = "Running";
+    public static final String PAINT = "Painting";
+
+    public PersonModelExample() {
+        // Create Hobbies
+        this.hobbies.put(GOLF, new Hobby(GOLF, null));
+        this.hobbies.put(SKI, new Hobby(SKI, null));
+        this.hobbies.put(SWIM, new Hobby(SWIM, null));
+        this.hobbies.put(RUN, new Hobby(RUN, null));
+        this.hobbies.put(PAINT, new Hobby(PAINT, null));
+
+        // Create Simple Person with no relationships
+        this.simplePerson = new PersonEntity();
+        this.simplePerson.setName("Bob");
+
+        // create fullPerson
+        this.fullPerson = new PersonEntity();
+        this.fullPerson.setName("Jim");
+        this.fullPerson.setAddress(new AddressEntity("123 Anywhere St", "Miami", "Florida"));
+        this.fullPerson.addPhone("Home", "111-111-1111");
+        this.fullPerson.setDateOfBirth(new Date(70, 8, 13));
+
+        // create futurePerson
+        this.futurePerson = new PersonEntity();
+        this.futurePerson.setName("Sally");
+        this.futurePerson.getEffectivity().setStart(T2);
+        Address futureAddress = new AddressEntity("45 O'Connor Street", "Ottawa", "Ontario");
+        futureAddress.getEffectivity().setStart(T3);
+        this.futurePerson.setAddress(futureAddress);
+        this.futurePerson.addPhone("Work", "321-654-0987").getEffectivity().setStart(T4);
+        this.futurePerson.addHobby(this.hobbies.get(GOLF), T2);
+    }
+
+    public static void main(String[] args) {
+        PersonModelExample example = new PersonModelExample();
+        EntityManagerFactory emf = Persistence.createEntityManagerFactory("example");
+
+        // Replace Schema
+        Server session = JpaHelper.getServerSession(emf);
+        SchemaManager sm = new SchemaManager(session);
+        sm.replaceDefaultTables();
+        sm.replaceSequences();
+
+        EntityManager em = TemporalEntityManager.getInstance(emf.createEntityManager());
+
+        em.getTransaction().begin();
+        example.populateAll(em);
+        em.getTransaction().commit();
+
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+        example.queryAllCurrent(em);
+
+        em.close();
+        emf.close();
+    }
+
+    /**
+     * Create a new Person edition based on the current starting at T2.
+     */
+    public void populateAll(EntityManager em) {
+        populateHobbies(em);
+        em.persist(this.simplePerson);
+        em.persist(this.fullPerson);
+        em.persist(this.futurePerson);
+    }
+
+    public void populateHobbies(EntityManager em) {
+        for (Hobby h : this.hobbies.values()) {
+            em.persist(h);
+        }
+    }
+
+    public List<Person> queryAllCurrent(EntityManager em) {
+        List<Person> results = em.createQuery("SELECT p From Person p", Person.class).getResultList();
+
+        System.out.println("\nQUERY ALL CURRENT:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+        }
+
+        return results;
+    }
+
+    public List<Person> queryAllCurrentJoinAddress(EntityManager em) {
+        List<Person> results = em.createQuery("SELECT p From Person p JOIN FETCH p.address", Person.class).getResultList();
+
+        System.out.println("\nQUERY CURRENT (JOIN ADDRESS):");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+        }
+
+        return results;
+    }
+
+    public Person queryCurrentSimple(EntityManager em) {
+        Person person = em.createQuery("SELECT p From Person p WHERE p.id = " + this.simplePerson.getId(), Person.class).getSingleResult();
+        person.getAddress();
+
+        System.out.println("FIND CURRENT: " + person);
+        return person;
+    }
+
+    public Person querySampleCurrentPersonJoinAddress(EntityManager em) {
+        Person person = em.createQuery("SELECT p From Person p JOIN FETCH p.address WHERE p.id = " + this.simplePerson.getId(), Person.class).getSingleResult();
+        person.getAddress();
+
+        System.out.println("FIND CURRENT: " + person);
+
+        return person;
+    }
+
+    public Person findSampleCurrentPerson(EntityManager em) {
+        Person person = em.find(Person.class, this.simplePerson.getId());
+
+        System.out.println("FIND CURRENT: " + person);
+
+        return person;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtBOT(TemporalEntityManager em) {
+        em.setEffectiveTime(Effectivity.BOT);
+
+        Person pEdition = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ BOT: " + pEdition);
+
+        return pEdition;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtT1(TemporalEntityManager em) {
+        em.setEffectiveTime(T1);
+
+        Person pEdition = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T1: " + pEdition);
+
+        return pEdition;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtT2(TemporalEntityManager em) {
+        em.setEffectiveTime(T2);
+
+        Person pEdition = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T2: " + pEdition);
+
+        return pEdition;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtT2JoinFetchAddress(TemporalEntityManager em) {
+        em.setEffectiveTime(T2);
+
+        Person person = em.createQuery("SELECT p FROM Person p JOIN FETCH p.address WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+        Address address = person.getAddress();
+
+        System.out.println("QUERY EDITION @ T2: " + person);
+        System.out.println("\t> " + address);
+
+        return person;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtT3(TemporalEntityManager em) {
+        em.setEffectiveTime(T3);
+
+        Person personEdition = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T3: " + personEdition);
+
+        return personEdition;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtT4(TemporalEntityManager em) {
+        em.setEffectiveTime(T4);
+
+        Person pEdition = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T4: " + pEdition);
+
+        return pEdition;
+    }
+
+    public Person queryFutureEditionOfCurrentPersonAtT5(TemporalEntityManager em) {
+        em.setEffectiveTime( T5);
+
+        Person pEdition = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + this.simplePerson.getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T5: " + pEdition);
+
+        return pEdition;
+    }
+
+    public List<Person> nativeQueryForAllEdition(EntityManager em) {
+
+        @SuppressWarnings("unchecked")
+        List<Person> editions = em.createNativeQuery("SELECT * From TPERSON WHERE CID = " + this.simplePerson.getId(), Person.class).getResultList();
+
+        System.out.println("QUERY ALL EDITIONS:");
+        for (Person p : editions) {
+            System.out.println("\t" + p);
+        }
+
+        return editions;
+    }
+
+}
diff --git a/Temporal Entity Example/src/model/Address.java b/Temporal Entity Example/src/model/Address.java
new file mode 100644
index 0000000..60290f5
--- /dev/null
+++ b/Temporal Entity Example/src/model/Address.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model;
+
+import temporal.TemporalEntity;
+
+
+public interface Address extends TemporalEntity<Address> {
+
+    public String getStreet();
+
+    public void setStreet(String street);
+
+    public String getCity();
+
+    public void setCity(String city);
+
+    public String getState();
+
+    public void setState(String state);
+
+}
diff --git a/Temporal Entity Example/src/model/Hobby.java b/Temporal Entity Example/src/model/Hobby.java
new file mode 100644
index 0000000..16da05d
--- /dev/null
+++ b/Temporal Entity Example/src/model/Hobby.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * Represents a Hobby that a person participates in. This entity type is not temporal but is referred to 
+ *
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@Entity
+@Table(name="THOBBY")
+public class Hobby {
+
+    @Id
+    private String name;
+    
+    private String description;
+
+    private Hobby() {
+        super();
+    }
+
+    public Hobby(String name, String description) {
+        this();
+        this.name = name;
+        this.description = description;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    
+}
diff --git a/Temporal Entity Example/src/model/Person.java b/Temporal Entity Example/src/model/Person.java
new file mode 100644
index 0000000..c86848c
--- /dev/null
+++ b/Temporal Entity Example/src/model/Person.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model;
+
+import java.sql.Date;
+import java.util.Map;
+import java.util.Set;
+
+import temporal.TemporalEntity;
+
+public interface Person extends TemporalEntity<Person> {
+
+    String getName();
+
+    void setName(String name);
+
+    Address getAddress();
+
+    void setAddress(Address address);
+
+    Map<String, Phone> getPhones();
+
+    Phone getPhone(String type);
+
+    Phone addPhone(Phone phone);
+
+    Phone addPhone(String type, String number);
+
+    Phone removePhone(String type);
+
+    Map<String, PersonHobby> getPersonHobbies();
+
+    PersonHobby addHobby(Hobby hobby, long asOf);
+    
+    PersonHobby addHobby(PersonHobby personHobby);
+
+    PersonHobby removeHobby(Hobby hobby, long asOf, long current);
+
+    Set<String> getNicknames();
+
+    boolean addNickname(String name);
+
+    boolean removeNickname(String name);
+
+    Date getDateOfBirth();
+
+    void setDateOfBirth(Date dateOfBirth);
+
+    String getEmail();
+
+    void setEmail(String email);
+
+}
diff --git a/Temporal Entity Example/src/model/PersonHobby.java b/Temporal Entity Example/src/model/PersonHobby.java
new file mode 100644
index 0000000..cf6c26e
--- /dev/null
+++ b/Temporal Entity Example/src/model/PersonHobby.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model;
+
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import model.entities.PersonEntity;
+import temporal.Effectivity;
+import temporal.Temporal;
+
+/**
+ * Represents a Person's interest in a hobby. This relationship object is
+ * {@link Temporal}, meaning that the time frame a person is interested in a
+ * hobby is managed but there is not continuity for the relationship itself.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@Entity
+@Table(name = "TPERSON_HOBBY")
+public class PersonHobby implements Temporal {
+
+    @Id
+    private String name;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    private Hobby hobby;
+
+    @ManyToOne(fetch = FetchType.EAGER, targetEntity = PersonEntity.class)
+    @JoinColumn(name = "PERSON_ID", referencedColumnName = "CID")
+    private Person person;
+
+    @Embedded
+    private Effectivity effectivity = new Effectivity();
+
+    public PersonHobby() {
+        this.effectivity = new Effectivity();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Hobby getHobby() {
+        return hobby;
+    }
+
+    public void setPerson(Person person) {
+        this.person = person;
+    }
+
+    public void setHobby(Hobby hobby) {
+        this.name = hobby.getName();
+        this.hobby = hobby;
+    }
+
+    public Person getPerson() {
+        return person;
+    }
+
+    public void setEffectivity(Effectivity effectivity) {
+        this.effectivity = effectivity;
+    }
+
+    @Override
+    public Effectivity getEffectivity() {
+        return this.effectivity;
+    }
+
+    @Override
+    public String toString() {
+        return "PersonHobby[" + getPerson() + "->" + getName() + "]";
+    }
+}
diff --git a/Temporal Entity Example/src/model/Phone.java b/Temporal Entity Example/src/model/Phone.java
new file mode 100644
index 0000000..890b6a4
--- /dev/null
+++ b/Temporal Entity Example/src/model/Phone.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model;
+
+import temporal.TemporalEntity;
+
+/**
+ * TODO
+ *
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public interface Phone extends TemporalEntity<Phone> {
+
+    public String getType();
+
+    public void setType(String type);
+
+    public String getNumber();
+
+    public void setNumber(String number);
+
+    public Person getPerson();
+
+    public void setPerson(Person person);
+
+}
diff --git a/Temporal Entity Example/src/model/entities/AddressEntity.java b/Temporal Entity Example/src/model/entities/AddressEntity.java
new file mode 100644
index 0000000..d7a54e7
--- /dev/null
+++ b/Temporal Entity Example/src/model/entities/AddressEntity.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import model.Address;
+import temporal.BaseTemporalEntity;
+
+@Entity(name = "Address")
+@Table(name = "TADDRESS")
+public class AddressEntity extends BaseTemporalEntity<Address> implements Address {
+
+    private String street;
+
+    private String city;
+
+    private String state;
+
+    public AddressEntity() {
+        super();
+        setContinuity(this);
+    }
+
+    public AddressEntity(String street, String city, String state) {
+        this();
+        this.street = street;
+        this.city = city;
+        this.state = state;
+    }
+
+    public AddressEntity(String street, String city, String state, long start, long end) {
+        this(street, state, city);
+        getEffectivity().setStart(start);
+        getEffectivity().setEnd(end);
+    }
+
+    public String getStreet() {
+        return street;
+    }
+
+    public void setStreet(String street) {
+        this.street = street;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    public String toString() {
+        return getEffectivity().toString(this);
+    }
+
+}
diff --git a/Temporal Entity Example/src/model/entities/PersonEntity.java b/Temporal Entity Example/src/model/entities/PersonEntity.java
new file mode 100644
index 0000000..4379cb3
--- /dev/null
+++ b/Temporal Entity Example/src/model/entities/PersonEntity.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model.entities;
+
+import java.sql.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.MapKey;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+import model.Address;
+import model.Hobby;
+import model.Person;
+import model.PersonHobby;
+import model.Phone;
+
+import org.eclipse.persistence.annotations.Property;
+
+import temporal.BaseTemporalEntity;
+import temporal.TemporalEntity;
+import temporal.TemporalHelper;
+
+@Entity(name = "Person")
+@Table(name = "TPERSON")
+@NamedQueries({ @NamedQuery(name = "Person.currentById", query = "SELECT p FROM Person p WHERE p.cid = :ID") })
+public class PersonEntity extends BaseTemporalEntity<Person> implements Person {
+
+    @Column(name = "P_NAMES")
+    private String name;
+
+    private String email;
+
+    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = AddressEntity.class)
+    @JoinColumn(name = "ADDR_ID")
+    private Address address;
+
+    @OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
+    @MapKey(name = "type")
+    private Map<String, Phone> phones = new HashMap<String, Phone>();
+
+    @ElementCollection
+    @CollectionTable(name = "TPERSON_NNAMES", joinColumns = @JoinColumn(name = "OID", referencedColumnName = "OID"))
+    @Column(name = "NAME")
+    private Set<String> nicknames = new HashSet<String>();
+
+    @OneToMany(mappedBy = "person", cascade = { CascadeType.MERGE, CascadeType.REMOVE })
+    @MapKey(name = "name")
+    private Map<String, PersonHobby> hobbies = new HashMap<String, PersonHobby>();
+
+    @Basic
+    @Property(name = TemporalHelper.NON_TEMPORAL, value = "true")
+    private Date dateOfBirth;
+
+    public PersonEntity() {
+        setContinuity(this);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Address getAddress() {
+        return address;
+    }
+
+    public void setAddress(Address address) {
+        this.address = address;
+    }
+
+    public Map<String, Phone> getPhones() {
+        return phones;
+    }
+
+    public Phone getPhone(String type) {
+        return getPhones().get(type);
+    }
+
+    public Phone addPhone(Phone phone) {
+        getPhones().put(phone.getType(), phone);
+        phone.setPerson(this);
+        return phone;
+    }
+
+    public Phone addPhone(String type, String number) {
+        Phone phone = new PhoneEntity();
+        phone.setNumber(number);
+        phone.setType(type);
+        return addPhone(phone);
+    }
+
+    public Phone removePhone(String type) {
+        return getPhones().remove(type);
+    }
+
+    public Map<String, PersonHobby> getPersonHobbies() {
+        return this.hobbies;
+    }
+
+    @Override
+    public PersonHobby addHobby(PersonHobby personHobby) {
+        personHobby.setPerson(this);
+        this.hobbies.put(personHobby.getName(), personHobby);
+        return personHobby;
+    }
+
+    @Override
+    public PersonHobby addHobby(Hobby hobby, long asOf) {
+       PersonHobby ph = new PersonHobby();
+       ph.setHobby(hobby);
+       ph.getEffectivity().setStart(asOf);
+       return addHobby(ph);
+    }
+
+    @Override
+    public PersonHobby removeHobby(Hobby hobby, long asOf, long current) {
+        PersonHobby personHobby = getPersonHobbies().remove(hobby.getName());
+        if (personHobby == null) {
+            throw new IllegalArgumentException("Hobby not found: " + hobby);
+        }
+        if (current >= asOf) {
+            this.hobbies.remove(hobby.getName());
+        }
+        personHobby.getEffectivity().setEnd(asOf);
+        return personHobby;
+    }
+
+    public Set<String> getNicknames() {
+        return nicknames;
+    }
+
+    public boolean addNickname(String name) {
+        return getNicknames().add(name);
+    }
+
+    public boolean removeNickname(String name) {
+        return getNicknames().remove(name);
+    }
+
+    public Date getDateOfBirth() {
+        return isContinuity() ? this.dateOfBirth : getContinuity().getDateOfBirth();
+    }
+
+    public void setDateOfBirth(Date dateOfBirth) {
+        if (isContinuity()) {
+            this.dateOfBirth = dateOfBirth;
+        } else {
+            getContinuity().setDateOfBirth(dateOfBirth);
+        }
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public void applyEdition(TemporalEntity edition) {
+       Person personEdition = (Person) edition;
+       
+       for (PersonHobby ph: personEdition.getPersonHobbies().values()) {
+           PersonHobby newPh = new PersonHobby();
+           newPh.setHobby(ph.getHobby());
+           newPh.getEffectivity().setStart(ph.getEffectivity().getStart());
+           newPh.getEffectivity().setEnd(ph.getEffectivity().getEnd());
+           addHobby(newPh);
+       }
+       personEdition.getPersonHobbies().clear();
+    }
+
+    public String toString() {
+        return getEffectivity().toString(this);
+    }
+
+}
diff --git a/Temporal Entity Example/src/model/entities/PhoneEntity.java b/Temporal Entity Example/src/model/entities/PhoneEntity.java
new file mode 100644
index 0000000..cd631f9
--- /dev/null
+++ b/Temporal Entity Example/src/model/entities/PhoneEntity.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package model.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import model.Person;
+import model.Phone;
+import temporal.BaseTemporalEntity;
+
+@Entity(name = "Phone")
+@Table(name = "TPHONE")
+public class PhoneEntity extends BaseTemporalEntity<Phone> implements Phone {
+
+    @Column(name = "PTYPE")
+    private String type;
+
+    @Column(name = "PNUM")
+    private String number;
+
+    @ManyToOne
+    private Person person;
+
+    public PhoneEntity() {
+        setContinuity(this);
+    }
+
+    public PhoneEntity(String type, String number) {
+        setType(type);
+        setNumber(number);
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getNumber() {
+        return number;
+    }
+
+    public void setNumber(String number) {
+        this.number = number;
+    }
+
+    public Person getPerson() {
+        return person;
+    }
+
+    public void setPerson(Person person) {
+        this.person = person;
+    }
+
+    public String toString() {
+        return getEffectivity().toString(this);
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/BaseEntity.java b/Temporal Entity Example/src/temporal/BaseEntity.java
new file mode 100644
index 0000000..6bcda98
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/BaseEntity.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Version;
+
+/**
+ * Base entity class which contains the identifier and optimistic locking
+ * version state.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@MappedSuperclass
+public abstract class BaseEntity {
+
+    /**
+     * The OID represents the unique identifier
+     */
+    @Id
+    @GeneratedValue
+    @Column(name = "OID")
+    private int oid;
+
+    @Version
+    private long version;
+
+    /**
+     * Create new current
+     */
+    public BaseEntity() {
+    }
+
+    public int getId() {
+        return oid;
+    }
+
+    public void setId(int id) {
+        this.oid = id;
+    }
+
+    public long getVersion() {
+        return version;
+    }
+
+}
\ No newline at end of file
diff --git a/Temporal Entity Example/src/temporal/BaseTemporalEntity.java b/Temporal Entity Example/src/temporal/BaseTemporalEntity.java
new file mode 100644
index 0000000..38049dc
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/BaseTemporalEntity.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Transient;
+
+/**
+ * Base entity class which contains the identifier and optimistic locking
+ * version state.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@MappedSuperclass
+public abstract class BaseTemporalEntity<T extends TemporalEntity<?>> extends BaseEntity {
+
+    public BaseTemporalEntity() {
+    }
+
+    /**
+     * M:1 relationship to continuity.
+     */
+    @Transient
+    private T continuity;
+
+    /**
+     * M:1 relationship to continuity.
+     */
+    @Transient
+    private T previousEdition;
+
+    @Embedded
+    private Effectivity effectivity = new Effectivity();
+    
+    @Column(name="CID", insertable=false, updatable=false)
+    private int continuityId;
+
+    public T getContinuity() {
+        return this.continuity;
+    }
+
+    public void setContinuity(T continuity) {
+        this.continuity = continuity;
+        this.continuityId = continuity.getId();
+    }
+
+    public int getContinuityId() {
+        return continuityId;
+    }
+
+    public Effectivity getEffectivity() {
+        return this.effectivity;
+    }
+
+    public T getPreviousEdition() {
+        return previousEdition;
+    }
+
+    public void setPreviousEdition(T previousEdition) {
+        this.previousEdition = previousEdition;
+    }
+    
+    public boolean isContinuity() {
+        return getContinuity() != null &&  getId() == getContinuity().getId();
+    }
+    
+    /**
+     * TODO
+     */
+    @SuppressWarnings("rawtypes")
+    public void applyEdition(TemporalEntity edition) {
+        
+    }
+}
\ No newline at end of file
diff --git a/Temporal Entity Example/src/temporal/EditionSet.java b/Temporal Entity Example/src/temporal/EditionSet.java
new file mode 100644
index 0000000..8d38dbf
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/EditionSet.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.*;
+
+import org.eclipse.persistence.annotations.ChangeTracking;
+import org.eclipse.persistence.annotations.ChangeTrackingType;
+import org.eclipse.persistence.annotations.Customizer;
+
+import temporal.persistence.EditionSetEventListener;
+
+/**
+ * An EditionSet represents a proposed set of future changes that should be performed
+ * together at the same effective time. This is an optimisation in the model to
+ * collect all changes for a future point and simplify committing them all
+ * together as the current.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@Entity
+@Table(name = "TEDITIONSET")
+@ChangeTracking(ChangeTrackingType.DEFERRED)
+@Customizer(EditionSetEventListener.class)
+public class EditionSet {
+
+    @Id
+    @Column(name="ID")
+    private long effective;
+
+    private String description;
+    
+    @OneToMany(mappedBy="editionSet", cascade=CascadeType.ALL)
+    private List<EditionSetEntry> entries = new ArrayList<EditionSetEntry>();
+
+    private EditionSet() {
+        super();
+    }
+
+    public EditionSet(long effective) {
+        this();
+        this.effective = effective;
+    }
+
+    public long getEffective() {
+        return effective;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public List<EditionSetEntry> getEntries() {
+        return entries;
+    }
+
+    public EditionSetEntry add(Temporal temporalObject) {
+        EditionSetEntry entry = new EditionSetEntry(this, temporalObject);
+        getEntries().add(entry);
+        return entry;
+    }
+
+    public boolean hasEntries() {
+        return !getEntries().isEmpty();
+    }
+}
diff --git a/Temporal Entity Example/src/temporal/EditionSetEntry.java b/Temporal Entity Example/src/temporal/EditionSetEntry.java
new file mode 100644
index 0000000..823f55b
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/EditionSetEntry.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.eclipse.persistence.annotations.VariableOneToOne;
+
+/**
+ * An EditionSet represents a proposed set of future changes that should be
+ * performed together at the same effective time. This is an optimisation in the
+ * model to collect all changes for a future point and simplify committing them
+ * all together as the current.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@Entity
+@Table(name = "TEDITIONSET_ENTRY")
+public class EditionSetEntry {
+
+    @Id
+    @GeneratedValue
+    @Column(name = "ID")
+    private long id;
+
+    @ManyToOne
+    @JoinColumn(name = "EDITION_SET_ID", referencedColumnName = "ID")
+    private EditionSet editionSet;
+
+    /**
+     * The {@link Temporal} or {@link TemporalEntity} that has been created or
+     * modified
+     */
+    @VariableOneToOne(fetch = FetchType.LAZY)
+    private Temporal temporal;
+
+    /**
+     * Set of attributes that have been modified in this edition.
+     */
+    @ElementCollection
+    @CollectionTable(name = "TEDITIONSET_ENTRY_ATTR", joinColumns = @JoinColumn(name = "ID", referencedColumnName = "ID"))
+    @Column(name = "ATTRIBUTE")
+    private Set<String> attributes = new HashSet<String>();
+
+    private EditionSetEntry() {
+        super();
+    }
+
+    public EditionSetEntry(EditionSet editionSet, Temporal temporal) {
+        this();
+        this.editionSet = editionSet;
+        this.temporal = temporal;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public Temporal getTemporal() {
+        return temporal;
+    }
+
+    public TemporalEntity<?> getTemporalEntity() {
+        return (TemporalEntity<?>) temporal;
+    }
+
+    public EditionSet getEditionSet() {
+        return editionSet;
+    }
+
+    public Set<String> getAttributes() {
+        return attributes;
+    }
+
+    public void addAttribute(String attr) {
+        if (!getAttributes().contains(attr)) {
+            getAttributes().add(attr);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "EditionSetEntry[" + getTemporal() + "]";
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/EditionSetHelper.java b/Temporal Entity Example/src/temporal/EditionSetHelper.java
new file mode 100644
index 0000000..6285102
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/EditionSetHelper.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.persistence.EntityManager;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.descriptors.changetracking.ChangeTracker;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+
+import temporal.persistence.DescriptorHelper;
+
+/**
+ * Apply an {@link EditionSet} making all of its contained editions the current.
+ * This involves copying all relevant values into the current including the
+ * {@link Effectivity} and then delete this edition. The OID of the current
+ * should be changed to that of the edition when the operation is complete.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionSetHelper {
+
+    /**
+     * Apply the {@link EditionSet} causing all its editions to become the
+     * continuity.
+     * 
+     * @param em
+     * @param editionSet
+     */
+    public static void apply(EntityManager em, EditionSet editionSet) {
+        for (EditionSetEntry ese : editionSet.getEntries()) {
+            copyValues(em, ese);
+
+            em.remove(ese.getTemporal());
+
+        }
+    }
+
+    public static void copyValues(EntityManager em, EditionSetEntry entry) {
+        TemporalEntity<?> edition = entry.getTemporalEntity();
+        TemporalEntity<?> continuity = entry.getTemporalEntity().getContinuity();
+
+        AbstractSession session = em.unwrap(RepeatableWriteUnitOfWork.class);
+        ClassDescriptor descriptor = DescriptorHelper.getCurrentDescriptor(session, edition.getClass());
+
+        for (String attr : entry.getAttributes()) {
+            DatabaseMapping mapping = descriptor.getMappingForAttributeName(attr);
+
+            if (!mapping.isForeignReferenceMapping()) {
+                Object value = mapping.getRealAttributeValueFromObject(edition, session);
+                Object oldValue = mapping.getRealAttributeValueFromObject(continuity, session);
+                mapping.setRealAttributeValueInObject(continuity, value);
+                if (continuity instanceof ChangeTracker) {
+                    PropertyChangeListener listener = ((ChangeTracker) continuity)._persistence_getPropertyChangeListener();
+                    listener.propertyChange(new PropertyChangeEvent(continuity, attr, oldValue, value));
+                }
+            }
+        }
+        
+       continuity.applyEdition(edition);
+
+        continuity.getEffectivity().setEnd(edition.getEffectivity().getEnd());
+    }
+
+    /**
+     * TODO
+     * 
+     * @param em
+     * @param editionSet
+     * @param effective
+     */
+    public static void move(EntityManager em, EditionSet editionSet, long effective) {
+
+    }
+}
diff --git a/Temporal Entity Example/src/temporal/EditionWrapperHandler.java b/Temporal Entity Example/src/temporal/EditionWrapperHandler.java
new file mode 100644
index 0000000..dadf961
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/EditionWrapperHandler.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+
+package temporal;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+
+
+/**
+ * {@link Proxy} wrapper for {@link TemporalEntity} to handle the update
+ * scenarios where changes made to an edition should result in new editions
+ * being created.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionWrapperHandler<T extends TemporalEntity<?>> implements InvocationHandler, TemporalEdition<T> {
+
+    /**
+     * The original edition being used by the client. This edition will not be
+     * changed with the exception of the end effectivity time if a new edition
+     * is created.
+     */
+    private T original;
+
+    /**
+     * The new edition created if a set method is invoked
+     */
+    private T newEdition;
+
+    private TemporalEntityManager entityManager;
+
+    /**
+     * 
+     */
+    private Map<String, Object[]> changes;
+
+    public EditionWrapperHandler(T original, EntityManager em) {
+        this.original = original;
+        this.entityManager = TemporalEntityManager.getInstance(em);
+    }
+
+    public T getOriginal() {
+        return original;
+    }
+
+    public T getNewEdition() {
+        return newEdition;
+    }
+
+    public T getEntity() {
+        if (getNewEdition() != null) {
+            return getNewEdition();
+        }
+        return getOriginal();
+    }
+
+    public TemporalEntityManager getEntityManager() {
+        return entityManager;
+    }
+
+    public Map<String, Object[]> getChanges() {
+        return changes;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (method.getDeclaringClass() == TemporalEdition.class) {
+            return method.invoke(this, args);
+        }
+
+        if (args != null && args.length > 0) {
+            if (this.newEdition == null) {
+                this.newEdition = getEntityManager().newEdition(getOriginal());
+                this.changes = new HashMap<String, Object[]>();
+            }
+            getChanges().put(method.getName(), args);
+        }
+
+        Object result = method.invoke(getEntity(), args);
+
+        if (result != null && TemporalHelper.isTemporalEntity(result)) {
+            result = EditionWrapperHelper.wrap(getEntityManager(), result);
+        }
+
+        return result;
+    }
+
+    @Override
+    public boolean hasChanges() {
+        if (getNewEdition() == null) {
+            return false;
+        }
+
+        return !getChanges().isEmpty();
+    }
+
+    /**
+     * Verify if the new edition created by modifications conflicts with any
+     * future editions which already exist.
+     */
+    public boolean hasConflicts() {
+        // TODO: Check for future versions that have conflicting changes
+        throw new RuntimeException("NOT YET IMPLEMENTED");
+    }
+
+    /**
+     * TODO
+     */
+    @SuppressWarnings("unchecked")
+    public T newEdition() {
+        return (T) getEntityManager().newEntity(this.original.getClass());
+    }
+
+    @Override
+    public EditionSetEntry getEditionSetEntry() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/EditionWrapperHelper.java b/Temporal Entity Example/src/temporal/EditionWrapperHelper.java
new file mode 100644
index 0000000..d744fed
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/EditionWrapperHelper.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+
+package temporal;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+
+import javax.persistence.EntityManager;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+
+import temporal.persistence.DescriptorHelper;
+
+
+/**
+ * Helper class used to wrap and unwrap {@link TemporalEntity} with
+ * {@link TemporalEdition} wrappers.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionWrapperHelper {
+
+    @SuppressWarnings("unchecked")
+    public static <T> T wrap(EntityManager em, T entities) {
+        TemporalEntityManager tem = TemporalEntityManager.getInstance(em);
+
+        if (entities instanceof Collection) {
+            Collection<TemporalEntity<?>> source = (Collection<TemporalEntity<?>>) entities;
+            Collection<TemporalEntity<?>> target = (Collection<TemporalEntity<?>>) newCollection(source);
+
+            for (Object obj : source) {
+                target.add((TemporalEntity<?>) wrap(em, obj));
+            }
+        }
+
+        TemporalEntity<?> entity = (TemporalEntity<?>) entities;
+
+        if (Proxy.isProxyClass(entity.getClass())) {
+            return (T) entity;
+        }
+
+        if (entity.getId() <= 0) {
+            throw new IllegalArgumentException("Cannot wrap new entity or edition (persist first)");
+        }
+
+        entity = tem.getEdition(entity);
+
+        if (entity == null) {
+            throw new IllegalArgumentException("Edition does not exist for entity: " + entity);
+        }
+
+        RepeatableWriteUnitOfWork uow = em.unwrap(RepeatableWriteUnitOfWork.class);
+        ClassLoader classLoader = uow.getPlatform().getConversionManager().getLoader();
+        ClassDescriptor descriptor = uow.getClassDescriptor(entity);
+        ClassDescriptor currentDesc = DescriptorHelper.getCurrentDescriptor(uow, descriptor.getJavaClass());
+        Class<?> wrapperInterface = (Class<?>) currentDesc.getProperty(TemporalHelper.INTERFACE);
+
+        EditionWrapperHandler<?> handler = new EditionWrapperHandler<TemporalEntity<?>>(entity, em);
+        return (T) Proxy.newProxyInstance(classLoader, new Class[] { wrapperInterface, TemporalEdition.class }, handler);
+    }
+
+    /**
+     * Create a new collection. Used when wrapping and unwrapping collections to
+     * ensure the result matches the source.
+     * 
+     * @param source
+     * @return
+     */
+    private static Collection<?> newCollection(Collection<?> source) {
+        try {
+            @SuppressWarnings("unchecked")
+            Constructor<Collection<?>> constructor = (Constructor<Collection<?>>) source.getClass().getConstructor(new Class[] { int.class });
+            if (constructor == null) {
+                return source.getClass().newInstance();
+            }
+            return constructor.newInstance(source.size());
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Could not create collection copy to wrap", e);
+        }
+    }
+
+    /**
+     * Unwrap the edition wrappers. If the wrapper contains
+     * 
+     * @param entities
+     * @return unwrapped entity or collection of entities.
+     * @throws IllegalArgumentException
+     *             if any entity provided is not a {@link TemporalEntity}
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T unwrap(T entities) {
+        if (entities != null || entities instanceof Collection) {
+            Collection<TemporalEntity<?>> source = (Collection<TemporalEntity<?>>) entities;
+            Collection<TemporalEntity<?>> target = (Collection<TemporalEntity<?>>) newCollection(source);
+
+            for (Object obj : source) {
+                target.add((TemporalEntity<?>) unwrap(obj));
+            }
+        } else if (entities == null || !(entities instanceof TemporalEntity)) {
+            throw new IllegalArgumentException("Unsupported: " + entities);
+        }
+        TemporalEntity<?> entity = (TemporalEntity<?>) entities;
+        if (Proxy.isProxyClass(entity.getClass())) {
+            EditionWrapperHandler<?> handler = (EditionWrapperHandler<?>) Proxy.getInvocationHandler(entity);
+            entity = handler.getEntity();
+        }
+        return (T) entity;
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/Effectivity.java b/Temporal Entity Example/src/temporal/Effectivity.java
new file mode 100644
index 0000000..3999117
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/Effectivity.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import java.io.StringWriter;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+import org.eclipse.persistence.internal.helper.Helper;
+
+/**
+ * Embedded class encompassing the effectivity start and end dates as well as a
+ * reference to the continuity. This class is mapped onto temporal entity
+ * classes that implement {@link TemporalEntity}
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@Embeddable
+public class Effectivity {
+
+    /**
+     * Beginning Of Time (BOT) value used to indicate the current version in
+     * this example since no history is maintained.
+     */
+    public static final long BOT = 0;
+
+    /**
+     * End Of Time (EOT) value used to represent that the edition using this
+     * value has no planned termination.
+     */
+    public static final long EOT = Long.MAX_VALUE;
+
+    /**
+     * Start time where this edition is planned to become the current edition.
+     * The current edition always has a start value of {@value #BOT}.
+     */
+    @Column(name = "START_TS")
+    private long start = BOT;
+
+    /**
+     * The end time where this edition is planned to be replaced another
+     * edition. The final edition in the sequence that has no planned terminal
+     * time will have a value of {@link #EOT}
+     */
+    @Column(name = "END_TS")
+    private long end = EOT;
+
+    public Effectivity() {
+    }
+
+    public long getStart() {
+        return start;
+    }
+
+    public void setStart(long start) {
+        this.start = start;
+    }
+
+    public long getEnd() {
+        return end;
+    }
+
+    public void setEnd(long end) {
+        this.end = end;
+    }
+
+    public boolean isCurrent() {
+        return getStart() == BOT;
+    }
+
+    /**
+     * @return <code>true</code> if this edition only exists in the future.
+     */
+    public boolean isFutureEdition() {
+        return getStart() > BOT;
+    }
+
+    public String toString() {
+        return "Effectivity(" + getStart() + " - " + getEnd() + ")";
+    }
+
+    public String toString(TemporalEntity<?> entity) {
+        StringWriter writer = new StringWriter();
+
+        writer.write(Helper.getShortClassName(entity));
+        writer.write("(" + entity.getId() + ")");
+        writer.write("Effective: ");
+        writer.write(timeString(getStart()));
+        writer.write(" to ");
+        writer.write(timeString(getEnd()));
+
+        return writer.toString();
+    }
+
+    private String timeString(long ts) {
+        if (ts == BOT) {
+            return "BOT";
+        }
+        if (ts == EOT) {
+            return "EOT";
+        }
+        return Long.toString(ts);
+    }
+}
\ No newline at end of file
diff --git a/Temporal Entity Example/src/temporal/Temporal.java b/Temporal Entity Example/src/temporal/Temporal.java
new file mode 100644
index 0000000..eba2264
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/Temporal.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2011 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+
+/**
+ * Indicates a persistent object which is effective for a specified period of time. 
+ * 
+ * @see Effectivity
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public interface Temporal {
+
+    /**
+     * The range of time the persistent object is effective.
+     */
+    Effectivity getEffectivity();
+
+}
diff --git a/Temporal Entity Example/src/temporal/TemporalEdition.java b/Temporal Entity Example/src/temporal/TemporalEdition.java
new file mode 100644
index 0000000..141ad62
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/TemporalEdition.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+
+package temporal;
+
+
+/**
+ * Additional interface implemented on edition wrappers returned from
+ * {@link EditionWrapperHelper#wrap(javax.persistence.EntityManager, Object)}
+ * which allows users of the wrapper to know if changes exist and to verify if
+ * their change has temporal conflicts with future editions.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public interface TemporalEdition<T extends TemporalEntity<?>> {
+
+    /**
+     * Check if a new edition has been created and if it has changes.
+     */
+    boolean hasChanges();
+
+    /**
+     * Verify if the new edition created by modifications conflicts with any
+     * future editions which already exist.
+     */
+    //boolean hasConflicts();
+        
+    /**
+     * TODO
+     */
+    EditionSetEntry getEditionSetEntry();
+    
+    String toString();
+}
diff --git a/Temporal Entity Example/src/temporal/TemporalEntity.java b/Temporal Entity Example/src/temporal/TemporalEntity.java
new file mode 100644
index 0000000..e97ce3f
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/TemporalEntity.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2011 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import temporal.persistence.ConfigureTemporalDescriptors;
+
+/**
+ * Marker interface used to indicate classes and their subclasses that are
+ * temporal. All descriptors for classes with this interface will be customized
+ * by {@link ConfigureTemporalDescriptors}.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public interface TemporalEntity<T extends TemporalEntity<?>> extends Temporal {
+
+    int getId();
+
+    T getContinuity();
+
+    void setContinuity(T continuity);
+    
+    int getContinuityId();
+
+    T getPreviousEdition();
+
+    void setPreviousEdition(T edition);
+
+    long getVersion();
+
+    boolean isContinuity();
+
+    /**
+     * When an edition is promoted to become the continuity this method is
+     * invoked. This method is invoked after the {@link EditionSetHelper} has
+     * copied all of the mapped values over and allows for entity specific logic
+     * to be applied.
+     */
+    @SuppressWarnings("rawtypes")
+    void applyEdition(TemporalEntity edition);
+
+
+}
diff --git a/Temporal Entity Example/src/temporal/TemporalEntityManager.java b/Temporal Entity Example/src/temporal/TemporalEntityManager.java
new file mode 100644
index 0000000..07c78e1
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/TemporalEntityManager.java
@@ -0,0 +1,509 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import static temporal.TemporalHelper.NON_TEMPORAL;
+import static temporal.persistence.DescriptorHelper.*;
+
+import java.lang.reflect.Member;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaQuery;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor;
+import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+import org.eclipse.persistence.jpa.JpaHelper;
+import org.eclipse.persistence.mappings.AggregateObjectMapping;
+import org.eclipse.persistence.mappings.CollectionMapping;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.queries.DatabaseQuery;
+import org.eclipse.persistence.queries.ObjectLevelReadQuery;
+import org.eclipse.persistence.sessions.Session;
+
+import temporal.persistence.AbstractEntityManagerWrapper;
+import temporal.persistence.DescriptorHelper;
+
+/**
+ * TODO
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.2
+ */
+public class TemporalEntityManager extends AbstractEntityManagerWrapper {
+
+    /**
+     * Property named used to specify the current effective time for all queries
+     * run in the current persistence context.
+     */
+    public static final String EFF_TS_PROPERTY = "EFF_TS";
+
+    /**
+     * TODO
+     */
+    public static final String TEMPORAL_EM_PROPERTY = TemporalEntityManager.class.getName();
+
+    /**
+     * TODO
+     */
+    private Long effective;
+
+    /**
+     * TODO
+     */
+    private EditionSet editionSet;
+
+    /**
+     * TODO
+     * 
+     * @param em
+     * @return
+     */
+    public static TemporalEntityManager getInstance(EntityManager em) {
+        if (TemporalEntityManager.class.isAssignableFrom(em.getClass())) {
+            return (TemporalEntityManager) em;
+        }
+        TemporalEntityManager tem = (TemporalEntityManager) em.getProperties().get(TEMPORAL_EM_PROPERTY);
+        if (tem == null) {
+            tem = new TemporalEntityManager(em);
+        }
+        return tem;
+    }
+
+    /**
+     * Lookup the {@link TemporalEntityManager} as a property within the
+     * provided session.
+     * 
+     * @throws IllegalStateException
+     *             no {@link TemporalEntityManager} is found for the key
+     *             {@value #TEMPORAL_EM_PROPERTY}
+     */
+    public static TemporalEntityManager getInstance(Session session) {
+        TemporalEntityManager tem = (TemporalEntityManager) session.getProperty(TEMPORAL_EM_PROPERTY);
+        if (tem == null) {
+            throw new IllegalStateException("No TemporalEntityManager found in: " + session);
+        }
+        return tem;
+    }
+
+    private TemporalEntityManager(EntityManager em) {
+        super(em);
+        em.setProperty(TEMPORAL_EM_PROPERTY, this);
+    }
+
+    private RepeatableWriteUnitOfWork getUnitOfWork() {
+        return unwrap(RepeatableWriteUnitOfWork.class);
+    }
+
+    public EditionSet setEffectiveTime(Long startTime, boolean initializeEditionSet) {
+        this.effective = startTime;
+        setProperty(EFF_TS_PROPERTY, startTime);
+
+        if (getEditionSet() != null && getEditionSet().getEffective() != startTime) {
+            this.editionSet = null;
+        }
+        if (initializeEditionSet) {
+            this.editionSet = initializeEditionSet();
+        }
+        return this.editionSet;
+    }
+
+    public EditionSet setEffectiveTime(Long startTime) {
+        return setEffectiveTime(startTime, false);
+    }
+
+    public void clearEffectiveTime() {
+        this.effective = null;
+        setProperty(EFF_TS_PROPERTY, null);
+    }
+
+    public Long getEffectiveTime() {
+        // Lookup the EditionSet and use its effective if one exists.
+        EditionSet editionSet = getEditionSet();
+        if (editionSet != null) {
+            return editionSet.getEffective();
+        }
+
+        return this.effective;
+    }
+
+    public boolean hasEffectiveTime() {
+        return getEffectiveTime() != null;
+    }
+
+    /**
+     * Create a new edition based on the previous edition (could be current or
+     * future continuity as well). All values from the provided
+     * {@link BaseEntity} are copied into the new one and if the start time is
+     * provided both the edition and previous version have their start and end
+     * times set accordingly.
+     * <p>
+     * Note: This method currently does not validate for date range conflicts.
+     * It simply adds the next edition assuming the one passed in was correct an
+     * no other future editions exist that will conflict with this addition.
+     * 
+     * @param em
+     *            {@link EntityManager} within a transaction
+     * @param continuityOrEdition
+     *            the {@link BaseEntity} to base this new edition on.
+     * @param start
+     *            the time this new edition should start at. This value is set
+     *            on the new edition and used as the end on the provided entity.
+     *            If null the times are not left as per TemporalEntity's
+     *            constructor.
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends TemporalEntity<?>> T newEdition(T sourceEntity) {
+        AbstractSession session = getUnitOfWork();
+        Long start = getEffectiveTime();
+
+        if (start == null || start == Effectivity.BOT) {
+            throw new IllegalStateException("Cannot create an eddition without an effective time set");
+        }
+        
+        ClassDescriptor descriptor = getClassDescriptor(session, sourceEntity);
+        T source = sourceEntity;
+        if (descriptor.hasWrapperPolicy() && descriptor.getWrapperPolicy().isWrapped(sourceEntity)) {
+            source = (T) descriptor.getWrapperPolicy().unwrapObject(sourceEntity, session);
+        }
+
+        ClassDescriptor editionDesc = getEditionDescriptor(session, source.getClass());
+        if (editionDesc == null) {
+            throw new IllegalArgumentException("No edition descriptor for: " + source);
+        }
+
+        // Lookup the EditionSet and throw and exception if one was not created.
+        EditionSet editionSet = getEditionSet();
+        if (editionSet == null) {
+            throw new IllegalStateException("No EditionSet associated with this EntityManager");
+        }
+
+        TemporalEntity<T> edition = (TemporalEntity<T>) editionDesc.getInstantiationPolicy().buildNewInstance();
+        edition.setContinuity((T) source.getContinuity());
+        edition.setPreviousEdition(source);
+
+        // Copy the mapped values from source to new edition
+        for (DatabaseMapping mapping : editionDesc.getMappings()) {
+            copyValue(session, mapping, source, edition);
+        }
+
+        edition.getEffectivity().setStart(start);
+        edition.getEffectivity().setEnd(source.getEffectivity().getEnd());
+        source.getEffectivity().setEnd(start);
+        
+        getEntityManager().persist(edition);
+
+        editionSet.add(edition);
+
+        // Flush the transaction so that any changes made to the new edition are
+        // tracked and the EditionSet can be properly populated at commit.
+        if (getEntityManager().getTransaction().isActive()) {
+            getEntityManager().flush();
+        }
+
+        if (editionDesc.hasWrapperPolicy() && ! editionDesc.getWrapperPolicy().isWrapped(edition)) {
+            edition = (TemporalEntity<T>) editionDesc.getWrapperPolicy().wrapObject(edition, session);
+        }
+        
+        return (T) edition;
+    }
+
+    /**
+     * Create a new entity that is planned to exist at some future time. The
+     * entity created will have a start time greater than
+     * {@link TemporalEntity#BOT} (beginning of time) and will be the continuity
+     * as well. The start team is specified by the effective time of the
+     * {@link EntityManager} specified by its {@value #EFF_TS_PROPERTY}
+     * property.
+     * 
+     * @param em
+     *            {@link EntityManager} to persist the new edition into
+     * @param entityClass
+     *            the edition or current class
+     * @return the new edition entity
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Temporal> T newTemporal(Class<T> temporalClass) {
+        AbstractSession session = getEntityManager().unwrap(RepeatableWriteUnitOfWork.class);
+        Long start = getEffectiveTime();
+        ClassDescriptor descriptor = session.getClassDescriptor(temporalClass);
+
+        if (descriptor == null) {
+            throw new IllegalArgumentException("No descriptor for: " + temporalClass);
+        }
+        // Lookup the EditionSet and throw and exception if one was not created.
+        EditionSet editionSet = getEditionSet();
+        if (editionSet == null && start != null) {
+            throw new IllegalStateException("No EditionSet associated with this EntityManager");
+        }
+
+        Temporal newInstance = (Temporal) descriptor.getInstantiationPolicy().buildNewInstance();
+
+        // TODO: Unsure why but seeing a null effectivity
+        if (newInstance.getEffectivity() == null) {
+            AggregateObjectMapping effMapping = (AggregateObjectMapping) descriptor.getMappingForAttributeName("effectivity");
+            Effectivity eff = (Effectivity) effMapping.getReferenceDescriptor().getInstantiationPolicy().buildNewInstance();
+            effMapping.setAttributeValueInObject(newInstance, eff);
+        }
+
+        if (start != null) {
+            newInstance.getEffectivity().setStart(start);
+        }
+        getEntityManager().persist(newInstance);
+
+        if (editionSet != null) {
+            editionSet.add(newInstance);
+        }
+
+        // TODO: Enable if change tracking required
+        // em.flush();
+
+        return (T) newInstance;
+    }
+
+    /**
+     * Create a new entity that is planned to exist at some future time. The
+     * entity created will have a start time greater than
+     * {@link TemporalEntity#BOT} (beginning of time) and will be the continuity
+     * as well. The start team is specified by the effective time of the
+     * {@link EntityManager} specified by its {@value #EFF_TS_PROPERTY}
+     * property.
+     * 
+     * @param em
+     *            {@link EntityManager} to persist the new edition into
+     * @param entityClass
+     *            the edition or current class
+     * @return the new edition entity
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends TemporalEntity<?>> T newEntity(Class<T> entityClass) {
+        AbstractSession session = getEntityManager().unwrap(RepeatableWriteUnitOfWork.class);
+        Long start = getEffectiveTime();
+        ClassDescriptor descriptor = session.getClassDescriptor(entityClass);
+
+        if (start != null) {
+            descriptor = getEditionDescriptor(session, (Class<TemporalEntity<T>>) entityClass);
+        }
+        if (descriptor == null) {
+            throw new IllegalArgumentException("No descriptor for: " + entityClass);
+        }
+        // Lookup the EditionSet and throw and exception if one was not created.
+        EditionSet editionSet = getEditionSet();
+        if (editionSet == null && start != null) {
+            throw new IllegalStateException("No EditionSet associated with this EntityManager");
+        }
+
+        TemporalEntity<T> edition = (TemporalEntity<T>) descriptor.getInstantiationPolicy().buildNewInstance();
+        edition.setContinuity((T) edition);
+        if (start != null) {
+            edition.getEffectivity().setStart(start);
+        }
+        getEntityManager().persist(edition);
+
+        if (editionSet != null) {
+            editionSet.add(edition);
+        }
+
+        getEntityManager().flush();
+
+        if (descriptor.hasWrapperPolicy() && ! descriptor.getWrapperPolicy().isWrapped(edition)) {
+            edition = (TemporalEntity<T>) descriptor.getWrapperPolicy().wrapObject(edition, session);
+        }
+        
+        return (T) edition;
+    }
+
+    /**
+     * Copy mapped value from source to new edition. This copies the real
+     * attribute value.
+     */
+    protected void copyValue(AbstractSession session, DatabaseMapping mapping, TemporalEntity<?> source, TemporalEntity<?> target) {
+        if (mapping.getAttributeName().equals("effectivity")) {
+            return;
+        }
+
+        String nonTemporal = (String) mapping.getProperty(NON_TEMPORAL);
+        if (nonTemporal != null && Boolean.valueOf(nonTemporal)) {
+            return;
+        }
+        
+        TemporalEntity<?> unwrappedSource = source;
+        if (mapping.getDescriptor().hasWrapperPolicy() && mapping.getDescriptor().getWrapperPolicy().isWrapped(unwrappedSource)) {
+            unwrappedSource = (TemporalEntity<?>) mapping.getDescriptor().getWrapperPolicy().unwrapObject(unwrappedSource, session); 
+        }
+
+        Member member = null;
+
+        if (mapping.getAttributeAccessor().isInstanceVariableAttributeAccessor()) {
+            member = ((InstanceVariableAttributeAccessor) mapping.getAttributeAccessor()).getAttributeField();
+        } else {
+            member = ((MethodAttributeAccessor) mapping.getAttributeAccessor()).getGetMethod();
+        }
+        if (member.getDeclaringClass().equals(BaseEntity.class)) {
+            return;
+        }
+
+        Object value = mapping.getRealAttributeValueFromObject(unwrappedSource, session);
+
+        if (mapping.isCollectionMapping()) {
+            value = ((CollectionMapping) mapping).getContainerPolicy().cloneFor(value);
+        }
+        
+        Object unwrappedTarget = target;
+        if (mapping.getDescriptor().hasWrapperPolicy() && mapping.getDescriptor().getWrapperPolicy().isWrapped(unwrappedTarget)) {
+            unwrappedTarget = (TemporalEntity<?>) mapping.getDescriptor().getWrapperPolicy().unwrapObject(unwrappedTarget, session); 
+        }
+
+        mapping.setRealAttributeValueInObject(unwrappedTarget, value);
+    }
+
+    /**
+     * Get an edition for a {@link TemporalEntity} handling it being a current
+     * or edition.
+     * 
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends TemporalEntity<?>> T getEdition(T entity) {
+        ClassDescriptor descriptor = getEditionDescriptor(getEntityManager().unwrap(Session.class), entity.getClass());
+
+        if (descriptor == null) {
+            throw new IllegalArgumentException("No edition descriptor found for: " + entity);
+        }
+
+        if (descriptor.getJavaClass() == entity.getClass()) {
+            return entity;
+        }
+        if (entity.getContinuity() == null) {
+            throw new IllegalArgumentException("Entity has no continuity");
+        }
+        if (entity.getEffectivity() == null) {
+            throw new IllegalArgumentException("Entity has no effectivity");
+        }
+        Long original = getEffectiveTime();
+        if (original == null) {
+            setEffectiveTime(Effectivity.BOT);
+        }
+        try {
+            return (T) find(descriptor.getJavaClass(), entity.getContinuity().getId());
+        } finally {
+            setEffectiveTime(original);
+        }
+    }
+
+    public EditionSet getEditionSet() {
+        return this.editionSet;
+    }
+
+    /**
+     * Initialize a new EditionSet
+     */
+    public EditionSet initializeEditionSet() {
+        if (!hasEffectiveTime()) {
+            throw new IllegalStateException("No effective time configured");
+        }
+        Long effective = getEffectiveTime();
+
+        if (getEditionSet() == null || getEditionSet().getEffective() != effective) {
+            EditionSet es = getEntityManager().find(EditionSet.class, effective);
+            if (es == null) {
+                es = new EditionSet(effective);
+                getEntityManager().persist(es);
+            }
+            this.editionSet = es;
+        }
+        return editionSet;
+    }
+
+    /**
+     * TODO: Remove this method when em.find works on either current or edition
+     * based on temporal effectivity of EntityManager
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T find(Class<T> entityClass, Object primaryKey) {
+        if (hasEffectiveTime() && TemporalHelper.isTemporalEntity(entityClass)) {
+            RepeatableWriteUnitOfWork uow = getUnitOfWork();
+            ClassDescriptor descriptor = DescriptorHelper.getEditionDescriptor(uow, entityClass);
+
+            Query query = createNamedQuery(descriptor.getAlias() + ".find");
+            query.setParameter("ID", primaryKey);
+
+            return (T) query.getSingleResult();
+        }
+
+        return (T) super.find(entityClass, primaryKey);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T unwrap(Class<T> clazz) {
+        if (TemporalEntityManager.class == clazz) {
+            return (T) this;
+        }
+        if (EntityManager.class == clazz) {
+            return (T) getEntityManager();
+        }
+        return getEntityManager().unwrap(clazz);
+    }
+
+    @Override
+    public Query createQuery(String qlString) {
+        Query query = super.createQuery(qlString);
+        updateTemporalQuery(query);
+        return query;
+    }
+
+    @Override
+    public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
+        TypedQuery<T> query = super.createQuery(qlString, resultClass);
+        updateTemporalQuery(query);
+        return query;
+    }
+
+    @Override
+    public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
+        TypedQuery<T> query = super.createQuery(criteriaQuery);
+        updateTemporalQuery(query);
+        return query;
+    }
+
+    /**
+     * Update the provided JPA query based on the effective time of use the
+     * correct target entity or edition
+     */
+    private void updateTemporalQuery(Query query) {
+        DatabaseQuery elQuery = JpaHelper.getDatabaseQuery(query);
+        
+        if (hasEffectiveTime() && TemporalHelper.isTemporalEntity(elQuery.getReferenceClass())) {
+            RepeatableWriteUnitOfWork uow = getUnitOfWork();
+            ClassDescriptor descriptor = DescriptorHelper.getEditionDescriptor(uow, elQuery.getReferenceClass());
+            ((ObjectLevelReadQuery) elQuery).setReferenceClass(descriptor.getJavaClass());
+            
+            // TODO: Should this be set every time?
+            if (elQuery.getDescriptor() != null) {
+                elQuery.setDescriptor(descriptor);
+            }
+        }
+    }
+
+
+    public String toString() {
+        return "TemporalEntityManager@" + getEffectiveTime() + "[" + getEntityManager() + "]";
+    }
+}
diff --git a/Temporal Entity Example/src/temporal/TemporalHelper.java b/Temporal Entity Example/src/temporal/TemporalHelper.java
new file mode 100644
index 0000000..8eaa5db
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/TemporalHelper.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal;
+
+import static temporal.persistence.DescriptorHelper.EDITION;
+import static temporal.persistence.DescriptorHelper.EDITION_VIEW;
+import static temporal.persistence.DescriptorHelper.getEditionDescriptor;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.sessions.Session;
+
+/**
+ * This helper is used in to configure and access the temporal values of an
+ * {@link EntityManager} and its managed entities.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class TemporalHelper {
+
+    /**
+     * {@link TemporalEntity} interface name
+     */
+    public static final String INTERFACE = TemporalEntity.class.getName();
+
+    /**
+     * Mapping property used to indicate that a mapping holds a non-temporal
+     * value. The result is that only the continuity row will hold the value.
+     */
+    public static final String NON_TEMPORAL = "example.NonTemporal";
+
+    /**
+     * @return <code>true</code> if this is an instance of the edition subclass.
+     */
+    public static boolean isEdition(EntityManager em, TemporalEntity<?> entity) {
+        ClassDescriptor descriptor = getEditionDescriptor(em.unwrap(Session.class), entity.getClass());
+        return descriptor != null && descriptor.getJavaClass() == entity.getClass();
+    }
+
+
+    /**
+     * TODO
+     * 
+     * @param entityClass
+     * @return
+     */
+    public static boolean isEditionClass(Class<BaseEntity> entityClass) {
+        // TODO: Change to adding a marker interface on created edition class
+        return entityClass.getName().endsWith(EDITION);
+    }
+
+    /**
+     * TODO
+     * 
+     * @param entityClass
+     * @return
+     */
+    public static boolean isEditionViewClass(Class<BaseEntity> entityClass) {
+        // TODO: Change to adding a marker interface on created edition class
+        return entityClass.getName().endsWith(EDITION_VIEW);
+    }
+
+    /**
+     * Helper method used to determine if an object is {@link TemporalEntity}
+     * including the case where a collection is provided. In the case of a
+     * collection it is assumed that if the first entity is temporal then all
+     * elements of the collection are.
+     */
+    public static boolean isTemporalEntity(Object value) {
+        if (value instanceof Class) {
+            return isTemporalEntity((Class<?>) value);
+        }
+        if (value instanceof TemporalEntity) {
+            return true;
+        }
+        if (value instanceof Collection && !((Collection<?>) value).isEmpty()) {
+            Collection<?> c = (Collection<?>) value;
+            Object first = c.iterator().next();
+            return isTemporalEntity(first);
+        }
+        if (value instanceof Map) {
+            throw new IllegalArgumentException("Map not supported");
+        }
+        return false;
+    }
+
+    public static boolean isTemporalEntity(Class<?> value) {
+        return value != null && TemporalEntity.class.isAssignableFrom(value);
+    }
+
+    /**
+     * Helper method used to determine if an object is {@link Temporal}
+     * including the case where a collection is provided. In the case of a
+     * collection it is assumed that if the first entity is temporal then all
+     * elements of the collection are.
+     */
+    public static boolean isTemporal(Object value) {
+        if (value instanceof Class) {
+            return isTemporal((Class<?>) value, true);
+        }
+        if (value instanceof Temporal) {
+            return true;
+        }
+        if (value instanceof Collection && !((Collection<?>) value).isEmpty()) {
+            Collection<?> c = (Collection<?>) value;
+            Object first = c.iterator().next();
+            return isTemporal(first);
+        }
+        if (value instanceof Map) {
+            throw new IllegalArgumentException("Map not supported");
+        }
+        return false;
+    }
+
+    public static boolean isTemporal(Class<?> value, boolean includeTemporalEntity) {
+        if (value == null || (!includeTemporalEntity && isTemporalEntity(value))) {
+            return false;
+        }
+        return Temporal.class.isAssignableFrom(value);
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/AbstractEntityManagerWrapper.java b/Temporal Entity Example/src/temporal/persistence/AbstractEntityManagerWrapper.java
new file mode 100644
index 0000000..0b3af45
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/AbstractEntityManagerWrapper.java
@@ -0,0 +1,254 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.Metamodel;
+
+/**
+ * Utility class that provides a simplified wrapper for an {@link EntityManager}
+ * allowing subclasses to just customize or enhance the behaviour they require.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.2
+ */
+public abstract class AbstractEntityManagerWrapper implements EntityManager {
+
+    /**
+     * Wrapped {@link EntityManager} which all operations will be performed
+     * against
+     */
+    private EntityManager entityManager;
+
+    protected AbstractEntityManagerWrapper(EntityManager em) {
+        this.entityManager = em;
+    }
+
+    protected EntityManager getEntityManager() {
+        return this.entityManager;
+    }
+
+    @Override
+    public <T> T find(Class<T> entityClass, Object primaryKey) {
+        return getEntityManager().find(entityClass, primaryKey);
+    }
+
+    @Override
+    public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
+        return getEntityManager().find(entityClass, primaryKey, properties);
+    }
+
+    @Override
+    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
+        return getEntityManager().find(entityClass, primaryKey, lockMode);
+    }
+
+    @Override
+    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
+        return getEntityManager().find(entityClass, primaryKey, lockMode, properties);
+    }
+
+    @Override
+    public <T> T getReference(Class<T> entityClass, Object primaryKey) {
+        return getEntityManager().getReference(entityClass, primaryKey);
+    }
+
+    @Override
+    public void flush() {
+        getEntityManager().flush();
+    }
+
+    @Override
+    public FlushModeType getFlushMode() {
+        return getEntityManager().getFlushMode();
+    }
+
+    @Override
+    public void clear() {
+        getEntityManager().clear();
+    }
+
+    @Override
+    public void detach(Object entity) {
+        getEntityManager().detach(entity);
+    }
+
+    @Override
+    public boolean contains(Object entity) {
+        return getEntityManager().contains(entity);
+    }
+
+    @Override
+    public LockModeType getLockMode(Object entity) {
+        return getEntityManager().getLockMode(entity);
+    }
+
+    @Override
+    public Map<String, Object> getProperties() {
+        return getEntityManager().getProperties();
+    }
+
+    @Override
+    public Query createQuery(String qlString) {
+        return getEntityManager().createQuery(qlString);
+    }
+
+    @Override
+    public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
+        return getEntityManager().createQuery(criteriaQuery);
+    }
+
+    @Override
+    public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
+        return getEntityManager().createQuery(qlString, resultClass);
+    }
+
+    @Override
+    public Query createNamedQuery(String name) {
+        return getEntityManager().createNamedQuery(name);
+    }
+
+    @Override
+    public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
+        return getEntityManager().createNamedQuery(name, resultClass);
+    }
+
+    @Override
+    public Query createNativeQuery(String sqlString) {
+        return getEntityManager().createNativeQuery(sqlString);
+    }
+
+    @Override
+    public Query createNativeQuery(String sqlString, @SuppressWarnings("rawtypes") Class resultClass) {
+        return getEntityManager().createNativeQuery(sqlString, resultClass);
+    }
+
+    @Override
+    public Query createNativeQuery(String sqlString, String resultSetMapping) {
+        return getEntityManager().createNativeQuery(sqlString, resultSetMapping);
+    }
+
+    @Override
+    public Object getDelegate() {
+        return getEntityManager().getDelegate();
+    }
+
+    @Override
+    public void close() {
+        getEntityManager().close();
+    }
+
+    @Override
+    public EntityManagerFactory getEntityManagerFactory() {
+        return getEntityManager().getEntityManagerFactory();
+    }
+
+    @Override
+    public CriteriaBuilder getCriteriaBuilder() {
+        return getEntityManager().getCriteriaBuilder();
+    }
+
+    @Override
+    public Metamodel getMetamodel() {
+        return getEntityManager().getMetamodel();
+    }
+
+    @Override
+    public EntityTransaction getTransaction() {
+        return getEntityManager().getTransaction();
+    }
+
+    @Override
+    public boolean isOpen() {
+        return getEntityManager().isOpen();
+    }
+
+    @Override
+    public void joinTransaction() {
+        getEntityManager().joinTransaction();
+    }
+
+    @Override
+    public void lock(Object entity, LockModeType lockModeType) {
+        getEntityManager().lock(entity, lockModeType);
+    }
+
+    @Override
+    public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
+        getEntityManager().lock(entity, lockModeType, properties);
+    }
+
+    @Override
+    public <T> T merge(T entity) {
+        return getEntityManager().merge(entity);
+    }
+
+    @Override
+    public void persist(Object entity) {
+        getEntityManager().persist(entity);
+    }
+
+    @Override
+    public void refresh(Object entity) {
+        getEntityManager().refresh(entity);
+    }
+
+    @Override
+    public void refresh(Object entity, Map<String, Object> properties) {
+        getEntityManager().refresh(entity, properties);
+    }
+
+    @Override
+    public void refresh(Object entity, LockModeType lockModeType) {
+        getEntityManager().refresh(entity, lockModeType);
+    }
+
+    @Override
+    public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
+        getEntityManager().refresh(entity, lockModeType, properties);
+    }
+
+    @Override
+    public void remove(Object entity) {
+        getEntityManager().remove(entity);
+    }
+
+    @Override
+    public void setFlushMode(FlushModeType flushModeType) {
+        getEntityManager().setFlushMode(flushModeType);
+    }
+
+    @Override
+    public void setProperty(String name, Object value) {
+        getEntityManager().setProperty(name, value);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T unwrap(Class<T> clazz) {
+        if (EntityManager.class == clazz) {
+            return (T) getEntityManager();
+        }
+        return getEntityManager().unwrap(clazz);
+    }
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/ConfigureTemporalDescriptors.java b/Temporal Entity Example/src/temporal/persistence/ConfigureTemporalDescriptors.java
new file mode 100644
index 0000000..799d86b
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/ConfigureTemporalDescriptors.java
@@ -0,0 +1,495 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import static temporal.TemporalHelper.INTERFACE;
+import static temporal.persistence.DescriptorHelper.CURRENT;
+import static temporal.persistence.DescriptorHelper.EDITION;
+import static temporal.persistence.DescriptorHelper.EDITION_VIEW;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+import org.eclipse.persistence.config.CacheIsolationType;
+import org.eclipse.persistence.config.SessionCustomizer;
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.descriptors.DescriptorEvent;
+import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
+import org.eclipse.persistence.descriptors.DescriptorEventListener;
+import org.eclipse.persistence.descriptors.InheritancePolicy;
+import org.eclipse.persistence.descriptors.changetracking.AttributeChangeTrackingPolicy;
+import org.eclipse.persistence.descriptors.changetracking.ChangeTracker;
+import org.eclipse.persistence.dynamic.DynamicClassLoader;
+import org.eclipse.persistence.dynamic.DynamicClassWriter;
+import org.eclipse.persistence.expressions.Expression;
+import org.eclipse.persistence.expressions.ExpressionBuilder;
+import org.eclipse.persistence.internal.expressions.ParameterExpression;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.internal.jpa.CMP3Policy;
+import org.eclipse.persistence.internal.sessions.AbstractRecord;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.mappings.ForeignReferenceMapping;
+import org.eclipse.persistence.mappings.ManyToOneMapping;
+import org.eclipse.persistence.mappings.OneToManyMapping;
+import org.eclipse.persistence.mappings.OneToOneMapping;
+import org.eclipse.persistence.mappings.VariableOneToOneMapping;
+import org.eclipse.persistence.mappings.querykeys.DirectQueryKey;
+import org.eclipse.persistence.queries.DatabaseQuery;
+import org.eclipse.persistence.queries.QueryRedirector;
+import org.eclipse.persistence.queries.ReadAllQuery;
+import org.eclipse.persistence.queries.ReadObjectQuery;
+import org.eclipse.persistence.queries.SQLCall;
+import org.eclipse.persistence.sessions.Record;
+import org.eclipse.persistence.sessions.Session;
+
+import temporal.EditionSetEntry;
+import temporal.Effectivity;
+import temporal.TemporalEdition;
+import temporal.TemporalEntity;
+import temporal.TemporalHelper;
+
+/**
+ * Customize the persistence unit by adding edition {@link ClassDescriptor}
+ * using dynamic subclasses. This additional descriptor is added to enable
+ * separate edition based queries using an effective time.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class ConfigureTemporalDescriptors implements SessionCustomizer {
+
+    @Override
+    public void customize(Session session) throws Exception {
+        DynamicClassLoader dcl = new DynamicClassLoader(session.getPlatform().getConversionManager().getLoader());
+        session.getPlatform().getConversionManager().setLoader(dcl);
+
+        // Create edition descriptor for all subclasses of TemporalEntity
+        List<ClassDescriptor> editionDescriptors = new ArrayList<ClassDescriptor>();
+        List<ClassDescriptor> editionViewDescriptors = new ArrayList<ClassDescriptor>();
+        Map<Class<?>, ClassDescriptor> interfaceDescriptors = new HashMap<Class<?>, ClassDescriptor>();
+
+        for (ClassDescriptor current : session.getProject().getDescriptors().values()) {
+            if (!current.isDescriptorForInterface() && TemporalHelper.isTemporalEntity(current.getJavaClass())) {
+                ClassDescriptor editionDesc = createEditionType(session, dcl, current, EDITION);
+                editionDescriptors.add(editionDesc);
+
+                ClassDescriptor editionViewDesc = createEditionType(session, dcl, current, EDITION_VIEW);
+                editionViewDescriptors.add(editionViewDesc);
+
+                configureQueries(current, editionDesc, editionViewDesc, session);
+
+                // Cache related descriptors for easy lookup
+                current.setProperty(CURRENT, current);
+                current.setProperty(EDITION, editionDesc);
+                current.setProperty(EDITION_VIEW, editionViewDesc);
+                editionDesc.setProperty(CURRENT, current);
+                editionDesc.setProperty(EDITION, editionDesc);
+                editionDesc.setProperty(EDITION_VIEW, editionViewDesc);
+                editionViewDesc.setProperty(CURRENT, current);
+                editionViewDesc.setProperty(EDITION, editionDesc);
+                editionViewDesc.setProperty(EDITION_VIEW, editionViewDesc);
+
+                setupInterfaceDescriptor(current, editionDesc, session, interfaceDescriptors);
+
+                // Since the redirector can cause queries to run against
+                // different types it is important that no expression to query
+                // caching be used.
+                current.getQueryManager().setExpressionQueryCacheMaxSize(0);
+
+                // FIX relationships from entity to temporal (non-entity)
+                for (DatabaseMapping mapping : current.getMappings()) {
+                    if (mapping.isForeignReferenceMapping()) {
+                        ForeignReferenceMapping frMapping = (ForeignReferenceMapping) mapping;
+                        if (frMapping.isOneToManyMapping() && TemporalHelper.isTemporal(frMapping.getReferenceClass(), false)) {
+                            OneToManyMapping otmm = (OneToManyMapping) frMapping;
+                            Expression original = otmm.buildSelectionCriteria();
+                            ExpressionBuilder eb = original.getBuilder();
+                            otmm.setSelectionCriteria(original.and(eb.get("effectivity").get("start").equal(0)));
+                        }
+                    }
+                }
+
+                // TODO: Configure Wrapper policies
+                //current.setWrapperPolicy(new EditionWrapperPolicy());
+                //editionDesc.setWrapperPolicy(new EditionWrapperPolicy());
+            }
+        }
+
+        // Fix all relationship FKs to edition
+        for (ClassDescriptor desc : editionDescriptors) {
+            fixEditionRelationships(desc, dcl, EDITION);
+            desc.setCacheIsolation(CacheIsolationType.ISOLATED);
+        }
+
+        // Fix all relationship FKs to edition view
+        for (ClassDescriptor desc : editionViewDescriptors) {
+            fixEditionRelationships(desc, dcl, EDITION_VIEW);
+            desc.setCacheIsolation(CacheIsolationType.ISOLATED);
+        }
+
+        session.getProject().addDescriptors(editionDescriptors, (DatabaseSessionImpl) session);
+        session.getProject().addDescriptors(editionViewDescriptors, (DatabaseSessionImpl) session);
+        session.getProject().getDescriptors().putAll(interfaceDescriptors);
+
+        configureEditionSetEntryVariableMapping(session, editionDescriptors);
+
+        session.getEventManager().addListener(new PropagateEditionChangesListener());
+
+    }
+
+    /**
+     * Create new dynamic edition subclass and clone the original descriptor to
+     * have all of the mappings of its parent.
+     * 
+     * @return edition {@link ClassDescriptor}
+     */
+    private ClassDescriptor createEditionType(Session session, DynamicClassLoader dcl, ClassDescriptor source, String suffix) {
+        String interfaceName = source.getJavaClassName() + suffix + "I";
+        Class<?> infc = dcl.createDynamicClass(interfaceName, new EditionInterfaceClassWriter(source.getJavaClass().getInterfaces()[0]));
+
+        String className = source.getJavaClassName() + suffix;
+        Class<?> cls = dcl.createDynamicClass(className, new EditionClassWriter(source.getJavaClass(), infc));
+
+        ClassDescriptor desc = (ClassDescriptor) source.clone();
+        desc.setJavaClassName(className);
+        desc.setJavaClass(cls);
+        desc.setAlias(source.getAlias() + suffix);
+        desc.setCMPPolicy(new CMP3Policy());
+
+        // Configure cache invalidation for edition & current sharing same row
+        desc.getEventManager().addEntityListenerEventListener(new CurrentCacheInvalidator());
+
+        // Configure attribute change tracking as initialization requires
+        // weaving interfaces directly on each class
+        if (ChangeTracker.class.isAssignableFrom(desc.getJavaClass())) {
+            desc.setObjectChangePolicy(new AttributeChangeTrackingPolicy());
+        }
+
+        if (desc.hasInheritance()) {
+            Map<?, ?> classIndicatorMapping = fixEditionMap(source.getInheritancePolicy().getClassIndicatorMapping(), dcl, suffix);
+            desc.getInheritancePolicy().setClassIndicatorMapping(classIndicatorMapping);
+            Map<?, ?> classNameIndicatorMapping = fixEditionMap(desc.getInheritancePolicy().getClassNameIndicatorMapping(), dcl, suffix);
+            desc.getInheritancePolicy().setClassNameIndicatorMapping(classNameIndicatorMapping);
+            fixParentClass(desc.getInheritancePolicy(), dcl, suffix);
+        }
+
+        return desc;
+    }
+
+    private void fixParentClass(InheritancePolicy inheritancePolicy, DynamicClassLoader dcl, String sufix) {
+        if (inheritancePolicy.getParentClass() != null && inheritancePolicy.getParentClassName() != null) {
+            Class<?> parent = dcl.createDynamicClass(inheritancePolicy.getParentClassName() + sufix, new DynamicClassWriter(inheritancePolicy.getParentClass()));
+            inheritancePolicy.setParentClass(parent);
+            inheritancePolicy.setParentClassName(inheritancePolicy.getParentClassName() + sufix);
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private Map<?, ?> fixEditionMap(Map sourceClassIndicatorMapping, DynamicClassLoader dcl, String sufix) {
+        Map newMap = new HashMap();
+        for (Object key : sourceClassIndicatorMapping.keySet()) {
+            try {
+                // indicator mappings
+                if (key instanceof String && sourceClassIndicatorMapping.get(key) instanceof Class) {
+                    Class<?> value = dcl.createDynamicClass(((Class) sourceClassIndicatorMapping.get(key)).getName() + sufix, new DynamicClassWriter((Class) sourceClassIndicatorMapping.get(key)));
+                    newMap.put(key, value);
+                } else if (key instanceof Class && sourceClassIndicatorMapping.get(key) instanceof String) {
+                    Class<?> newkey = dcl.createDynamicClass(((Class) key).getName() + sufix, new DynamicClassWriter((Class) key));
+                    newMap.put(newkey, sourceClassIndicatorMapping.get(key));
+                }
+                // indicator name mapping
+                else if (key instanceof String && sourceClassIndicatorMapping.get(key) instanceof String) {
+                    newMap.put(key + sufix, sourceClassIndicatorMapping.get(key));
+                }
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        return newMap;
+    }
+
+    /**
+     * Adjust the relationship mappings on the edition descriptors so that they
+     * reference other edition descriptors. This can only be done after all
+     * edition dynamic classes have been created and are available in the
+     * {@link DynamicClassLoader}.
+     * <p>
+     * All edition relationships must also be modified so that their FK
+     * references are to the CID combined with the start-end date range applied
+     * by the additional criteria. This method assumes that only simple FK
+     * structures are in use.
+     */
+    @SuppressWarnings("unchecked")
+    private void fixEditionRelationships(ClassDescriptor descriptor, DynamicClassLoader dcl, String suffix) throws ClassNotFoundException {
+
+        // Point all reference mappings to TemporalEntity to edition classes
+        for (DatabaseMapping mapping : descriptor.getMappings()) {
+            if (mapping.isForeignReferenceMapping()) {
+                if (TemporalHelper.isTemporalEntity(((ForeignReferenceMapping) mapping).getReferenceClass())) {
+                    ForeignReferenceMapping frMapping = (ForeignReferenceMapping) mapping;
+                    frMapping.setReferenceClassName(frMapping.getReferenceClassName() + suffix);
+                    frMapping.setReferenceClass(dcl.loadClass(frMapping.getReferenceClassName()));
+
+                    // Relationship or edition descriptor must not be cached so
+                    // that
+                    // the EntityManager/ClientSession/UOW properties are
+                    // available
+                    // to the relationship query
+                    frMapping.setIsCacheable(false);
+
+                    if (mapping.getAttributeName().equals("continuity")) {
+                        ManyToOneMapping contMapping = (ManyToOneMapping) mapping;
+                        // Use a native query to avoid additional criteria
+                        // Causes additional SQL calls
+                        contMapping.setSelectionSQLString("SELECT * FROM " + descriptor.getTableName() + " WHERE OID = #CID");
+                        contMapping.getSelectionQuery().setRedirector(new ContinuityMappingQueryRedirector());
+                        ((ReadObjectQuery) contMapping.getSelectionQuery()).setReferenceClass(frMapping.getReferenceClass());
+                    } else if (frMapping.isOneToOneMapping()) {
+                        fixFKNames(((OneToOneMapping) frMapping).getSourceToTargetKeyFields());
+                    } else if (frMapping.isOneToManyMapping()) {
+                        OneToManyMapping otMMapping = (OneToManyMapping) frMapping;
+                        fixFKNames(otMMapping.getTargetForeignKeysToSourceKeys());
+
+                        List<DatabaseField> sourceFields = (List<DatabaseField>) otMMapping.getSourceKeyFields().clone();
+                        otMMapping.getSourceKeyFields().clear();
+                        List<DatabaseField> targetFields = (List<DatabaseField>) otMMapping.getTargetForeignKeyFields().clone();
+                        otMMapping.getTargetForeignKeyFields().clear();
+
+                        for (int i = 0; i < sourceFields.size(); i++) {
+                            DatabaseField sourceField = sourceFields.get(0).clone();
+                            DatabaseField targetField = targetFields.get(0).clone();
+                            if (sourceField.getName().equals("OID")) {
+                                sourceField.setName("CID");
+                            }
+                            otMMapping.addTargetForeignKeyFieldName(sourceField.getQualifiedName(), targetField.getQualifiedName());
+                        }
+
+                    } else {
+                        throw new RuntimeException("Unsupported temporal entity mapping: " + frMapping);
+                    }
+                } else if (TemporalHelper.isTemporal(((ForeignReferenceMapping) mapping).getReferenceClass(), false)) {
+                    ForeignReferenceMapping frMapping = (ForeignReferenceMapping) mapping;
+
+                    if (mapping.isOneToManyMapping()) {
+                        OneToManyMapping otmm = (OneToManyMapping) frMapping;
+                        Expression original = otmm.buildSelectionCriteria();
+                        ExpressionBuilder eb = original.getBuilder();
+                        // :EFF_TS >= this.effectivity.start AND :EFF_TS <
+                        // this.effectivity.end
+                        ParameterExpression effTsExp = (ParameterExpression) eb.getParameter("EFF_TS");
+                        effTsExp.setIsProperty(true);
+                        Expression startExp = effTsExp.greaterThanEqual(eb.get("effectivity").get("start"));
+                        Expression endExp = effTsExp.lessThan(eb.get("effectivity").get("end"));
+                        otmm.setSelectionCriteria(original.and(startExp.and(endExp)));
+                    } else {
+                        throw new RuntimeException("Unsupported temporal mapping: " + frMapping);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Replace the FK field references to OID to use the continuity id (CID) for
+     * edition relationships. This works with the temporal range to get the
+     * effective instances.
+     */
+    private void fixFKNames(Map<DatabaseField, DatabaseField> keys) {
+        for (Map.Entry<DatabaseField, DatabaseField> entry : keys.entrySet()) {
+            if (entry.getValue().getName().equals("OID")) {
+                entry.getValue().setName("CID");
+            }
+        }
+
+    }
+
+    /**
+     * Configure queries for current and edition descriptors.
+     */
+    private void configureQueries(ClassDescriptor currentDesc, ClassDescriptor editionDesc, ClassDescriptor editionViewDesc, Session session) {
+
+        // EDITION VIEW: Add query keys
+        addCidQueryKey("id", editionViewDesc, session);
+        addCidQueryKey("cid", editionViewDesc, session);
+
+        // EDITION: Add additional criteria and query keys
+        editionDesc.getDescriptorQueryManager().setAdditionalCriteria(":EFF_TS >= this.effectivity.start AND :EFF_TS < this.effectivity.end");
+        addCidQueryKey("id", editionDesc, session);
+        addCidQueryKey("cid", editionDesc, session);
+
+        // CURRENT: Add additional criteria to current descriptor
+        currentDesc.getQueryManager().setAdditionalCriteria("this.effectivity.start = " + Effectivity.BOT);
+        addCidQueryKey("id", currentDesc, session);
+        addCidQueryKey("cid", currentDesc, session);
+
+        // Add Named Queries for editions
+        ReadAllQuery raq = new ReadAllQuery(editionDesc.getJavaClass());
+        raq.setName(editionDesc.getAlias() + ".find");
+        ExpressionBuilder eb = raq.getExpressionBuilder();
+        raq.setSelectionCriteria(eb.get("id").equal(eb.getParameter("ID")));
+        raq.addArgument("ID", int.class);
+        session.addQuery(raq.getName(), raq);
+
+        raq = new ReadAllQuery(editionDesc.getJavaClass());
+        raq.setName(editionDesc.getAlias() + ".all");
+        SQLCall call = new SQLCall("SELECT * From TPERSON WHERE CID = #CID ORDER BY START_TS");
+        call.setHasCustomSQLArguments(true);
+        call.setCustomSQLArgumentType("CID", int.class);
+        raq.setCall(call);
+        raq.addArgument("CID", int.class);
+        session.addQuery(raq.getName(), raq);
+    }
+
+    private void addCidQueryKey(String keyName, ClassDescriptor desc, Session session) {
+        DatabaseField cidField = getCidField(desc, session);
+        if (cidField != null) {
+            DirectQueryKey cidKey = new DirectQueryKey();
+            cidKey.setName(keyName);
+            cidKey.setField(cidField);
+            cidKey.setFieldName(cidField.getQualifiedName());
+            cidKey.initialize(desc);
+            desc.addQueryKey(cidKey);
+        }
+    }
+
+    private DatabaseField getCidField(ClassDescriptor desc, Session session) {
+        DatabaseMapping prop = desc.getMappingForAttributeName("continuity");
+        if (prop != null) {
+            if (prop.isForeignReferenceMapping()) {
+                Vector<DatabaseField> fields = ((ManyToOneMapping) prop).getForeignKeyFields();
+                return fields.iterator().next();
+            }
+
+        }
+        // try to find it in the parent
+        if (desc.hasInheritance() && desc.getInheritancePolicy().getParentClass() != null) {
+            ClassDescriptor parentDesc = session.getClassDescriptor(desc.getInheritancePolicy().getParentClass());
+            if (parentDesc != null) {
+                return getCidField(parentDesc, session);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Calculate interface descriptors.
+     */
+    private void setupInterfaceDescriptor(ClassDescriptor currentDesc, ClassDescriptor editionDesc, Session session, Map<Class<?>, ClassDescriptor> interfaceDescriptors) {
+        Class<?>[] interfaces = currentDesc.getJavaClass().getInterfaces();
+        if (interfaces.length == 0) {
+            throw new IllegalStateException("TemporalEntity types must implement an interface");
+        }
+
+        Class<?> currentInterface = interfaces[0];
+        Class<?> editionInterface = editionDesc.getJavaClass().getInterfaces()[0];
+
+        currentDesc.setProperty(INTERFACE, currentInterface);
+        editionDesc.setProperty(INTERFACE, editionInterface);
+
+        interfaceDescriptors.put(currentInterface, currentDesc);
+        interfaceDescriptors.put(editionInterface, editionDesc);
+    }
+
+    /**
+     * Configure the {@link VariableOneToOneMapping} from
+     * {@link EditionSetEntry} to the {@link TemporalEdition} populating all of
+     * the edition descriptor types.
+     */
+    @SuppressWarnings("unchecked")
+    private void configureEditionSetEntryVariableMapping(Session session, List<ClassDescriptor> editionDescriptors) {
+        ClassDescriptor editionSetEntryDesc = session.getClassDescriptor(EditionSetEntry.class);
+        VariableOneToOneMapping originalMapping = (VariableOneToOneMapping) editionSetEntryDesc.removeMappingForAttributeName("temporal");
+        CustomVariableOneToOneMaping mapping = new CustomVariableOneToOneMaping(originalMapping);
+        editionSetEntryDesc.addMapping(mapping);
+        mapping.setIsCacheable(false);
+
+        for (ClassDescriptor editionDesc : editionDescriptors) {
+            String shortAlias = editionDesc.getAlias().substring(0, editionDesc.getAlias().indexOf(EDITION));
+            mapping.addClassIndicator(editionDesc.getJavaClass(), shortAlias);
+        }
+
+        for (ClassDescriptor desc : session.getDescriptors().values()) {
+            if (!desc.isDescriptorForInterface() && TemporalHelper.isTemporal(desc.getJavaClass(), false)) {
+                mapping.addClassIndicator(desc.getJavaClass(), desc.getAlias());
+
+                if (desc.getMappingForAttributeName("oid") == null) {
+                    desc.addDirectQueryKey("oid", desc.getPrimaryKeyFieldNames().get(0));
+                }
+            }
+        }
+
+        for (Entry<?, String> entry : ((Map<?, String>) mapping.getSourceToTargetQueryKeyNames()).entrySet()) {
+            entry.setValue("oid");
+        }
+    }
+
+    /**
+     * This redirector is used on the edition descriptor's M:1 continuity
+     * mapping to check for cache hits. The query on the mapping has been
+     * altered to use native SQL to avoid the descriptor's additional criteria
+     * so without this there will never be a cache hit.
+     */
+    @SuppressWarnings("serial")
+    class ContinuityMappingQueryRedirector implements QueryRedirector {
+
+        @Override
+        public Object invokeQuery(DatabaseQuery query, Record arguments, Session session) {
+            TemporalEntity<?> cachedEntity = (TemporalEntity<?>) session.getIdentityMapAccessor().getFromIdentityMap(arguments, query.getReferenceClass());
+            if (cachedEntity != null && cachedEntity.getEffectivity().isCurrent()) {
+                return cachedEntity;
+            }
+
+            query.setDoNotRedirect(true);
+            return ((AbstractSession) session).executeQuery(query, (AbstractRecord) arguments);
+        }
+
+    }
+
+    /**
+     * Invalidate the cache for any current entities when a change is written
+     * for an edition entity with a start effectivity time of
+     * {@value Effectivity#BOT}.
+     * <p>
+     * A {@link DescriptorEventListener} approach is used which means the
+     * invalidation happens after the write but before the transaction commits.
+     * This could result in cache invalidations for transactions that do not
+     * commit.
+     */
+    class CurrentCacheInvalidator extends DescriptorEventAdapter {
+
+        @Override
+        public void postWrite(DescriptorEvent event) {
+            TemporalEntity<?> entity = (TemporalEntity<?>) event.getSource();
+            if (entity.getEffectivity().getStart() == Effectivity.BOT) {
+                AbstractSession session = event.getSession().getRootSession(event.getQuery());
+                Object pk = event.getDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(entity.getContinuity(), session);
+                ClassDescriptor currentDesc = DescriptorHelper.getCurrentDescriptor(session, entity.getClass());
+                session.getIdentityMapAccessor().invalidateObject(pk, currentDesc.getJavaClass());
+            }
+        }
+
+    }
+
+    // Added to avoid Eclipse WTP-Dali Bug 361196
+    public ConfigureTemporalDescriptors() {
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/CurrentWrapperPolicy.java b/Temporal Entity Example/src/temporal/persistence/CurrentWrapperPolicy.java
new file mode 100644
index 0000000..8544686
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/CurrentWrapperPolicy.java
@@ -0,0 +1,188 @@
+package temporal.persistence;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.descriptors.WrapperPolicy;
+import org.eclipse.persistence.exceptions.DescriptorException;
+import org.eclipse.persistence.internal.descriptors.PersistenceObject;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.queries.FetchGroupTracker;
+import org.eclipse.persistence.sessions.Session;
+
+import temporal.EditionSetEntry;
+import temporal.TemporalEdition;
+import temporal.TemporalEntity;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+
+public class CurrentWrapperPolicy implements WrapperPolicy {
+    private static final long serialVersionUID = 1L;
+
+    private AbstractSession session;
+
+    private ClassDescriptor descriptor;
+
+    @Override
+    public void initialize(AbstractSession session) throws DescriptorException {
+        this.session = session;
+    }
+
+    public AbstractSession getSession() {
+        return session;
+    }
+
+    @Override
+    public boolean isTraversable() {
+        return true;
+    }
+
+    @Override
+    public boolean isWrapped(Object object) {
+        return Proxy.isProxyClass(object.getClass());
+    }
+
+    @Override
+    public void setDescriptor(ClassDescriptor descriptor) {
+        this.descriptor = descriptor;
+    }
+
+    public ClassDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    public Object unwrapObject(Object proxy, AbstractSession session) {
+        InvocationHandler handler = Proxy.getInvocationHandler(proxy);
+
+        if (handler instanceof CurrentWrapperHandler<?>) {
+            return ((CurrentWrapperHandler<?>) handler).getOriginal();
+        }
+
+        if (handler instanceof EditionWrapperPolicy.Handler<?>) {
+            return ((EditionWrapperPolicy.Handler<?>) handler).getEntity();
+        }
+        throw new IllegalArgumentException("Unknown proxy: " + proxy);
+    }
+
+    @Override
+    public Object wrapObject(Object original, AbstractSession session) {
+        Class<?> wrapperInterface = (Class<?>) getDescriptor().getProperty(TemporalHelper.INTERFACE);
+        CurrentWrapperHandler<?> handler = new CurrentWrapperHandler<TemporalEntity<?>>((TemporalEntity<?>) original);
+        return Proxy.newProxyInstance(getSession().getLoader(), new Class[] { wrapperInterface, TemporalEdition.class, PersistenceObject.class, FetchGroupTracker.class }, handler);
+    }
+
+    /**
+     * {@link Proxy} wrapper for {@link TemporalEntity} to handle the update
+     * scenarios where changes made to an edition should result in new editions
+     * being created.
+     * 
+     * @author dclarke
+     * @since EclipseLink 2.3.1
+     */
+    public class CurrentWrapperHandler<T extends TemporalEntity<?>> implements InvocationHandler, TemporalEdition<T> {
+
+        /**
+         * The original edition being used by the client. This edition will not
+         * be changed with the exception of the end effectivity time if a new
+         * edition is created.
+         */
+        private T original;
+
+        /**
+         * The new edition created if a set method is invoked
+         */
+        private T newEdition;
+
+        private TemporalEntityManager entityManager;
+
+        /**
+         * 
+         */
+        private Map<String, Object[]> changes;
+
+        public CurrentWrapperHandler(T original) {
+            this.original = original;
+        }
+
+        public T getOriginal() {
+            return original;
+        }
+
+        public T getNewEdition() {
+            return newEdition;
+        }
+
+        public T getEntity() {
+            if (getNewEdition() != null) {
+                return getNewEdition();
+            }
+            return getOriginal();
+        }
+
+        public TemporalEntityManager getEntityManager() {
+            if (this.entityManager == null && getOriginal() instanceof FetchGroupTracker) {
+                Session session = ((FetchGroupTracker) getOriginal())._persistence_getSession();
+                if (session != null) {
+                    this.entityManager = TemporalEntityManager.getInstance(session);
+                }
+            }
+            return entityManager;
+        }
+
+        public void setEntityManager(TemporalEntityManager entityManager) {
+            this.entityManager = entityManager;
+        }
+
+        public Map<String, Object[]> getChanges() {
+            return changes;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (method.getDeclaringClass() == TemporalEdition.class) {
+                return method.invoke(this, args);
+            }
+
+            if ("toString".equals(method.getName())) {
+                return "CurrentEntityProxy[" + getEntity() + "]";
+            }
+
+            if (getEntityManager() != null && args != null && args.length > 0) {
+                if (this.newEdition == null) {
+                    this.newEdition = getEntityManager().newEdition(getOriginal());
+                    this.changes = new HashMap<String, Object[]>();
+                }
+                getChanges().put(method.getName(), args);
+            }
+
+            return method.invoke(getEntity(), args);
+        }
+
+        @Override
+        public boolean hasChanges() {
+            if (getNewEdition() == null) {
+                return false;
+            }
+
+            return !getChanges().isEmpty();
+        }
+
+        @Override
+        public EditionSetEntry getEditionSetEntry() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            return "CurrentEntityProxy[" + getEntity() + "]";
+        }
+
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/CustomVariableOneToOneMaping.java b/Temporal Entity Example/src/temporal/persistence/CustomVariableOneToOneMaping.java
new file mode 100644
index 0000000..4bd20cf
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/CustomVariableOneToOneMaping.java
@@ -0,0 +1,51 @@
+package temporal.persistence;
+
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+
+import java.util.Set;
+
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.mappings.VariableOneToOneMapping;
+
+/**
+ * Custom {@link VariableOneToOneMapping} added to work-around bug in base
+ * mapping with respect to field caching.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class CustomVariableOneToOneMaping extends VariableOneToOneMapping {
+
+    public CustomVariableOneToOneMaping(VariableOneToOneMapping original) {
+        setAttributeAccessor(original.getAttributeAccessor());
+        setAttributeName(original.getAttributeName());
+        setDescriptor(original.getDescriptor());
+        setIndirectionPolicy(original.getIndirectionPolicy());
+        setFields(original.getFields());
+        setForeignKeyFields(original.getForeignKeyFields());
+        setClassIndicatorAssociations(original.getClassIndicatorAssociations());
+        setReferenceClass(original.getReferenceClass());
+        setIsLazy(original.isLazy());
+        setTypeField(original.getTypeField());
+        setSourceToTargetQueryKeyFields(original.getSourceToTargetQueryKeyNames());
+    }
+
+    @Override
+    public void collectQueryParameters(Set<DatabaseField> cacheFields) {
+        super.collectQueryParameters(cacheFields);
+        cacheFields.add(getTypeField());
+    }
+
+    private static final long serialVersionUID = 1L;
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/DescriptorHelper.java b/Temporal Entity Example/src/temporal/persistence/DescriptorHelper.java
new file mode 100644
index 0000000..3585bb9
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/DescriptorHelper.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Member;
+import java.lang.reflect.Proxy;
+
+import javax.persistence.EntityManager;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor;
+import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.sessions.Session;
+
+import temporal.BaseEntity;
+import temporal.TemporalEntity;
+import temporal.TemporalHelper;
+
+/**
+ * This helper is used in to configure and access the temporal values of an
+ * {@link EntityManager} and its managed entities.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class DescriptorHelper {
+
+    /**
+     * Property name used to cache current descriptor on edition and edition
+     * view descriptors
+     */
+    public static final String CURRENT = "Current";
+
+    /**
+     * Entity type name prefix prepended to current entity type
+     */
+    public static final String EDITION = "Edition";
+
+    /**
+     * Entity type name prefix prepended to current entity type
+     */
+    public static final String EDITION_VIEW = "EditionView";
+
+    /**
+     * Copy mapped value from source to new edition. This copies the real
+     * attribute value.
+     */
+    protected static void copyValue(AbstractSession session, DatabaseMapping mapping, TemporalEntity<?> source, TemporalEntity<?> target) {
+        if (mapping.getAttributeName().equals("effectivity")) {
+            return;
+        }
+
+        String nonTemporal = (String) mapping.getProperty(TemporalHelper.NON_TEMPORAL);
+        if (nonTemporal != null && Boolean.valueOf(nonTemporal)) {
+            return;
+        }
+
+        Member member = null;
+
+        if (mapping.getAttributeAccessor().isInstanceVariableAttributeAccessor()) {
+            member = ((InstanceVariableAttributeAccessor) mapping.getAttributeAccessor()).getAttributeField();
+        } else {
+            member = ((MethodAttributeAccessor) mapping.getAttributeAccessor()).getGetMethod();
+        }
+        if (member.getDeclaringClass().equals(BaseEntity.class)) {
+            return;
+        }
+
+        Object value = mapping.getRealAttributeValueFromObject(source, session);
+        mapping.setRealAttributeValueInObject(target, value);
+    }
+
+    private static ClassDescriptor getDescriptor(Session session, Class<?> entityClass, String type) {
+        ClassDescriptor desc = session.getClassDescriptor(entityClass);
+        if (desc == null) {
+            throw new IllegalArgumentException("Non-persistent type: " + entityClass);
+        }
+        return (ClassDescriptor) desc.getProperty(type);
+    }
+
+    public static ClassDescriptor getCurrentDescriptor(Session session, Class<?> entityClass) {
+        return getDescriptor(session, entityClass, CURRENT);
+    }
+
+    public static ClassDescriptor getEditionDescriptor(Session session, Class<?> entityClass) {
+        return getDescriptor(session, entityClass, EDITION);
+    }
+    
+    /**
+     * TODO
+     */
+    public static ClassDescriptor getClassDescriptor(Session session, Object entity) {
+        Object domainObject = entity;
+        
+        if (Proxy.isProxyClass(entity.getClass())) {
+            InvocationHandler handler = Proxy.getInvocationHandler(entity);
+            
+            if (handler instanceof EditionWrapperPolicy.Handler<?>) {
+                domainObject = ((EditionWrapperPolicy.Handler<?>) handler).getEntity();
+            }
+            else            if (handler instanceof CurrentWrapperPolicy.CurrentWrapperHandler) {
+                domainObject = ((CurrentWrapperPolicy.CurrentWrapperHandler<?>) handler).getEntity();
+            }
+        }
+        return session.getClassDescriptor(domainObject);
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/EditionClassWriter.java b/Temporal Entity Example/src/temporal/persistence/EditionClassWriter.java
new file mode 100644
index 0000000..f03c35d
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/EditionClassWriter.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import static org.eclipse.persistence.internal.dynamic.DynamicPropertiesManager.PROPERTIES_MANAGER_FIELD;
+
+import java.lang.reflect.Modifier;
+
+import org.eclipse.persistence.dynamic.DynamicClassLoader;
+import org.eclipse.persistence.dynamic.DynamicClassWriter;
+import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
+import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
+import org.eclipse.persistence.internal.libraries.asm.Opcodes;
+
+/**
+ * Custom {@link DynamicClassWriter} used to creat edition class with additional
+ * interface.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionClassWriter extends DynamicClassWriter implements Opcodes {
+    
+    private Class<?> editionInterface;
+    
+    public EditionClassWriter(@SuppressWarnings("rawtypes") Class parentClass, Class<?> editionInterface) {
+        super(parentClass);
+        this.editionInterface = editionInterface;
+    }
+
+    public byte[] writeClass(DynamicClassLoader loader, String className) throws ClassNotFoundException {
+
+        Class<?> parent = getParentClass(loader);
+        parentClassName = parent.getName();
+        if (parent == null || parent.isPrimitive() || parent.isArray() || parent.isEnum() || parent.isInterface() || Modifier.isFinal(parent.getModifiers())) {
+            throw new IllegalArgumentException("Invalid parent class: " + parent);
+        }
+        String parentClassNameAsSlashes = parentClassName.replace('.', '/');
+        String classNameAsSlashes = className.replace('.', '/');
+        String editionInterfaceName = this.editionInterface.getName().replace('.', '/');
+        
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+
+        // public class Foo extends DynamicEntityImpl {
+        cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, classNameAsSlashes, null, parentClassNameAsSlashes, new String[] {editionInterfaceName});
+
+        // public static DynamicPropertiesManager DPM = new
+        // DynamicPropertiesManager();
+        cw.visitField(ACC_PUBLIC + ACC_STATIC, PROPERTIES_MANAGER_FIELD, "L" + DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";", null, null);
+        MethodVisitor mv = cw.visitMethod(ACC_STATIC, CLINIT, "()V", null, null);
+        mv.visitTypeInsn(NEW, DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES);
+        mv.visitInsn(DUP);
+        mv.visitMethodInsn(INVOKESPECIAL, DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES, INIT, "()V");
+        mv.visitFieldInsn(PUTSTATIC, classNameAsSlashes, PROPERTIES_MANAGER_FIELD, "L" + DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";");
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+
+        // public Foo() {
+        // super();
+        // }
+        mv = cw.visitMethod(ACC_PUBLIC, INIT, "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, parentClassNameAsSlashes, INIT, "()V");
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+
+        mv = cw.visitMethod(ACC_PUBLIC, "fetchPropertiesManager", "()L" + DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";", null, null);
+        mv.visitFieldInsn(GETSTATIC, classNameAsSlashes, PROPERTIES_MANAGER_FIELD, "L" + DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";");
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+
+        cw.visitEnd();
+        return cw.toByteArray();
+
+    }
+
+    private Class<?> getParentClass(ClassLoader loader) throws ClassNotFoundException {
+        if (parentClass == null && parentClassName != null) {
+            parentClass = loader.loadClass(parentClassName);
+        }
+        return parentClass;
+    }
+
+
+    public byte[] writeInterface() {
+        ClassWriter cw = new ClassWriter(0);
+
+        cw.visit(51, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "tests/internal/asm/PersonEdition", null, "java/lang/Object", new String[] { "model/Person" });
+
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/EditionInterfaceClassWriter.java b/Temporal Entity Example/src/temporal/persistence/EditionInterfaceClassWriter.java
new file mode 100644
index 0000000..ce811b8
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/EditionInterfaceClassWriter.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import java.lang.reflect.Modifier;
+
+import org.eclipse.persistence.dynamic.DynamicClassLoader;
+import org.eclipse.persistence.dynamic.DynamicClassWriter;
+import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
+import org.eclipse.persistence.internal.libraries.asm.Opcodes;
+
+/**
+ * Custom {@link DynamicClassWriter} used to creat edition class with additional
+ * interface.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionInterfaceClassWriter extends DynamicClassWriter implements Opcodes {
+
+    public EditionInterfaceClassWriter(Class<?> parentInterface) {
+        super(parentInterface);
+    }
+
+    public byte[] writeClass(DynamicClassLoader loader, String className) throws ClassNotFoundException {
+
+        Class<?> parent = getParentClass(loader);
+        parentClassName = parent.getName();
+        if (parent == null || parent.isPrimitive() || parent.isArray() || parent.isEnum() || !parent.isInterface() || Modifier.isFinal(parent.getModifiers())) {
+            throw new IllegalArgumentException("Invalid parent interface: " + parent);
+        }
+        String classNameAsSlashes = className.replace('.', '/');
+        String parentClassNameAsSlashes = parentClassName.replace('.', '/');
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+
+        // public class Foo extends DynamicEntityImpl {
+        cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, classNameAsSlashes, null, "java/lang/Object", new String[] { parentClassNameAsSlashes });
+
+        cw.visitEnd();
+        return cw.toByteArray();
+
+    }
+
+    private Class<?> getParentClass(ClassLoader loader) throws ClassNotFoundException {
+        if (parentClass == null && parentClassName != null) {
+            parentClass = loader.loadClass(parentClassName);
+        }
+        return parentClass;
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/EditionSetEventListener.java b/Temporal Entity Example/src/temporal/persistence/EditionSetEventListener.java
new file mode 100644
index 0000000..84a0514
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/EditionSetEventListener.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import org.eclipse.persistence.config.DescriptorCustomizer;
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.descriptors.DescriptorEvent;
+import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
+import org.eclipse.persistence.descriptors.DescriptorEventListener;
+import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet;
+
+import temporal.EditionSet;
+import temporal.EditionSetEntry;
+import temporal.TemporalHelper;
+
+/**
+ * Listener which adds the modified attributes to
+ * {@link EditionSetEntry#getAttributes()} during the
+ * {@link DescriptorEventListener#preWrite(DescriptorEvent)} event. This
+ * provides the {@link EditionSetEntry} with a set of attribute names that were
+ * modified.
+ * <p>
+ * This listener relies on the fact that all new editions are first flushed to
+ * the database before any changes are made. If this does not happen then there
+ * is no {@link ObjectChangeSet} for the new edition instance and thus the
+ * attributes modified are not known.
+ * 
+ * @see TemporalHelper#createEdition(javax.persistence.EntityManager,
+ *      temporal.TemporalEntity)
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionSetEventListener extends DescriptorEventAdapter implements DescriptorCustomizer {
+
+    /**
+     * Listener enabled through the use of {@link DescriptorCustomizer}
+     * 
+     * @see EditionSet - @Customizer(EditionSetEventListener.class)
+     */
+    @Override
+    public void customize(ClassDescriptor descriptor) throws Exception {
+        descriptor.getEventManager().addListener(this);
+    }
+
+    @Override
+    public void preWrite(DescriptorEvent event) {
+        EditionSet es = (EditionSet) event.getSource();
+        RepeatableWriteUnitOfWork uow = (RepeatableWriteUnitOfWork) event.getSession();
+        UnitOfWorkChangeSet uowCS = (UnitOfWorkChangeSet) uow.getUnitOfWorkChangeSet();
+
+        if (es.hasEntries() && uowCS.hasChanges()) {
+            for (EditionSetEntry entry : es.getEntries()) {
+                ObjectChangeSet objCS = uowCS.getCloneToObjectChangeSet().get(entry.getTemporal());
+                if (objCS != null && objCS.hasChanges()) {
+                    for (String attr : objCS.getChangedAttributeNames()) {
+                        entry.addAttribute(attr);
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/EditionWrapperPolicy.java b/Temporal Entity Example/src/temporal/persistence/EditionWrapperPolicy.java
new file mode 100644
index 0000000..1a6add6
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/EditionWrapperPolicy.java
@@ -0,0 +1,135 @@
+package temporal.persistence;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.descriptors.WrapperPolicy;
+import org.eclipse.persistence.exceptions.DescriptorException;
+import org.eclipse.persistence.internal.descriptors.PersistenceObject;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.queries.FetchGroupTracker;
+import org.eclipse.persistence.sessions.Session;
+
+import temporal.EditionSetEntry;
+import temporal.TemporalEdition;
+import temporal.TemporalEntity;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+
+public class EditionWrapperPolicy implements WrapperPolicy {
+    private static final long serialVersionUID = 1L;
+
+    private AbstractSession session;
+
+    private ClassDescriptor descriptor;
+
+    @Override
+    public void initialize(AbstractSession session) throws DescriptorException {
+        this.session = session;
+    }
+
+    public AbstractSession getSession() {
+        return session;
+    }
+
+    @Override
+    public boolean isTraversable() {
+        return true;
+    }
+
+    @Override
+    public boolean isWrapped(Object object) {
+        return Proxy.isProxyClass(object.getClass());
+    }
+
+    @Override
+    public void setDescriptor(ClassDescriptor descriptor) {
+        this.descriptor = descriptor;
+    }
+
+    public ClassDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    public Object unwrapObject(Object proxy, AbstractSession session) {
+        Handler<?> handler = (Handler<?>) Proxy.getInvocationHandler(proxy);
+        return handler.getEntity();
+    }
+
+    @Override
+    public Object wrapObject(Object original, AbstractSession session) {
+        Class<?> wrapperInterface = (Class<?>) getDescriptor().getProperty(TemporalHelper.INTERFACE);
+        Handler<?> handler = new Handler<TemporalEntity<?>>((TemporalEntity<?>) original);
+        return Proxy.newProxyInstance(getSession().getLoader(), new Class[] { wrapperInterface, TemporalEdition.class, PersistenceObject.class, FetchGroupTracker.class }, handler);
+    }
+
+    public class Handler<T extends TemporalEntity<?>> implements InvocationHandler, TemporalEdition<T> {
+
+        /**
+         * The original edition being used by the client. This edition will not
+         * be changed with the exception of the end effectivity time if a new
+         * edition is created.
+         */
+        private T entity;
+
+        /**
+         * 
+         */
+        private TemporalEntityManager entityManager;
+
+        private Map<String, Object[]> changes;
+
+        public Handler(T entity) {
+            this.entity = entity;
+            this.changes = new HashMap<String, Object[]>();
+        }
+
+        public T getEntity() {
+            return this.entity;
+        }
+
+        public TemporalEntityManager getEntityManager() {
+            if (this.entityManager == null && getEntity() instanceof FetchGroupTracker) {
+                Session session = ((FetchGroupTracker) getEntity())._persistence_getSession();
+                if (session != null) {
+                    this.entityManager = TemporalEntityManager.getInstance(session);
+                }
+            }
+            return entityManager;
+        }
+
+        public void setEntityManager(TemporalEntityManager entityManager) {
+            this.entityManager = entityManager;
+        }
+
+        public Map<String, Object[]> getChanges() {
+            return changes;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (method.getDeclaringClass() == TemporalEdition.class) {
+                return method.invoke(this, args);
+            }
+
+            return method.invoke(getEntity(), args);
+        }
+
+        public boolean hasChanges() {
+            return !getChanges().isEmpty();
+        }
+
+        @Override
+        public EditionSetEntry getEditionSetEntry() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/PropagateEditionChangesListener.java b/Temporal Entity Example/src/temporal/persistence/PropagateEditionChangesListener.java
new file mode 100644
index 0000000..acbe83e
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/PropagateEditionChangesListener.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.descriptors.changetracking.ChangeTracker;
+import org.eclipse.persistence.expressions.Expression;
+import org.eclipse.persistence.expressions.ExpressionBuilder;
+import org.eclipse.persistence.internal.sessions.ChangeRecord;
+import org.eclipse.persistence.internal.sessions.DirectToFieldChangeRecord;
+import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet;
+import org.eclipse.persistence.queries.ReadAllQuery;
+import org.eclipse.persistence.sessions.SessionEvent;
+import org.eclipse.persistence.sessions.SessionEventAdapter;
+
+import temporal.EditionSet;
+import temporal.EditionSetEntry;
+import temporal.TemporalEntity;
+import temporal.TemporalEntityManager;
+
+/**
+ * During the initial phases of a commit this listener will look at all proposed
+ * edition changes and propagate them through all future editions applying the
+ * change if that future edition has the same old value as this edition did
+ * before the change.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class PropagateEditionChangesListener extends SessionEventAdapter {
+
+    @Override
+    public void preCalculateUnitOfWorkChangeSet(SessionEvent event) {
+        RepeatableWriteUnitOfWork uow = (RepeatableWriteUnitOfWork) event.getSession();
+        UnitOfWorkChangeSet uowCS = (UnitOfWorkChangeSet) uow.getUnitOfWorkChangeSet();
+        TemporalEntityManager tem = TemporalEntityManager.getInstance(uow);
+        EditionSet es = tem.getEditionSet();
+
+        if (es != null && es.hasEntries() && uowCS.hasChanges()) {
+            for (EditionSetEntry entry : es.getEntries()) {
+                ObjectChangeSet objCS = uowCS.getCloneToObjectChangeSet().get(entry.getTemporal());
+                List<TemporalEntity<?>> futures = findFutureEditions(uow, entry);
+
+                if (objCS != null && objCS.hasChanges() && futures != null) {
+                    for (String attr : objCS.getChangedAttributeNames()) {
+                        ChangeRecord cr = (ChangeRecord) objCS.getAttributesToChanges().get(attr);
+                        entry.getAttributes().add(attr);
+
+                        propogateChanges(uow, futures, entry, cr);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Find all of the future EditionView instances ordered by the start time.
+     * These will be used to propagate changes. A native expression query is
+     * used since we are already under the JPA layer.
+     */
+    @SuppressWarnings("unchecked")
+    private List<TemporalEntity<?>> findFutureEditions(RepeatableWriteUnitOfWork uow, EditionSetEntry entry) {
+        ClassDescriptor desc = uow.getClassDescriptor(entry.getTemporal());
+        desc = (ClassDescriptor) desc.getProperty(DescriptorHelper.EDITION_VIEW);
+
+        if (desc != null) {
+            ReadAllQuery raq = new ReadAllQuery(desc.getJavaClass());
+            ExpressionBuilder eb = raq.getExpressionBuilder();
+            Expression cidExp = eb.get("cid").equal(entry.getTemporalEntity().getContinuity().getId());
+            Expression startExp = eb.get("effectivity").get("start");
+            Expression futureExp = startExp.greaterThan(entry.getEditionSet().getEffective());
+            raq.setSelectionCriteria(cidExp.and(futureExp));
+            raq.addOrdering(startExp.ascending());
+            raq.getContainerPolicy().setContainerClass(ArrayList.class);
+
+            return (List<TemporalEntity<?>>) uow.executeQuery(raq);
+        }
+        return null;
+    }
+
+    /**
+     * Carry and changes forward through future editions that
+     */
+    private void propogateChanges(RepeatableWriteUnitOfWork uow, List<TemporalEntity<?>> futures, EditionSetEntry entry, ChangeRecord record) {
+        if (!futures.isEmpty() && !(record instanceof DirectToFieldChangeRecord)) {
+            throw new UnsupportedOperationException("Only direct mapping changes can be propagated");
+        }
+
+        for (TemporalEntity<?> future : futures) {
+            Object newValue = record.getMapping().getRealAttributeValueFromObject(entry.getTemporal(), uow);
+            Object futureValue = record.getMapping().getRealAttributeValueFromObject(future, uow);
+
+            if ((futureValue == null && record.getOldValue() == null) || futureValue.equals(record.getOldValue())) {
+                record.getMapping().setRealAttributeValueInObject(future, newValue);
+                if (future instanceof ChangeTracker) {
+                    ((ChangeTracker) future)._persistence_getPropertyChangeListener().propertyChange(new PropertyChangeEvent(future, record.getAttribute(), record.getOldValue(), newValue));
+                }
+            } else {
+                // Stop propagating when you hit the first non-match
+                return;
+            }
+        }
+    }
+
+}
diff --git a/Temporal Entity Example/src/temporal/persistence/TemporalSchemaManager.java b/Temporal Entity Example/src/temporal/persistence/TemporalSchemaManager.java
new file mode 100644
index 0000000..9070bfd
--- /dev/null
+++ b/Temporal Entity Example/src/temporal/persistence/TemporalSchemaManager.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package temporal.persistence;
+
+import java.util.Iterator;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.mappings.DirectCollectionMapping;
+import org.eclipse.persistence.sessions.Project;
+import org.eclipse.persistence.sessions.server.Server;
+import org.eclipse.persistence.tools.schemaframework.DefaultTableGenerator;
+import org.eclipse.persistence.tools.schemaframework.ForeignKeyConstraint;
+import org.eclipse.persistence.tools.schemaframework.SchemaManager;
+import org.eclipse.persistence.tools.schemaframework.TableCreator;
+import org.eclipse.persistence.tools.schemaframework.TableDefinition;
+
+import temporal.TemporalHelper;
+
+/**
+ * TODO
+ *
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class TemporalSchemaManager extends SchemaManager {
+
+    public TemporalSchemaManager(Server session) {
+        super(session);
+    }
+
+    protected TableCreator getDefaultTableCreator(boolean generateFKConstraints) {
+        if (defaultTableCreator == null) {
+            defaultTableCreator = new TemporalTableGenerator(session.getProject(), generateFKConstraints).generateDefaultTableCreator();
+            // defaultTableCreator.setIgnoreDatabaseException(true);
+            fixTemporalFKConstraints();
+        }
+        return defaultTableCreator;
+    }
+    
+    public TableCreator getTableCreator() {
+        return defaultTableCreator;
+    }
+
+    public TableDefinition getTableDefinition(String tableName) {
+        for (@SuppressWarnings("unchecked")
+        Iterator<Object> i = getTableCreator().getTableDefinitions().iterator(); i.hasNext();) {
+            TableDefinition td = (TableDefinition) i.next();
+            
+            if (td.getName().equals(tableName)) {
+                return td;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Replace all FK constraints referencing CID with OID
+     */
+    private void fixTemporalFKConstraints() {
+        for (ClassDescriptor desc: getSession().getDescriptors().values()) {
+            if (desc.getTableName() != null &&  TemporalHelper.isTemporal(desc.getJavaClass(), true)) {
+                TableDefinition td = getTableDefinition(desc.getTableName());
+                for (ForeignKeyConstraint fkc: td.getForeignKeys()) {
+                    if (fkc.getTargetFields().size() == 1 && fkc.getTargetFields().get(0).equals("CID")) {
+                        fkc.getTargetFields().set(0, "OID");
+                    }
+                }
+            }
+        }
+    }
+    
+
+    class TemporalTableGenerator extends DefaultTableGenerator {
+
+        public TemporalTableGenerator(Project project, boolean generateFKConstraints) {
+            super(project, generateFKConstraints);
+        }
+
+        /**
+         * Build direct collection table definitions in a EclipseLink descriptor
+         */
+        protected void buildDirectCollectionTableDefinition(DirectCollectionMapping mapping, ClassDescriptor descriptor) {
+            TableDefinition tableDefinition = this.tableMap.get(mapping.getReferenceTable().getName());
+            
+            if (tableDefinition == null) {
+                super.buildDirectCollectionTableDefinition(mapping, descriptor);
+            }
+
+        }
+
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/AllTests.java b/Temporal Entity Example/test-src/tests/AllTests.java
new file mode 100644
index 0000000..1f0a617
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/AllTests.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({ tests.internal.AllTests.class, 
+                FullPersonWithEditions.class, 
+                FuturePersonTests.class,
+                DeleteTests.class,
+                ProxyWrapperUpdateTests.class,
+                //ModifyCurrentTests.class})
+                //DeleteContinuityTests.class,
+                MultipleEditionQueries.class,
+                DuplicateInsertOnCreateMerge.class,
+                tests.editionsets.AllTests.class})
+public class AllTests {
+}
diff --git a/Temporal Entity Example/test-src/tests/BaseTestCase.java b/Temporal Entity Example/test-src/tests/BaseTestCase.java
new file mode 100644
index 0000000..e9d09f5
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/BaseTestCase.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.eclipse.persistence.jpa.JpaHelper;
+import org.eclipse.persistence.sessions.server.Server;
+import org.eclipse.persistence.tools.schemaframework.SchemaManager;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+
+import temporal.TemporalEntityManager;
+import temporal.persistence.TemporalSchemaManager;
+
+/**
+ * 
+ * @author dclarke
+ * @Since EclipseLink 2.3.1
+ */
+public abstract class BaseTestCase {
+
+    private static EntityManagerFactory emf;
+
+    private TemporalEntityManager entityManager;
+
+    @Rule
+    public TestName testName = new TestName();
+
+    public EntityManagerFactory getEMF() {
+        if (emf == null) {
+            emf = Persistence.createEntityManagerFactory("example");
+
+            Server session = JpaHelper.getServerSession(emf);
+
+            SchemaManager sm = new TemporalSchemaManager(session);
+            // Cache SchemaManager so it can be verified in test cases
+            session.setProperty(SchemaManager.class.getName(), sm);
+            sm.replaceDefaultTables(false, true);
+            sm.replaceSequences();
+
+            // Populate test case example instances
+            TemporalEntityManager em = TemporalEntityManager.getInstance(emf.createEntityManager());
+            em.getTransaction().begin();
+            populate(em);
+            em.getTransaction().commit();
+            em.close();
+            System.out.println("\n--- CREATE EMF & POPULATE DONE ---\n");
+
+            closeEntityManager();
+        }
+        return emf;
+    }
+
+    public TemporalEntityManager getEntityManager() {
+        return getEntityManager(null);
+    }
+
+    public TemporalEntityManager getEntityManager(Long effectiveTime) {
+        if (this.entityManager == null || !this.entityManager.isOpen()) {
+            TemporalEntityManager em = TemporalEntityManager.getInstance(getEMF().createEntityManager());
+            em.setEffectiveTime(effectiveTime, false);
+            this.entityManager = em;
+        }
+        return this.entityManager;
+    }
+
+    public void populate(TemporalEntityManager em) {
+    }
+
+    @AfterClass
+    public static void closeEMF() {
+        if (emf != null && emf.isOpen()) {
+            emf.close();
+        }
+        emf = null;
+    }
+
+    @Before
+    public void logTestName() {
+        System.out.println("\n\nTEST: " + testName.getMethodName() + "\n");
+    }
+
+    /**
+     * After each test case ensure the {@link EntityManager} is closed and if a
+     * transaction is active roll it back first.
+     */
+    @After
+    public void closeEntityManager() {
+        if (this.entityManager != null && this.entityManager.isOpen()) {
+            if (this.entityManager.getTransaction().isActive()) {
+                this.entityManager.getTransaction().rollback();
+            }
+            this.entityManager.close();
+        }
+        this.entityManager = null;
+        if (emf != null && emf.isOpen()) {
+            JpaHelper.getServerSession(emf).getIdentityMapAccessor().initializeAllIdentityMaps();
+        }
+
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/CustomerScenarios.java b/Temporal Entity Example/test-src/tests/CustomerScenarios.java
new file mode 100644
index 0000000..cfba216
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/CustomerScenarios.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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:
+ *      dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+
+package tests;
+
+import static example.PersonModelExample.T1;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T3;
+import static example.PersonModelExample.T4;
+
+import java.util.List;
+
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+import model.entities.AddressEntity;
+import model.entities.PhoneEntity;
+
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+
+/**
+ * TODO
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class CustomerScenarios extends BaseTestCase {
+
+    @Test
+    public void createPersonAndAddressNow() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+
+        Person p = em.newEntity(Person.class);
+        p.setName("Now");
+        Address a = new AddressEntity("now", "now", "now");
+        p.setAddress(a);
+
+        em.persist(p);
+
+        em.getTransaction().commit();
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+        System.out.println("\nREAD:\n");
+
+        Person readP = em.find(Person.class, p.getId());
+
+        Assert.assertEquals(p.getName(), readP.getName());
+        Assert.assertEquals("now", readP.getAddress().getCity());
+    }
+
+    @Test
+    public void createPersonAndAddressFuture() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2, true);
+
+        em.getTransaction().begin();
+
+        Person p = em.newEntity( Person.class);
+        p.setName("Future");
+        Address a = em.newEntity( Address.class);
+        a.setCity("t2");
+        p.setAddress(a);
+
+        em.persist(p);
+
+        em.getTransaction().commit();
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+        System.out.println("\nREAD:\n");
+
+        Person readP = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + p.getId(), Person.class).getSingleResult();
+
+        Assert.assertEquals(p.getName(), readP.getName());
+        Assert.assertEquals("t2", readP.getAddress().getCity());
+    }
+
+    @Test
+    public void createPersonInFutureWithOldAddress() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+        Address a = new AddressEntity("now", "now", "now");
+        em.persist(a);
+        em.flush();
+
+        em.setEffectiveTime(T2, true);
+
+        Person p = em.newEntity( Person.class);
+        p.setName("Future");
+        p.setAddress(a);
+
+        em.persist(p);
+
+        em.getTransaction().commit();
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+        System.out.println("\nREAD:\n");
+
+        em.setEffectiveTime(T1, false);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.address.city = 'now'", Person.class).getResultList();
+        Assert.assertTrue(results.isEmpty());
+
+        em.setEffectiveTime(T2, false);
+        Person readP = em.createQuery("SELECT p FROM Person p JOIN FETCH p.address WHERE p.address.city = 'now'", Person.class).getSingleResult();
+
+        Assert.assertNotNull(readP);
+        Assert.assertNotNull(readP.getAddress());
+        Assert.assertEquals(p.getName(), readP.getName());
+        Assert.assertEquals("now", readP.getAddress().getCity());
+    }
+
+    @Test
+    public void createPersonInFutureWithOldPhone() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+        Phone phone_BOT = new PhoneEntity("work", "000-000-0000");
+        em.persist(phone_BOT);
+        em.flush();
+
+        em.setEffectiveTime(T2, true);
+
+        Person p = em.newEntity( Person.class);
+        p.setName("Future");
+        em.persist(p);
+
+        em.setEffectiveTime(T3, true);
+
+        Phone phone_T3 = em.newEdition(phone_BOT);
+        phone_T3.setNumber("333-333-3333");
+        p.addPhone(phone_T3);
+        em.persist(phone_T3);
+        em.getTransaction().commit();
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+
+        System.out.println("\nREAD:\n");
+
+        em.setEffectiveTime(T1);
+        Person readP_T1 = em.find(Person.class, p.getId());
+        System.out.println("Read Person @ T1: " + readP_T1);
+
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+
+        em.setEffectiveTime(T2);
+        Person readP_T2 = em.find(Person.class, p.getId());
+        System.out.println("Read Person @ T2: " + readP_T2 + " Phone: " + readP_T2.getPhone("work"));
+        Phone readPhone_T2 = em.find(Phone.class, phone_BOT.getId());
+        System.out.println("Read Phone @ T2: " + readPhone_T2);
+
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+
+        em.setEffectiveTime(T3);
+        Person readP_T3 = em.find(Person.class, p.getId());
+        System.out.println("Read Person @ T3: " + readP_T3 + " Phone: " + readP_T3.getPhone("work"));
+
+        em.clear();
+        em.getEntityManagerFactory().getCache().evictAll();
+
+        em.setEffectiveTime(T4);
+        Person readP_T4 = em.find(Person.class, p.getId());
+        System.out.println("Read Person @ T4: " + readP_T4 + " Phone: " + readP_T4.getPhone("work"));
+
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/DeleteContinuityTests.java b/Temporal Entity Example/test-src/tests/DeleteContinuityTests.java
new file mode 100644
index 0000000..608e5d4
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/DeleteContinuityTests.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+import model.Address;
+import model.Person;
+import model.Phone;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * TODO
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class DeleteContinuityTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void test() {
+        getSample();
+        Assert.fail("NOT YET IMPLEMENTED");
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nFullPersonWithEditions.populate:START");
+
+        example.populateHobbies(em);
+        em.persist(example.fullPerson);
+        em.flush();
+
+        System.out.println("\n> Create T2 Edition");
+        em.setEffectiveTime( T2, true);
+
+        Person fpEdition = em.find(Person.class, example.fullPerson.getId());
+        Person personEditionT2 = em.newEdition( fpEdition);
+        personEditionT2.setName("Jimmy");
+        Address aT2 = em.newEdition( example.fullPerson.getAddress());
+        aT2.setCity("Toronto");
+        aT2.setState("ON");
+        personEditionT2.setAddress(aT2);
+        Phone pT2 = em.newEdition( example.fullPerson.getPhone("Home"));
+        personEditionT2.addPhone(pT2);
+        pT2.setNumber("222-222-2222");
+        em.persist(personEditionT2.addHobby(example.hobbies.get("golf"), T2));
+        em.flush();
+
+        System.out.println("\n> Create T4 Edition");
+        em.setEffectiveTime( T4, true);
+
+        Person personEditionT4 = em.newEdition( personEditionT2);
+        personEditionT4.setName("James");
+        Address aT4 = em.newEdition( aT2);
+        aT4.setCity("San Francisco");
+        aT4.setState("CA");
+        personEditionT4.setAddress(aT4);
+        Phone pT4 = em.newEdition( pT2);
+        pT4.setNumber("444-444-4444");
+        personEditionT4.addPhone(pT4);
+        personEditionT4.removeHobby(example.hobbies.get(GOLF), T4, T4);
+        personEditionT4.addHobby(example.hobbies.get("running"), T4);
+        personEditionT4.addHobby(example.hobbies.get("skiing"), T4);
+        em.flush();
+
+        System.out.println("\nFullPersonWithEditions.populate::DONE");
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/DeleteTests.java b/Temporal Entity Example/test-src/tests/DeleteTests.java
new file mode 100644
index 0000000..51c0f43
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/DeleteTests.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.T1;
+
+import javax.persistence.EntityManager;
+
+import model.Person;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+import temporal.EditionWrapperHelper;
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * Tests to verify delete use cases. In this temporal usage delete is equivalent
+ * to setting the end date to a point in time in the future. Then any queries
+ * after that time result in no edition being returned.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class DeleteTests extends BaseTestCase {
+
+    private static PersonModelExample examples = new PersonModelExample();
+
+    @Test
+    public void deleteCurrentSimple() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+        em.persist(examples.simplePerson);
+        em.getTransaction().commit();
+        closeEntityManager();
+        
+        em = getEntityManager();
+            
+        Assert.assertEquals(1,  em.createQuery("SELECT COUNT(p) FROM Person p", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(a) FROM Address a", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Phone p", Number.class).getSingleResult().intValue());
+        Person p = em.createQuery("SELECT p FROM Person p", Person.class).getSingleResult();
+        
+        Assert.assertNotNull(p);
+        
+        em.getTransaction().begin();
+        em.remove(p);
+        em.getTransaction().commit();
+        
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Person p", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(a) FROM Address a", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Phone p", Number.class).getSingleResult().intValue());
+    }
+
+    @Test
+    public void deleteCurrentSimpleAtT1() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+        em.persist(examples.simplePerson);
+        em.getTransaction().commit();
+        closeEntityManager();
+        
+        em = getEntityManager();
+            
+        Assert.assertEquals(1,  em.createQuery("SELECT COUNT(p) FROM Person p", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(a) FROM Address a", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Phone p", Number.class).getSingleResult().intValue());
+        Person p = em.createQuery("SELECT p FROM Person p", Person.class).getSingleResult();
+        
+        Assert.assertNotNull(p);
+        
+        em.getTransaction().begin();
+
+        Person pWrapper = EditionWrapperHelper.wrap(em, p);
+        pWrapper.getEffectivity().setEnd(T1);
+        
+        em.getTransaction().commit();
+        
+        Assert.assertEquals(1,  em.createQuery("SELECT COUNT(p) FROM Person p", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(a) FROM Address a", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Phone p", Number.class).getSingleResult().intValue());
+
+        em.setEffectiveTime( T1);
+        
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Person p", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(a) FROM Address a", Number.class).getSingleResult().intValue());
+        Assert.assertEquals(0,  em.createQuery("SELECT COUNT(p) FROM Phone p", Number.class).getSingleResult().intValue());
+    }
+
+    @After
+    public void deleteAll() {
+        EntityManager em = TemporalEntityManager.getInstance(getEMF().createEntityManager());
+        em.getTransaction().begin();
+        em.createQuery("DELETE FROM PersonHobby ph").executeUpdate();
+        em.createQuery("DELETE FROM Hobby h").executeUpdate();
+        em.createNativeQuery("DELETE FROM TADDRESS").executeUpdate();
+        em.createNativeQuery("DELETE FROM TPERSON_NNAMES").executeUpdate();
+        em.createNativeQuery("UPDATE TPERSON SET CID = NULL").executeUpdate();
+        em.createNativeQuery("DELETE FROM TPERSON").executeUpdate();
+        em.createNativeQuery("DELETE FROM TPHONE").executeUpdate();
+        em.getTransaction().commit();
+        em.close();
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/DuplicateInsertOnCreateMerge.java b/Temporal Entity Example/test-src/tests/DuplicateInsertOnCreateMerge.java
new file mode 100644
index 0000000..9b4ff1b
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/DuplicateInsertOnCreateMerge.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SKI;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * Test cases dealing with potential duplicate insert scenarios
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class DuplicateInsertOnCreateMerge extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nFullPersonWithEditions.populate:START");
+
+        example.populateHobbies(em);
+        em.persist(getSample());
+        em.flush();
+
+        System.out.println("\nFullPersonWithEditions.populate::DONE");
+    }
+
+    public Person createPersonEditionAtT2(TemporalEntityManager em) {
+        em.setEffectiveTime( T2, true);
+
+        Person fpEdition = em.find(Person.class, getSample().getId());
+        Person personEditionT2 = fpEdition;
+
+        if (personEditionT2.getEffectivity().getStart() != T2) {
+            personEditionT2 = em.newEdition( fpEdition);
+            personEditionT2.setName("Jimmy");
+            Address aT2 = em.newEdition( fpEdition.getAddress());
+            aT2.setCity("Toronto");
+            aT2.setState("ON");
+            personEditionT2.setAddress(aT2);
+            Phone originalPhone = fpEdition.getPhone("Home");
+
+            Phone pT2 = em.newEdition( originalPhone);
+            personEditionT2.addPhone(pT2);
+            pT2.setNumber("222-222-2222");
+            em.persist(personEditionT2.addHobby(example.hobbies.get(GOLF), T2));
+        } else {
+            personEditionT2.getAddress();
+            personEditionT2.getPhones().size();
+        }
+        return personEditionT2;
+    }
+
+    @Test
+    public void createPersonAtT2AndMerge() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime( T2, true);
+        em.getTransaction().begin();
+
+        Person personEditionT2 = createPersonEditionAtT2(em);
+
+        Assert.assertNotNull(personEditionT2);
+        Assert.assertEquals(T2, personEditionT2.getEffectivity().getStart());
+        Assert.assertNotNull(personEditionT2.getPhone("Home"));
+
+        // XXX
+        em.merge(personEditionT2);
+
+        em.getTransaction().commit();
+
+        em.clear();
+        personEditionT2 = em.find(Person.class, getSample().getId());
+
+        Assert.assertNotNull(personEditionT2);
+        Assert.assertEquals(T2, personEditionT2.getEffectivity().getStart());
+        Phone pT2 = personEditionT2.getPhone("Home");
+        Assert.assertNotNull(pT2);
+    }
+
+    @Test
+    public void createPersonAtT4AndMerge() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+        Person personEditionT2 = createPersonEditionAtT2(em);
+        Assert.assertNotNull(personEditionT2);
+        Assert.assertEquals(T2, personEditionT2.getEffectivity().getStart());
+        Assert.assertNotNull(personEditionT2.getPhone("Home"));
+
+        em.setEffectiveTime( T4, true);
+
+        Person personEditionT4 = em.newEdition( personEditionT2);
+        personEditionT4.setName("James");
+        Address aT4 = em.newEdition( personEditionT4.getAddress());
+        aT4.setCity("San Francisco");
+        aT4.setState("CA");
+        personEditionT4.setAddress(aT4);
+        Phone pT4 = em.newEdition( personEditionT4.getPhone("Home"));
+        pT4.setNumber("444-444-4444");
+        personEditionT4.addPhone(pT4);
+        personEditionT4.removeHobby(example.hobbies.get(GOLF), T4, T4);
+        em.persist(personEditionT4.addHobby(example.hobbies.get(RUN), T4));
+        em.persist(personEditionT4.addHobby(example.hobbies.get(SKI), T4));
+
+        em.merge(personEditionT4);
+        em.getTransaction().commit();
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/FullPersonWithEditions.java b/Temporal Entity Example/test-src/tests/FullPersonWithEditions.java
new file mode 100644
index 0000000..17a29c5
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/FullPersonWithEditions.java
@@ -0,0 +1,798 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SKI;
+import static example.PersonModelExample.T1;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T3;
+import static example.PersonModelExample.T4;
+import static example.PersonModelExample.T5;
+import static temporal.Effectivity.BOT;
+import static temporal.Effectivity.EOT;
+
+import java.sql.Date;
+import java.util.List;
+
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+
+import model.Address;
+import model.Person;
+import model.Phone;
+import model.entities.PhoneEntity;
+
+import org.eclipse.persistence.jpa.JpaHelper;
+import org.eclipse.persistence.sessions.CopyGroup;
+import org.junit.Assert;
+import org.junit.Test;
+
+import temporal.BaseEntity;
+import temporal.EditionSet;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+import example.PersonModelExample;
+
+/**
+ * This test case performs current and edition queries on a simple
+ * Person-Address-Phones model both illustrating and verifying query operations.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class FullPersonWithEditions extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nFullPersonWithEditions.populate:START");
+
+        example.populateHobbies(em);
+        em.persist(example.fullPerson);
+        em.flush();
+
+        System.out.println("\n> Create T2 Edition");
+        em.setEffectiveTime(T2, true);
+
+        Person fpEdition = em.find(Person.class, example.fullPerson.getId());
+        Person personEditionT2 = em.newEdition(fpEdition);
+
+        personEditionT2.setName("Jimmy");
+        Address aT2 = em.newEdition(example.fullPerson.getAddress());
+        aT2.setCity("Toronto");
+        aT2.setState("ON");
+        personEditionT2.setDateOfBirth(new Date(75, 1, 5));
+
+        personEditionT2.setAddress(aT2);
+        Phone pT2 = em.newEdition(example.fullPerson.getPhone("Home"));
+        personEditionT2.addPhone(pT2);
+        pT2.setNumber("222-222-2222");
+        Phone pWT2 = em.newEntity(PhoneEntity.class);
+        pWT2.setType("Work");
+        pWT2.setNumber("333-333-3333");
+        personEditionT2.addPhone(pWT2);
+
+        em.persist(personEditionT2.addHobby(example.hobbies.get(GOLF), T2));
+
+        // Assert.assertEquals(personEditionT2.getPhones().size() - 1,
+        // fpEdition.getPhones().size());
+        // Assert.assertEquals(personEditionT2.getPersonHobbies().size() - 1,
+        // fpEdition.getPersonHobbies().size());
+
+        em.flush();
+
+        System.out.println("\n> Create T4 Edition");
+        em.setEffectiveTime(T4, true);
+
+        Person personEditionT4 = em.newEdition(personEditionT2);
+        personEditionT4.setName("James");
+        Address aT4 = em.newEdition(aT2);
+        aT4.setCity("San Francisco");
+        aT4.setState("CA");
+        personEditionT4.setAddress(aT4);
+
+        Phone pT4 = em.newEdition(pT2);
+        pT4.setNumber("444-444-4444");
+        personEditionT4.addPhone(pT4);
+        pWT2.getEffectivity().setEnd(T4);
+        Phone pCT4 = em.newEntity(PhoneEntity.class);
+        pCT4.setType("Cell");
+        pCT4.setNumber("555-555-55555");
+        personEditionT4.addPhone(pCT4);
+
+        personEditionT4.getPersonHobbies().get(GOLF).getEffectivity().setEnd(T4);
+
+        em.persist(personEditionT4.addHobby(example.hobbies.get(RUN), T4));
+        em.persist(personEditionT4.addHobby(example.hobbies.get(SKI), T4));
+
+        em.flush();
+
+        System.out.println("\nFullPersonWithEditions.populate::DONE");
+    }
+
+    @Test
+    public void queryAllCurrent() {
+        TemporalEntityManager em = getEntityManager();
+        List<Person> results = em.createQuery("SELECT p From Person p", Person.class).getResultList();
+
+        System.out.println("QUERY CURRENT:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+        }
+
+        Assert.assertEquals(1, results.size());
+
+        Person currentperson = results.get(0);
+        Assert.assertSame(currentperson, currentperson.getContinuity());
+        Assert.assertEquals(getSample().getId(), currentperson.getId());
+    }
+
+    @Test
+    public void findCurrent() {
+        TemporalEntityManager em = getEntityManager();
+
+        Person current = em.find(Person.class, getSample().getId());
+
+        System.out.println("VERIFY CURRENT: " + current);
+
+        // Verify person
+        Assert.assertNotNull(current);
+        Assert.assertEquals(current, current.getContinuity());
+        Assert.assertEquals(getSample().getId(), current.getId());
+        Assert.assertEquals(getSample().getName(), current.getName());
+        Assert.assertTrue(current.getEffectivity().isCurrent());
+        Assert.assertFalse(current.getEffectivity().isFutureEdition());
+        Assert.assertEquals(current.getEffectivity().getStart(), BOT);
+        Assert.assertEquals(current.getEffectivity().getEnd(), T2);
+
+        // Address
+        Assert.assertNotNull(current.getAddress());
+        Assert.assertEquals(getSample().getAddress().getStreet(), current.getAddress().getStreet());
+        Assert.assertEquals(getSample().getAddress().getCity(), current.getAddress().getCity());
+        Assert.assertEquals(getSample().getAddress().getState(), current.getAddress().getState());
+        Assert.assertTrue(current.getAddress().getEffectivity().isCurrent());
+        Assert.assertFalse(current.getAddress().getEffectivity().isFutureEdition());
+        Assert.assertEquals(current.getAddress().getEffectivity().getStart(), BOT);
+        Assert.assertEquals(current.getAddress().getEffectivity().getEnd(), T2);
+
+        // Phone
+        Assert.assertEquals(1, current.getPhones().size());
+        Phone currentHome = current.getPhone("Home");
+        Assert.assertNotNull(currentHome);
+        Assert.assertEquals("111-111-1111", currentHome.getNumber());
+        Assert.assertSame(current, currentHome.getPerson());
+    }
+
+    @Test
+    public void queryAllCurrentJoinAddress() {
+        TemporalEntityManager em = getEntityManager();
+        List<Person> results = em.createQuery("SELECT p From Person p JOIN FETCH p.address", Person.class).getResultList();
+
+        System.out.println("QUERY CURRENT:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+        }
+
+        Assert.assertEquals(1, results.size());
+
+        Person currentperson = results.get(0);
+        Assert.assertSame(currentperson, currentperson.getContinuity());
+        Assert.assertEquals(getSample().getId(), currentperson.getId());
+    }
+
+    @Test
+    public void querySampleCurrentPerson() {
+        TemporalEntityManager em = getEntityManager();
+
+        Person person = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+        Address address = person.getAddress();
+
+        Assert.assertNotNull(person);
+
+        System.out.println("FIND CURRENT: " + person);
+
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertSame(person, person.getContinuity());
+        Assert.assertNotNull(address);
+        Assert.assertEquals(getSample().getAddress().getCity(), address.getCity());
+    }
+
+    @Test
+    public void querySampleCurrentPersonJoinAddress() {
+        TemporalEntityManager em = getEntityManager();
+
+        Person person = em.createQuery("SELECT p From Person p JOIN FETCH p.address WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+        Address address = person.getAddress();
+
+        Assert.assertNotNull(person);
+
+        System.out.println("FIND CURRENT: " + person);
+
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertEquals(person, person.getContinuity());
+        Assert.assertNotNull(address);
+        Assert.assertEquals(getSample().getAddress().getCity(), address.getCity());
+    }
+
+    @Test
+    public void findSampleCurrentPerson() {
+        TemporalEntityManager em = getEntityManager();
+        Person person = em.find(Person.class, getSample().getId());
+
+        Assert.assertNotNull(person);
+
+        System.out.println("FIND CURRENT: " + person);
+
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertSame(person, person.getContinuity());
+        Assert.assertTrue(person.getEffectivity().isCurrent());
+        Assert.assertFalse(person.getEffectivity().isFutureEdition());
+        Assert.assertEquals(person.getEffectivity().getStart(), BOT);
+        Assert.assertEquals(person.getEffectivity().getEnd(), T2);
+
+        Assert.assertEquals(0, person.getPersonHobbies().size());
+
+        Assert.assertEquals(1, person.getPhones().size());
+
+    }
+
+    @Test
+    public void findFuturePersonEntityEditionT2() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2);
+
+        Person person = em.find(Person.class, getSample().getId());
+        Assert.assertNotNull(person);
+        System.out.println("FIND Future Edition: " + person);
+        Assert.assertEquals(1, person.getPersonHobbies().size());
+
+        Person continuity = person.getContinuity();
+
+        Assert.assertNotNull(continuity);
+        System.out.println("\tContinuity: " + continuity);
+        Assert.assertTrue("Not an edition entity", TemporalHelper.isEdition(em, person));
+        Assert.assertEquals(getSample().getId(), person.getContinuity().getId());
+
+        Assert.assertFalse(person.getEffectivity().isCurrent());
+        Assert.assertTrue(person.getEffectivity().isFutureEdition());
+        Assert.assertEquals(person.getEffectivity().getStart(), T2);
+        Assert.assertEquals(person.getEffectivity().getEnd(), T4);
+        Assert.assertNotSame(person, person.getContinuity());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtBOT() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(BOT);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ BOT: " + pEdition);
+
+        Assert.assertNotNull("No edition found at BOT", pEdition);
+        Assert.assertTrue(pEdition.getEffectivity().isCurrent());
+        Assert.assertFalse(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(BOT, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(T2, pEdition.getEffectivity().getEnd());
+        Assert.assertNotNull("No Continuity found", pEdition.getContinuity());
+        Assert.assertEquals(0, pEdition.getPersonHobbies().size());
+
+        Address address = pEdition.getAddress();
+
+        Assert.assertNotNull(address);
+        Assert.assertEquals(getSample().getAddress().getCity(), address.getCity());
+
+        Assert.assertEquals(1, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT1() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T1);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T1: " + pEdition);
+
+        Assert.assertNotNull("No edition found at T1", pEdition);
+        Assert.assertTrue(pEdition.getEffectivity().isCurrent());
+        Assert.assertFalse(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(BOT, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(T2, pEdition.getEffectivity().getEnd());
+        Assert.assertNotNull("No Continuity found", pEdition.getContinuity());
+
+        Assert.assertEquals(0, pEdition.getPersonHobbies().size());
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        Address address = pEdition.getAddress();
+
+        Assert.assertNotNull(address);
+        Assert.assertEquals(getSample().getAddress().getCity(), address.getCity());
+
+        Assert.assertEquals(1, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT2() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T2: " + pEdition);
+
+        Assert.assertNotNull("No edition found at T2", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T2, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getEnd());
+        Assert.assertNotSame(pEdition, pEdition.getContinuity());
+
+        Assert.assertEquals(1, pEdition.getPersonHobbies().size());
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        Address address = pEdition.getAddress();
+
+        Assert.assertNotNull(address);
+        Assert.assertEquals("Toronto", address.getCity());
+
+        Assert.assertEquals(2, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT2JoinFetchAddress() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2);
+
+        Person pEdition = null;
+        try {
+            pEdition = em.createQuery("SELECT p From Person p JOIN FETCH p.address WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+        } catch (NoResultException e) {
+            Assert.fail("Join returned no result");
+        }
+        Address address = pEdition.getAddress();
+
+        System.out.println("QUERY EDITION @ T2: " + pEdition);
+        System.out.println("\t> " + address);
+
+        Assert.assertNotNull("No edition found", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T2, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getEnd());
+        Assert.assertNotNull("No Continuity found", pEdition.getContinuity());
+        Assert.assertNotNull(address);
+        Assert.assertEquals("Toronto", address.getCity());
+
+        Assert.assertEquals(1, pEdition.getPersonHobbies().size());
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        Assert.assertEquals(2, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT3() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T3);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T3: " + pEdition);
+
+        Assert.assertNotNull("No edition found ", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T2, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getEnd());
+        Assert.assertNotSame(pEdition, pEdition.getContinuity());
+
+        Assert.assertEquals(1, pEdition.getPersonHobbies().size());
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        Address address = pEdition.getAddress();
+
+        Assert.assertNotNull(address);
+        Assert.assertEquals("Toronto", address.getCity());
+
+        Assert.assertEquals(2, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT4() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T4);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T4: " + pEdition);
+
+        Assert.assertNotNull("No Person Edition Found", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(EOT, pEdition.getEffectivity().getEnd());
+        Assert.assertNotSame(pEdition, pEdition.getContinuity());
+
+        Assert.assertEquals(2, pEdition.getPersonHobbies().size());
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        Address address = pEdition.getAddress();
+
+        Assert.assertNotNull(address);
+
+        Assert.assertEquals(2, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT5() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T5);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T5: " + pEdition);
+
+        Assert.assertNotNull("No edition found at T5", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getStart());
+        Assert.assertEquals(EOT, pEdition.getEffectivity().getEnd());
+        Assert.assertNotSame(pEdition, pEdition.getContinuity());
+        Assert.assertEquals(2, pEdition.getPersonHobbies().size());
+
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        Assert.assertEquals(2, pEdition.getPhones().size());
+    }
+
+    @Test
+    public void nativeQueryForAllEdition() {
+        TemporalEntityManager em = getEntityManager();
+
+        TypedQuery<Person> query = em.createNamedQuery("PersonEdition.all", Person.class);
+        query.setParameter("CID", getSample().getId());
+        List<Person> editions = query.getResultList();
+
+        Assert.assertFalse("No edition found", editions.isEmpty());
+
+        System.out.println("QUERY ALL EDITIONS:");
+        for (Person p : editions) {
+            System.out.println("\t" + p);
+            Assert.assertNotNull("No Continuity found", p.getContinuity());
+        }
+
+        Assert.assertEquals(3, editions.size());
+    }
+
+    // @Test
+    public void deleteAllAtT5() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T5);
+
+        Person p = em.find(Person.class, getSample().getId());
+
+        em.getTransaction().begin();
+
+        p.getEffectivity().setEnd(T5);
+        p.getAddress().getEffectivity().setEnd(T5);
+        for (Phone phone : p.getPhones().values()) {
+            phone.getEffectivity().setEnd(T5);
+        }
+
+        em.flush();
+
+        // TODO - validation
+    }
+
+    @Test
+    public void detachResultUsingCopyPolicy() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2);
+
+        TypedQuery<Person> query = em.createNamedQuery("PersonEdition.find", Person.class);
+        query.setParameter("ID", getSample().getId());
+
+        Person p = query.getSingleResult();
+
+        System.out.println("ORIGINAL: " + p + " HASHCODE: " + System.identityHashCode(p));
+        System.out.println("\t" + p.getAddress());
+
+        CopyGroup cg = new CopyGroup();
+        cg.cascadeAllParts();
+
+        Person pCopy = (Person) JpaHelper.getEntityManager(em).copy(p, cg);
+        System.out.println("COPY: " + pCopy + " HASHSCODE: " + System.identityHashCode(pCopy));
+        System.out.println("\t" + pCopy.getAddress());
+    }
+
+    @Test
+    public void modifyFutureEditionOfCurrentPersonAtT4() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T4);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T4: " + pEdition);
+
+        Assert.assertNotNull("No Person Edition Found", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getStart());
+        Assert.assertNotSame(pEdition, pEdition.getContinuity());
+
+        Assert.assertEquals(2, pEdition.getPersonHobbies().size());
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        long currentVersion = pEdition.getVersion();
+
+        em.getTransaction().begin();
+        pEdition.setName(pEdition.getName().toUpperCase());
+        em.flush();
+
+        Assert.assertEquals(currentVersion + 1, pEdition.getVersion());
+    }
+
+    @Test
+    public void modifyFutureEditionOfCurrentPersonAtT4UsingMerge() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T4);
+
+        Person pEdition = em.createQuery("SELECT p From Person p WHERE p.id = " + getSample().getId(), Person.class).getSingleResult();
+
+        System.out.println("QUERY EDITION @ T4: " + pEdition);
+
+        // Create new unregistered hobby and add.
+
+        Assert.assertNotNull("No Person Edition Found", pEdition);
+        Assert.assertFalse(pEdition.getEffectivity().isCurrent());
+        Assert.assertTrue(pEdition.getEffectivity().isFutureEdition());
+        Assert.assertEquals(T4, pEdition.getEffectivity().getStart());
+        Assert.assertNotSame(pEdition, pEdition.getContinuity());
+
+        Assert.assertEquals(2, pEdition.getPersonHobbies().size());
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(SKI));
+        Assert.assertTrue(pEdition.getPersonHobbies().containsKey(RUN));
+        Assert.assertFalse(pEdition.getPersonHobbies().containsKey(GOLF));
+
+        long currentVersion = pEdition.getVersion();
+
+        em.getTransaction().begin();
+        pEdition.setName(pEdition.getName().toUpperCase());
+        em.flush();
+
+        Assert.assertEquals(currentVersion + 1, pEdition.getVersion());
+    }
+
+    /**
+     * Verify that the edition creation operation correctly copies values
+     * including mutable values and collections.
+     */
+    @Test
+    public void verifyCreateEditionCopying() {
+        TemporalEntityManager em = getEntityManager();
+        EditionSet es = em.setEffectiveTime(T5, true);
+
+        Person pEdition = em.find(Person.class, getSample().getId());
+
+        Assert.assertNotNull(pEdition);
+        Assert.assertTrue(TemporalHelper.isEdition(em, pEdition));
+        Assert.assertEquals(T4, pEdition.getEffectivity().getStart());
+        Assert.assertNotNull(es);
+        Assert.assertTrue(es.getEntries().isEmpty());
+
+        Person pAtT5 = em.newEdition(pEdition);
+
+        Assert.assertNotNull(pAtT5);
+        Assert.assertTrue(TemporalHelper.isEdition(em, pEdition));
+        Assert.assertEquals(T5, pAtT5.getEffectivity().getStart());
+        Assert.assertFalse(es.getEntries().isEmpty());
+        Assert.assertEquals(1, es.getEntries().size());
+
+        // Verify collection/map cloning
+        Assert.assertNotSame(pEdition.getPhones(), pAtT5.getPhones());
+        Assert.assertNotSame(pEdition.getPersonHobbies(), pAtT5.getPersonHobbies());
+        Assert.assertNotSame(pEdition.getNicknames(), pAtT5.getNicknames());
+
+        // Mutable non-temporal values
+        Assert.assertSame(pEdition.getDateOfBirth(), pAtT5.getDateOfBirth());
+
+        // TODO: Validate mutable basic copying
+
+    }
+
+    @Test
+    public void testDateOfBirthNonTemporalStorage() {
+        TemporalEntityManager em = getEntityManager();
+
+        List<?> results = em.createNativeQuery("SELECT DATEOFBIRTH FROM TPERSON WHERE CID = 1 ORDER BY OID").getResultList();
+
+        Assert.assertNotNull(results);
+        Assert.assertEquals(3, results.size());
+        Assert.assertEquals(new Date(75, 1, 5), results.get(0));
+        Assert.assertNull(results.get(1));
+        Assert.assertNull(results.get(2));
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryCurrentHomePhone() {
+        TemporalEntityManager em = getEntityManager();
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertFalse(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(phone, phone.getContinuity());
+        Assert.assertEquals(BOT, phone.getEffectivity().getStart());
+        Assert.assertEquals(T2, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryHomePhoneAtBOT() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(BOT);
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(BOT, phone.getEffectivity().getStart());
+        Assert.assertEquals(T2, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryHomePhoneAtT1() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T1);
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(BOT, phone.getEffectivity().getStart());
+        Assert.assertEquals(T2, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryHomePhoneAtT2() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2);
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(T2, phone.getEffectivity().getStart());
+        Assert.assertEquals(T4, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryHomePhoneAtT3() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T3);
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(T2, phone.getEffectivity().getStart());
+        Assert.assertEquals(T4, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryHomePhoneAtT4() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T4);
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(T4, phone.getEffectivity().getStart());
+        Assert.assertEquals(EOT, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+
+    /**
+     * Verify the query result and relationship to person
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void queryHomePhoneAtT5() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T5);
+
+        TypedQuery<Phone> query = em.createQuery("SELECT p FROM Phone p WHERE p.type = 'Home'", Phone.class);
+        Phone phone = query.getSingleResult();
+
+        Assert.assertNotNull(phone);
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class<BaseEntity>) phone.getClass()));
+        Assert.assertNotNull(phone.getContinuity());
+        Assert.assertEquals(T4, phone.getEffectivity().getStart());
+        Assert.assertEquals(EOT, phone.getEffectivity().getEnd());
+
+        Assert.assertNotNull(phone.getPerson());
+        Assert.assertEquals(phone.getEffectivity().getStart(), phone.getPerson().getEffectivity().getStart());
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/FuturePersonTests.java b/Temporal Entity Example/test-src/tests/FuturePersonTests.java
new file mode 100644
index 0000000..dde9a31
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/FuturePersonTests.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.T1;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T3;
+import static example.PersonModelExample.T4;
+import static example.PersonModelExample.*;
+import static temporal.Effectivity.BOT;
+
+import java.util.List;
+
+import model.Person;
+import model.PersonHobby;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class FuturePersonTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.futurePerson;
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        example.populateHobbies(em);
+        for (PersonHobby ph : example.futurePerson.getPersonHobbies().values()) {
+            em.persist(ph);
+        }
+        em.persist(example.futurePerson);
+    }
+
+    @Test
+    public void queryAllCurrent() {
+        TemporalEntityManager em = getEntityManager();
+
+        List<Person> results = example.queryAllCurrent(em);
+
+        Assert.assertTrue(results.isEmpty());
+    }
+
+    @Test
+    public void queryPersonEditionAtBOT() {
+        TemporalEntityManager em = getEntityManager();
+        em.setProperty("EFF_TS", BOT);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + getSample().getId(), Person.class).getResultList();
+
+        Assert.assertTrue("Editions found", results.isEmpty());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT1() {
+        TemporalEntityManager em = getEntityManager();
+        em.setProperty("EFF_TS", T1);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + getSample().getId(), Person.class).getResultList();
+
+        Assert.assertTrue("Editions found", results.isEmpty());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT2() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T2);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + getSample().getId(), Person.class).getResultList();
+
+        System.out.println("QUERY EFFECTIVE @ T2:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+            System.out.println("\t\t>" + p.getAddress());
+            System.out.println("\t\t>" + p.getPhones().values());
+        }
+
+        Assert.assertFalse("No Editions found", results.isEmpty());
+        Assert.assertEquals(1, results.size());
+
+        Person person = results.get(0);
+
+        Assert.assertSame(person, person.getContinuity());
+        Assert.assertFalse(person.getEffectivity().isCurrent());
+        Assert.assertTrue(person.getEffectivity().isFutureEdition());
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertEquals(getSample().getName(), person.getName());
+        Assert.assertNull(person.getAddress());
+        Assert.assertTrue(person.getPhones().isEmpty());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT3() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T3);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + getSample().getId(), Person.class).getResultList();
+
+        System.out.println("QUERY EFFECTIVE @ T3:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+            System.out.println("\t\t>" + p.getAddress());
+            System.out.println("\t\t>" + p.getPhones().values());
+        }
+
+        Assert.assertFalse("No Editions found", results.isEmpty());
+        Assert.assertEquals(1, results.size());
+
+        Person person = results.get(0);
+
+        Assert.assertSame(person, person.getContinuity());
+        Assert.assertFalse(person.getEffectivity().isCurrent());
+        Assert.assertTrue(person.getEffectivity().isFutureEdition());
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertEquals(getSample().getName(), person.getName());
+        Assert.assertNotNull(person.getAddress());
+        Assert.assertTrue(person.getPhones().isEmpty());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT4() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T4);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + getSample().getId(), Person.class).getResultList();
+
+        Assert.assertFalse("No PersonEdition Found", results.isEmpty());
+
+        System.out.println("QUERY EFFECTIVE @ T4:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+            System.out.println("\t\t>" + p.getAddress());
+            System.out.println("\t\t>" + p.getPhones().values());
+        }
+
+        Assert.assertFalse("No Editions found", results.isEmpty());
+        Assert.assertEquals(1, results.size());
+
+        Person person = results.get(0);
+
+        Assert.assertSame(person, person.getContinuity());
+        Assert.assertFalse(person.getEffectivity().isCurrent());
+        Assert.assertTrue(person.getEffectivity().isFutureEdition());
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertEquals(getSample().getName(), person.getName());
+        Assert.assertNotNull(person.getAddress());
+        Assert.assertFalse(person.getPhones().isEmpty());
+    }
+
+    @Test
+    public void queryFutureEditionOfCurrentPersonAtT5() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T5);
+
+        List<Person> results = em.createQuery("SELECT p FROM Person p WHERE p.cid = " + getSample().getId(), Person.class).getResultList();
+
+        System.out.println("QUERY EFFECTIVE @ T5:");
+        for (Person p : results) {
+            System.out.println("\t>" + p);
+            System.out.println("\t\t>" + p.getAddress());
+            System.out.println("\t\t>" + p.getPhones().values());
+        }
+
+        Assert.assertFalse("No Editions found", results.isEmpty());
+        Assert.assertEquals(1, results.size());
+
+        Person person = results.get(0);
+
+        Assert.assertSame(person, person.getContinuity());
+        Assert.assertFalse(person.getEffectivity().isCurrent());
+        Assert.assertTrue(person.getEffectivity().isFutureEdition());
+        Assert.assertEquals(getSample().getId(), person.getId());
+        Assert.assertEquals(getSample().getName(), person.getName());
+        Assert.assertNotNull(person.getAddress());
+        Assert.assertFalse(person.getPhones().isEmpty());
+    }
+
+    @Test
+    public void verifyCreateNewEntityInFuture() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T6, true);
+
+        em.getTransaction().begin();
+
+        Person p = em.newEntity(Person.class);
+
+        Assert.assertNotNull(p);
+        Assert.assertNotNull(p.getEffectivity());
+
+        em.getTransaction().rollback();
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/ModifyCurrentTests.java b/Temporal Entity Example/test-src/tests/ModifyCurrentTests.java
new file mode 100644
index 0000000..56ee1c7
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/ModifyCurrentTests.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SKI;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+import model.Address;
+import model.Person;
+import model.Phone;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * Make changes to the current (continuity) require that all future editions
+ * which had the same value as the current be updated.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class ModifyCurrentTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void test() {
+        getSample();
+        Assert.fail("NOT YET IMPLEMENTED");
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nFullPersonWithEditions.populate:START");
+
+        example.populateHobbies(em);
+        em.persist(example.fullPerson);
+        em.flush();
+
+        System.out.println("\n> Create T2 Edition");
+        em.setEffectiveTime( T2, true);
+
+        Person fpEdition = em.find(Person.class, example.fullPerson.getId());
+        Person personEditionT2 = em.newEdition( fpEdition);
+        personEditionT2.setName("Jimmy");
+        Address aT2 = em.newEdition( example.fullPerson.getAddress());
+        aT2.setCity("Toronto");
+        aT2.setState("ON");
+        personEditionT2.setAddress(aT2);
+        Phone pT2 = em.newEdition( example.fullPerson.getPhone("Home"));
+        personEditionT2.addPhone(pT2);
+        pT2.setNumber("222-222-2222");
+        em.persist(personEditionT2.addHobby(example.hobbies.get("golf"), T2));
+        em.flush();
+
+        System.out.println("\n> Create T4 Edition");
+        em.setEffectiveTime( T4, true);
+
+        Person personEditionT4 = em.newEdition( personEditionT2);
+        personEditionT4.setName("James");
+        Address aT4 = em.newEdition( aT2);
+        aT4.setCity("San Francisco");
+        aT4.setState("CA");
+        personEditionT4.setAddress(aT4);
+        Phone pT4 = em.newEdition( pT2);
+        pT4.setNumber("444-444-4444");
+        personEditionT4.addPhone(pT4);
+        personEditionT4.removeHobby(example.hobbies.get(GOLF), T4, T4);
+        em.persist(personEditionT4.addHobby(example.hobbies.get(RUN), T4));
+        em.persist(personEditionT4.addHobby(example.hobbies.get(SKI), T4));
+        em.flush();
+
+        System.out.println("\nFullPersonWithEditions.populate::DONE");
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/MultipleEditionQueries.java b/Temporal Entity Example/test-src/tests/MultipleEditionQueries.java
new file mode 100644
index 0000000..2876c2f
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/MultipleEditionQueries.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SKI;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+
+import java.util.List;
+
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * TODO
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class MultipleEditionQueries extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void queryForAllPersonEditions() {
+        TemporalEntityManager em = getEntityManager();
+
+        List<Person> results = em.createQuery("SELECT p FROM PersonEditionView p ORDER BY p.effectivity.start", Person.class).getResultList();
+
+        Assert.assertNotNull(results);
+        Assert.assertEquals(3, results.size());
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nFullPersonWithEditions.populate:START");
+
+        example.populateHobbies(em);
+        em.persist(getSample());
+        em.flush();
+
+        System.out.println("\n> Create T2 Edition");
+        em.setEffectiveTime(T2, true);
+
+        Person fpEdition = em.find(Person.class, example.fullPerson.getId());
+        Person personEditionT2 = em.newEdition(fpEdition);
+        personEditionT2.setName("Jimmy");
+        Address aT2 = em.newEdition(example.fullPerson.getAddress());
+        aT2.setCity("Toronto");
+        aT2.setState("ON");
+        personEditionT2.setAddress(aT2);
+        Phone pT2 = em.newEdition(example.fullPerson.getPhone("Home"));
+        personEditionT2.addPhone(pT2);
+        pT2.setNumber("222-222-2222");
+        em.persist(personEditionT2.addHobby(example.hobbies.get(GOLF), T2));
+        em.flush();
+
+        System.out.println("\n> Create T4 Edition");
+        em.setEffectiveTime(T4, true);
+
+        Person personEditionT4 = em.newEdition(personEditionT2);
+        personEditionT4.setName("James");
+        Address aT4 = em.newEdition(aT2);
+        aT4.setCity("San Francisco");
+        aT4.setState("CA");
+        personEditionT4.setAddress(aT4);
+        Phone pT4 = em.newEdition(pT2);
+        pT4.setNumber("444-444-4444");
+        personEditionT4.addPhone(pT4);
+        personEditionT4.removeHobby(example.hobbies.get(GOLF), T4, T4);
+        em.persist(personEditionT4.addHobby(example.hobbies.get(RUN), T4));
+        em.persist(personEditionT4.addHobby(example.hobbies.get(SKI), T4));
+        em.flush();
+
+        System.out.println("\nFullPersonWithEditions.populate::DONE");
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/ProxyWrapperUpdateTests.java b/Temporal Entity Example/test-src/tests/ProxyWrapperUpdateTests.java
new file mode 100644
index 0000000..8745259
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/ProxyWrapperUpdateTests.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests;
+
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+
+import java.lang.reflect.Proxy;
+
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+import model.entities.AddressEntity;
+import model.entities.PersonEntity;
+import model.entities.PhoneEntity;
+
+import org.junit.Test;
+
+import temporal.EditionWrapperHelper;
+import temporal.TemporalEdition;
+import temporal.TemporalEntity;
+import temporal.TemporalEntityManager;
+import example.PersonModelExample;
+
+/**
+ * Tests that verify the update of editions
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class ProxyWrapperUpdateTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    @Test
+    public void createWrapperForCurrent() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime( null, false);
+        
+        try {
+            EditionWrapperHelper.wrap(em, new PersonEntity());
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+        Assert.fail("IllegalArgumentException not thrown");
+    }
+
+    @Test
+    public void createWrapperForPersonEditionWithoutEffectiveTS() {
+        TemporalEntityManager em = getEntityManager();
+        
+        try {
+            em.getTransaction().begin();
+            Person tempPerson = em.newEntity( Person.class);
+            em.persist(tempPerson);
+            em.flush();
+            
+            EditionWrapperHelper.wrap(em, tempPerson);
+
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+
+        Assert.fail("IllegalArgumentException expected");
+    }
+
+    @Test
+    public void createWrapperForPersonEdition() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime( T4, true);
+
+        em.getTransaction().begin();
+        Person tempPerson = em.newEntity( Person.class);
+        em.persist(tempPerson);
+        em.flush();
+
+        TemporalEntity<Person> wrapper = EditionWrapperHelper.wrap(em, tempPerson);
+
+        Assert.assertNotNull(wrapper);
+        Assert.assertTrue(wrapper instanceof Person);
+        Assert.assertTrue(wrapper instanceof TemporalEdition);
+    }
+
+    @Test
+    public void createWrapperForAddressEdition() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime( T4, true);
+
+        em.getTransaction().begin();
+        TemporalEntity<Address> wrapper = EditionWrapperHelper.wrap(em, em.newEntity( AddressEntity.class));
+
+        Assert.assertNotNull(wrapper);
+        Assert.assertTrue(wrapper instanceof Address);
+        Assert.assertTrue(wrapper instanceof TemporalEdition);
+        
+        em.getTransaction().rollback();
+    }
+
+    @Test
+    public void createWrapperForPhoneEdition() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime( T4, true);
+
+        em.getTransaction().begin();
+        TemporalEntity<Phone> wrapper = EditionWrapperHelper.wrap(em,em.newEntity( PhoneEntity.class));
+
+        Assert.assertNotNull(wrapper);
+        Assert.assertTrue(wrapper instanceof Phone);
+        Assert.assertTrue(wrapper instanceof TemporalEdition);
+        em.getTransaction().rollback();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void create2editionsUsingWrappers() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime( T2, true);
+
+
+        Person editionAtT2 = em.find(Person.class, example.fullPerson.getId());
+
+        em.getTransaction().begin();
+        Person wrappedPerson = (Person) EditionWrapperHelper.wrap(em, editionAtT2);
+
+        Assert.assertTrue(Proxy.isProxyClass(wrappedPerson.getClass()));
+        Assert.assertTrue(Proxy.isProxyClass(wrappedPerson.getAddress().getClass()));
+        Assert.assertFalse(((TemporalEdition<Person>) wrappedPerson).hasChanges());
+
+        wrappedPerson.setName(editionAtT2.getName() + "@T2");
+
+        Assert.assertTrue(((TemporalEdition<Person>) wrappedPerson).hasChanges());
+
+        em.getTransaction().commit();
+        em.close();
+
+        em = getEntityManager();
+        em.setEffectiveTime( T4, true);
+
+        Person editionAtT4 = em.find(Person.class, example.fullPerson.getId());
+
+        em.getTransaction().begin();
+        wrappedPerson = (Person) EditionWrapperHelper.wrap(em, editionAtT4);
+
+        Assert.assertFalse(((TemporalEdition<Person>) wrappedPerson).hasChanges());
+
+        wrappedPerson.setName(editionAtT4.getName() + "@T4");
+
+        Assert.assertTrue(((TemporalEdition<Person>) wrappedPerson).hasChanges());
+
+        em.getTransaction().commit();
+    }
+
+    @Override
+    public void populate(TemporalEntityManager em) {
+        em.persist(example.fullPerson);
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/AllTests.java b/Temporal Entity Example/test-src/tests/editionsets/AllTests.java
new file mode 100644
index 0000000..ed46d1d
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/AllTests.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({ EditionSetConfigTests.class, 
+                CreateEditionSetTests.class, 
+                ApplySimpleEditionSetTests.class, 
+                MoveSingleEditionSetTests.class,
+                DeleteEditionSetTests.class,
+                PropagateChangesTests.class})
+public class AllTests {
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/ApplySimpleEditionSetTests.java b/Temporal Entity Example/test-src/tests/editionsets/ApplySimpleEditionSetTests.java
new file mode 100644
index 0000000..b21f89f
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/ApplySimpleEditionSetTests.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.T2;
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+import model.entities.PersonEntity;
+
+import org.junit.Test;
+
+import temporal.EditionSet;
+import temporal.EditionSetEntry;
+import temporal.EditionSetHelper;
+import temporal.TemporalEntityManager;
+import tests.BaseTestCase;
+import example.PersonModelExample;
+
+/**
+ * Tests applying a simple (no conflict) {@link EditionSet}
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class ApplySimpleEditionSetTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void verifyEditionSetAtT2() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+
+        EditionSet es = em.setEffectiveTime(T2, true);
+
+        Assert.assertNotNull(es);
+        Assert.assertEquals(T2, es.getEffective());
+        Assert.assertEquals(3, es.getEntries().size());
+        
+        for (EditionSetEntry ese: es.getEntries()) {
+            Assert.assertNotNull(ese.getTemporal());
+        }
+
+        EditionSetHelper.apply(em, es);
+        
+        em.flush();
+    }
+
+    /**
+     * Populate initial sample entity
+     */
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nEditionSetTests.populate:START");
+        example.populateHobbies(em);
+        em.persist(getSample());
+        em.flush();
+        
+        populateT2Editions(em);
+        System.out.println("\nEditionSetTests.populate::DONE");
+    }
+
+    /**
+     * Create the edition at T2 if it has not already been created
+     */
+    public Person populateT2Editions(TemporalEntityManager em) {
+        EditionSet editionSet = em.setEffectiveTime(T2, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT2 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT2.getEffectivity().getStart() != T2) {
+            System.out.println("\nEditionSetTests.populateT2Edition:START");
+
+            editionSet.setDescription("EditionSetTests::Person@T2");
+            personEditionT2 = em.newEdition(personEditionT2);
+            personEditionT2.setName("Jimmy");
+            Address aT2 = em.newEdition(personEditionT2.getAddress());
+            aT2.setCity("Toronto");
+            aT2.setState("ON");
+            personEditionT2.setAddress(aT2);
+            Phone pT2 = em.newEdition(personEditionT2.getPhone("Home"));
+            personEditionT2.addPhone(pT2);
+            pT2.setNumber("222-222-2222");
+            em.persist(personEditionT2.addHobby(example.hobbies.get(GOLF), T2));
+            
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT2Edition::DONE");
+        }
+
+        return personEditionT2;
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/CreateEditionSetTests.java b/Temporal Entity Example/test-src/tests/editionsets/CreateEditionSetTests.java
new file mode 100644
index 0000000..857cf24
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/CreateEditionSetTests.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SKI;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+import static example.PersonModelExample.T5;
+
+import java.util.List;
+
+import javax.persistence.Temporal;
+
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.PersonHobby;
+import model.Phone;
+import model.entities.PersonEntity;
+
+import org.junit.Test;
+
+import temporal.EditionSet;
+import temporal.EditionSetEntry;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+import tests.BaseTestCase;
+import example.PersonModelExample;
+
+/**
+ * Tests verifying the {@link EditionSet} capabilities.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class CreateEditionSetTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void verifyEditionSetAtT2() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+        populateT2Editions(em);
+
+        EditionSet es = em.setEffectiveTime(T2, true);
+
+        Assert.assertNotNull(es);
+        Assert.assertEquals(T2, es.getEffective());
+        Assert.assertEquals(4, es.getEntries().size());
+
+        Assert.assertTrue(es.getEntries().get(0).getTemporal() instanceof Person);
+        Person p = (Person) es.getEntries().get(0).getTemporal();
+        Assert.assertEquals(T2, p.getEffectivity().getStart());
+
+        Assert.assertTrue(es.getEntries().get(1).getTemporal() instanceof Address);
+        Address a = (Address) es.getEntries().get(1).getTemporal();
+        Assert.assertEquals(T2, a.getEffectivity().getStart());
+
+        Assert.assertTrue(es.getEntries().get(2).getTemporal() instanceof Phone);
+        Phone phone = (Phone) es.getEntries().get(2).getTemporal();
+        Assert.assertEquals(T2, phone.getEffectivity().getStart());
+
+        Assert.assertTrue(es.getEntries().get(3).getTemporal() instanceof PersonHobby);
+        PersonHobby ph = (PersonHobby) es.getEntries().get(3).getTemporal();
+        Assert.assertEquals(T2, ph.getEffectivity().getStart());
+        Assert.assertSame(p, ph.getPerson());
+        Assert.assertEquals(PersonModelExample.GOLF, ph.getName());
+        Assert.assertEquals(PersonModelExample.GOLF, ph.getHobby().getName());
+
+        Assert.assertEquals(1, p.getPersonHobbies().size());
+        
+    }
+
+    @Test
+    public void verifyEditionSetAtT4() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+
+        populateT4Editions(em);
+
+        List<EditionSet> editionSets = em.createQuery("SELECT e FROM EditionSet e ORDER BY e.effective", EditionSet.class).getResultList();
+
+        Assert.assertNotNull(editionSets);
+        Assert.assertEquals("Incorrect number of EditionSets found.", 2, editionSets.size());
+
+        EditionSet t1 = editionSets.get(0);
+        Assert.assertNotNull(t1);
+        Assert.assertEquals(T2, t1.getEffective());
+
+        EditionSet t2 = editionSets.get(1);
+        Assert.assertNotNull(t2);
+        Assert.assertEquals(T4, t2.getEffective());
+    }
+
+    /**
+     * Verify that the addition of a {@link Temporal} value in a 1:M collection
+     * causes an EditionSetEntry to be created.
+     */
+    @Test
+    public void addHobbyAtT5WithInitializedEditionSet() {
+        TemporalEntityManager em = getEntityManager();
+        EditionSet es = em.setEffectiveTime(T5, true);
+
+        Assert.assertNotNull(es);
+
+        Person person = em.find(Person.class, getSample().getId());
+        Assert.assertNotNull(person);
+        Assert.assertTrue(TemporalHelper.isTemporalEntity(person));
+        Assert.assertEquals(T5, es.getEffective());
+
+        PersonHobby runHobby = em.newTemporal(PersonHobby.class);
+        runHobby.setHobby(example.hobbies.get(RUN));
+        person.addHobby(runHobby);
+
+        Assert.assertEquals(1, es.getEntries().size());
+
+        EditionSetEntry entry = es.getEntries().get(0);
+
+        Assert.assertTrue(entry.getTemporal() instanceof PersonHobby);
+    }
+
+    /**
+     * Populate initial sample entity
+     */
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nEditionSetTests.populate:START");
+        example.populateHobbies(em);
+        em.persist(getSample());
+        System.out.println("\nEditionSetTests.populate::DONE");
+    }
+
+    /**
+     * Create the edition at T2 if it has not already been created
+     */
+    public Person populateT2Editions(TemporalEntityManager em) {
+        EditionSet editionSet = em.setEffectiveTime(T2, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT2 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT2.getEffectivity().getStart() != T2) {
+            System.out.println("\nEditionSetTests.populateT2Edition:START");
+
+            editionSet.setDescription("EditionSetTests::Person@T2");
+            personEditionT2 = em.newEdition(personEditionT2);
+            personEditionT2.setName("Jimmy");
+            Address aT2 = em.newEdition(personEditionT2.getAddress());
+            aT2.setCity("Toronto");
+            aT2.setState("ON");
+            personEditionT2.setAddress(aT2);
+            Phone pT2 = em.newEdition(personEditionT2.getPhone("Home"));
+            personEditionT2.addPhone(pT2);
+            pT2.setNumber("222-222-2222");
+
+            PersonHobby golfHobby = em.newTemporal(PersonHobby.class);
+            golfHobby.setHobby(example.hobbies.get(GOLF));
+            personEditionT2.addHobby(golfHobby);
+
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT2Edition::DONE");
+        }
+
+        return personEditionT2;
+    }
+
+    public Person populateT4Editions(TemporalEntityManager em) {
+        populateT2Editions(em);
+        
+        EditionSet editionSet = em.setEffectiveTime(T4, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT4 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT4 == null) {
+            System.out.println("\nEditionSetTests.populateT4Edition:START");
+            em.initializeEditionSet().setDescription("EditionSetTests::Person@T4");
+            personEditionT4 = em.newEdition(personEditionT4);
+            personEditionT4.setName("James");
+            Address aT4 = em.newEdition(personEditionT4.getAddress());
+            aT4.setCity("San Francisco");
+            aT4.setState("CA");
+            personEditionT4.setAddress(aT4);
+            Phone pT4 = em.newEdition(personEditionT4.getPhone("Home"));
+            pT4.setNumber("444-444-4444");
+            personEditionT4.addPhone(pT4);
+            personEditionT4.getPersonHobbies().get(GOLF).getEffectivity().setEnd(T4);
+
+            PersonHobby runHobby = em.newTemporal(PersonHobby.class);
+            runHobby.setHobby(example.hobbies.get(RUN));
+            personEditionT4.addHobby(runHobby);
+
+            PersonHobby skiHobby = em.newTemporal(PersonHobby.class);
+            skiHobby.setHobby(example.hobbies.get(SKI));
+            personEditionT4.addHobby(skiHobby);
+
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT4Edition:DONE");
+        }
+
+        return personEditionT4;
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/DeleteEditionSetTests.java b/Temporal Entity Example/test-src/tests/editionsets/DeleteEditionSetTests.java
new file mode 100644
index 0000000..f1e9690
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/DeleteEditionSetTests.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SKI;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+import static example.PersonModelExample.T5;
+
+import java.util.List;
+
+import javax.persistence.Temporal;
+
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.PersonHobby;
+import model.Phone;
+import model.entities.PersonEntity;
+
+import org.junit.Test;
+
+import temporal.EditionSet;
+import temporal.EditionSetEntry;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+import tests.BaseTestCase;
+import example.PersonModelExample;
+
+/**
+ * Tests verifying the {@link EditionSet} capabilities.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class DeleteEditionSetTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void verifyEditionSetAtT2() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+        populateT2Editions(em);
+
+        EditionSet es = em.setEffectiveTime(T2, true);
+
+        Assert.assertNotNull(es);
+        Assert.assertEquals(T2, es.getEffective());
+        Assert.assertEquals(4, es.getEntries().size());
+
+        Assert.assertTrue(es.getEntries().get(0).getTemporal() instanceof Person);
+        Person p = (Person) es.getEntries().get(0).getTemporal();
+        Assert.assertEquals(T2, p.getEffectivity().getStart());
+
+        Assert.assertTrue(es.getEntries().get(1).getTemporal() instanceof Address);
+        Address a = (Address) es.getEntries().get(1).getTemporal();
+        Assert.assertEquals(T2, a.getEffectivity().getStart());
+
+        Assert.assertTrue(es.getEntries().get(2).getTemporal() instanceof Phone);
+        Phone phone = (Phone) es.getEntries().get(2).getTemporal();
+        Assert.assertEquals(T2, phone.getEffectivity().getStart());
+
+        Assert.assertTrue(es.getEntries().get(3).getTemporal() instanceof PersonHobby);
+        PersonHobby ph = (PersonHobby) es.getEntries().get(3).getTemporal();
+        Assert.assertEquals(T2, ph.getEffectivity().getStart());
+        Assert.assertSame(p, ph.getPerson());
+        Assert.assertEquals(PersonModelExample.GOLF, ph.getName());
+        Assert.assertEquals(PersonModelExample.GOLF, ph.getHobby().getName());
+
+        Assert.assertEquals(1, p.getPersonHobbies().size());
+        
+    }
+
+    @Test
+    public void verifyEditionSetAtT4() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+
+        populateT4Editions(em);
+
+        List<EditionSet> editionSets = em.createQuery("SELECT e FROM EditionSet e ORDER BY e.effective", EditionSet.class).getResultList();
+
+        Assert.assertNotNull(editionSets);
+        Assert.assertEquals("Incorrect number of EditionSets found.", 2, editionSets.size());
+
+        EditionSet t1 = editionSets.get(0);
+        Assert.assertNotNull(t1);
+        Assert.assertEquals(T2, t1.getEffective());
+
+        EditionSet t2 = editionSets.get(1);
+        Assert.assertNotNull(t2);
+        Assert.assertEquals(T4, t2.getEffective());
+    }
+
+    /**
+     * Verify that the addition of a {@link Temporal} value in a 1:M collection
+     * causes an EditionSetEntry to be created.
+     */
+    @Test
+    public void addHobbyAtT5WithInitializedEditionSet() {
+        TemporalEntityManager em = getEntityManager();
+        EditionSet es = em.setEffectiveTime(T5, true);
+
+        Assert.assertNotNull(es);
+
+        Person person = em.find(Person.class, getSample().getId());
+        Assert.assertNotNull(person);
+        Assert.assertTrue(TemporalHelper.isTemporalEntity(person));
+        Assert.assertEquals(T5, es.getEffective());
+
+        PersonHobby runHobby = em.newTemporal(PersonHobby.class);
+        runHobby.setHobby(example.hobbies.get(RUN));
+        person.addHobby(runHobby);
+
+        Assert.assertEquals(1, es.getEntries().size());
+
+        EditionSetEntry entry = es.getEntries().get(0);
+
+        Assert.assertTrue(entry.getTemporal() instanceof PersonHobby);
+    }
+
+    /**
+     * Populate initial sample entity
+     */
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nEditionSetTests.populate:START");
+        example.populateHobbies(em);
+        em.persist(getSample());
+        System.out.println("\nEditionSetTests.populate::DONE");
+    }
+
+    /**
+     * Create the edition at T2 if it has not already been created
+     */
+    public Person populateT2Editions(TemporalEntityManager em) {
+        EditionSet editionSet = em.setEffectiveTime(T2, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT2 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT2.getEffectivity().getStart() != T2) {
+            System.out.println("\nEditionSetTests.populateT2Edition:START");
+
+            editionSet.setDescription("EditionSetTests::Person@T2");
+            personEditionT2 = em.newEdition(personEditionT2);
+            personEditionT2.setName("Jimmy");
+            Address aT2 = em.newEdition(personEditionT2.getAddress());
+            aT2.setCity("Toronto");
+            aT2.setState("ON");
+            personEditionT2.setAddress(aT2);
+            Phone pT2 = em.newEdition(personEditionT2.getPhone("Home"));
+            personEditionT2.addPhone(pT2);
+            pT2.setNumber("222-222-2222");
+
+            PersonHobby golfHobby = em.newTemporal(PersonHobby.class);
+            golfHobby.setHobby(example.hobbies.get(GOLF));
+            personEditionT2.addHobby(golfHobby);
+
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT2Edition::DONE");
+        }
+
+        return personEditionT2;
+    }
+
+    public Person populateT4Editions(TemporalEntityManager em) {
+        populateT2Editions(em);
+        
+        EditionSet editionSet = em.setEffectiveTime(T4, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT4 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT4 == null) {
+            System.out.println("\nEditionSetTests.populateT4Edition:START");
+            em.initializeEditionSet().setDescription("EditionSetTests::Person@T4");
+            personEditionT4 = em.newEdition(personEditionT4);
+            personEditionT4.setName("James");
+            Address aT4 = em.newEdition(personEditionT4.getAddress());
+            aT4.setCity("San Francisco");
+            aT4.setState("CA");
+            personEditionT4.setAddress(aT4);
+            Phone pT4 = em.newEdition(personEditionT4.getPhone("Home"));
+            pT4.setNumber("444-444-4444");
+            personEditionT4.addPhone(pT4);
+            personEditionT4.getPersonHobbies().get(GOLF).getEffectivity().setEnd(T4);
+
+            PersonHobby runHobby = em.newTemporal(PersonHobby.class);
+            runHobby.setHobby(example.hobbies.get(RUN));
+            personEditionT4.addHobby(runHobby);
+
+            PersonHobby skiHobby = em.newTemporal(PersonHobby.class);
+            skiHobby.setHobby(example.hobbies.get(SKI));
+            personEditionT4.addHobby(skiHobby);
+
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT4Edition:DONE");
+        }
+
+        return personEditionT4;
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/EditionSetConfigTests.java b/Temporal Entity Example/test-src/tests/editionsets/EditionSetConfigTests.java
new file mode 100644
index 0000000..1fba99d
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/EditionSetConfigTests.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import static example.PersonModelExample.T6;
+import junit.framework.Assert;
+import model.Person;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.mappings.OneToManyMapping;
+import org.eclipse.persistence.mappings.VariableOneToOneMapping;
+import org.eclipse.persistence.sessions.server.Server;
+import org.junit.Test;
+
+import temporal.EditionSet;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+import tests.BaseTestCase;
+import example.PersonModelExample;
+
+/**
+ * Tests verifying the {@link EditionSet} capabilities.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class EditionSetConfigTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void verifyEditionSetMapping() {
+        TemporalEntityManager em = getEntityManager();
+
+        ClassDescriptor desc = em.unwrap(Server.class).getClassDescriptorForAlias("EditionSet");
+        Assert.assertNotNull(desc);
+
+        OneToManyMapping otmMapping = (OneToManyMapping) desc.getMappingForAttributeName("entries");
+        Assert.assertNotNull(otmMapping);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void verifyEditionSetEntryMapping() {
+        TemporalEntityManager em = getEntityManager();
+
+        ClassDescriptor desc = em.unwrap(Server.class).getClassDescriptorForAlias("EditionSetEntry");
+        Assert.assertNotNull(desc);
+
+        VariableOneToOneMapping votoMapping = (VariableOneToOneMapping) desc.getMappingForAttributeName("temporal");
+        Assert.assertNotNull(votoMapping);
+
+        Assert.assertEquals(8, votoMapping.getTypeIndicatorTranslation().size());
+
+        Assert.assertTrue(votoMapping.getTypeIndicatorTranslation().containsKey("Person"));
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class) votoMapping.getTypeIndicatorTranslation().get("Person")));
+
+        Assert.assertTrue(votoMapping.getTypeIndicatorTranslation().containsKey("Phone"));
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class) votoMapping.getTypeIndicatorTranslation().get("Phone")));
+
+        Assert.assertTrue(votoMapping.getTypeIndicatorTranslation().containsKey("Address"));
+        Assert.assertTrue(TemporalHelper.isEditionClass((Class) votoMapping.getTypeIndicatorTranslation().get("Address")));
+
+        Assert.assertTrue(votoMapping.getTypeIndicatorTranslation().containsKey("PersonHobby"));
+        Assert.assertTrue(TemporalHelper.isTemporal((Class) votoMapping.getTypeIndicatorTranslation().get("PersonHobby"), false));
+    }
+
+    @Test
+    public void verifySetEffectiveInitialize() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.setEffectiveTime(T6, true);
+
+        EditionSet es = em.getEditionSet();
+
+        Assert.assertNotNull(es);
+        Assert.assertEquals(T6, es.getEffective());
+    }
+
+    @Test
+    public void verifyInitialize() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.setEffectiveTime(T6);
+        em.initializeEditionSet();
+
+        EditionSet es = em.getEditionSet();
+
+        Assert.assertNotNull(es);
+        Assert.assertEquals(T6, es.getEffective());
+    }
+
+    @Test
+    public void verifyNotInitialized() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.setEffectiveTime(T6);
+
+        EditionSet es = em.getEditionSet();
+
+        Assert.assertNull(es);
+    }
+
+    /**
+     * Populate initial sample entity
+     */
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nEditionSetTests.populate:START");
+        example.populateHobbies(em);
+        em.persist(getSample());
+        System.out.println("\nEditionSetTests.populate::DONE");
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/MoveSingleEditionSetTests.java b/Temporal Entity Example/test-src/tests/editionsets/MoveSingleEditionSetTests.java
new file mode 100644
index 0000000..a2754a2
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/MoveSingleEditionSetTests.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.T2;
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+
+import org.junit.Test;
+
+import temporal.EditionSet;
+import temporal.EditionSetEntry;
+import temporal.TemporalEntityManager;
+import tests.BaseTestCase;
+import example.PersonModelExample;
+
+/**
+ * Tests applying a simple (no conflict) {@link EditionSet}
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class MoveSingleEditionSetTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void moveEditionSetFromT2toT3() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+
+        EditionSet es = em.setEffectiveTime(T2, true);
+
+        Assert.assertNotNull(es);
+        Assert.assertEquals(T2, es.getEffective());
+        Assert.assertEquals(3, es.getEntries().size());
+
+        for (EditionSetEntry entry : es.getEntries()) {
+            System.out.println("> " + entry.getTemporal());
+            for (String attrName : entry.getAttributes()) {
+                System.out.println("\t>> " + attrName);
+            }
+        }
+    }
+
+    /**
+     * Populate initial sample entity
+     */
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nEditionSetTests.populate:START");
+        example.populateHobbies(em);
+        em.persist(getSample());
+        populateT2Editions(em);
+        System.out.println("\nEditionSetTests.populate::DONE");
+    }
+
+    /**
+     * Create the edition at T2 if it has not already been created
+     */
+    public Person populateT2Editions(TemporalEntityManager em) {
+        EditionSet editionSet = em.setEffectiveTime(T2, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT2 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT2.getEffectivity().getStart() != T2) {
+            System.out.println("\nEditionSetTests.populateT2Edition:START");
+
+            editionSet.setDescription("EditionSetTests::Person@T2");
+            personEditionT2 = em.newEdition(personEditionT2);
+            personEditionT2.setName("Jimmy");
+            Address aT2 = em.newEdition(personEditionT2.getAddress());
+            aT2.setCity("Toronto");
+            aT2.setState("ON");
+            personEditionT2.setAddress(aT2);
+            Phone pT2 = em.newEdition(personEditionT2.getPhone("Home"));
+            personEditionT2.addPhone(pT2);
+            pT2.setNumber("222-222-2222");
+            em.persist(personEditionT2.addHobby(example.hobbies.get(GOLF), T2));
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT2Edition::DONE");
+        }
+
+        return personEditionT2;
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/editionsets/PropagateChangesTests.java b/Temporal Entity Example/test-src/tests/editionsets/PropagateChangesTests.java
new file mode 100644
index 0000000..8ebeab3
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/editionsets/PropagateChangesTests.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.editionsets;
+
+import static example.PersonModelExample.GOLF;
+import static example.PersonModelExample.RUN;
+import static example.PersonModelExample.SWIM;
+import static example.PersonModelExample.T2;
+import static example.PersonModelExample.T4;
+import junit.framework.Assert;
+import model.Address;
+import model.Person;
+import model.Phone;
+import model.entities.PersonEntity;
+
+import org.junit.Test;
+
+import temporal.EditionSet;
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+import tests.BaseTestCase;
+import example.PersonModelExample;
+
+/**
+ * Tests change propagation through future editions.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class PropagateChangesTests extends BaseTestCase {
+
+    private static PersonModelExample example = new PersonModelExample();
+
+    private Person getSample() {
+        return example.fullPerson;
+    }
+
+    @Test
+    public void makeBasicChangesAtT2Changes() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+
+        EditionSet esT2 = em.setEffectiveTime( T2, true);
+        Assert.assertNotNull(esT2);
+
+        Person personT2 = em.find(Person.class, getSample().getId());
+
+        Assert.assertNotNull(personT2);
+        Assert.assertTrue(TemporalHelper.isEdition(em, personT2));
+        Assert.assertEquals(T2, personT2.getEffectivity().getStart());
+
+        personT2.setName("Jimster");
+        personT2.setEmail("a@b.c");
+        personT2.getAddress().setState("ONT");
+        personT2.getAddress().setStreet(null);
+
+        em.flush();
+        em.clear();
+
+        EditionSet esT4 = em.setEffectiveTime( T4, true);
+        Assert.assertNotNull(esT4);
+
+        Person personT4 = em.find(Person.class, getSample().getId());
+
+        Assert.assertNotNull(personT4);
+        Assert.assertTrue(TemporalHelper.isEdition(em, personT4));
+        Assert.assertEquals(T4, personT4.getEffectivity().getStart());
+
+        String nativeName = (String) em.createNativeQuery("SELECT P_NAMES FROM TPERSON WHERE CID = " + getSample().getId() + " AND START_TS = 400").getSingleResult();
+        Assert.assertEquals("Jimbo", nativeName);
+        Assert.assertEquals("Jimbo", personT4.getName());
+
+        String nativeState = (String) em.createNativeQuery("SELECT STATE FROM TADDRESS WHERE CID = " + getSample().getAddress().getId() + " AND START_TS = 400").getSingleResult();
+        Assert.assertEquals("ONT", nativeState);
+        Assert.assertEquals("ONT", personT4.getAddress().getState());
+
+        Assert.assertNull(personT4.getAddress().getStreet());
+        Assert.assertNotNull(personT4.getEmail());
+    }
+
+    @Test
+    public void makeBasicCollectionChangesAtT2Changes() {
+        TemporalEntityManager em = getEntityManager();
+
+        em.getTransaction().begin();
+
+        EditionSet esT2 = em.setEffectiveTime( T2, true);
+        Assert.assertNotNull(esT2);
+
+        Person personT2 = em.find(Person.class, getSample().getId());
+
+        Assert.assertNotNull(personT2);
+        Assert.assertTrue(TemporalHelper.isEdition(em, personT2));
+        Assert.assertEquals(T2, personT2.getEffectivity().getStart());
+
+        em.persist(personT2.addHobby(example.hobbies.get(SWIM), T2));
+
+        try {
+            em.flush();
+        } catch (UnsupportedOperationException e) {
+            return;
+        }
+        Assert.fail("UnsupportedOperationException expected");
+
+    }
+
+    /**
+     * Populate initial sample entity
+     */
+    @Override
+    public void populate(TemporalEntityManager em) {
+        System.out.println("\nEditionSetTests.populate:START");
+        example.populateHobbies(em);
+        em.persist(getSample());
+        populateT2Editions(em);
+        populateT4Editions(em);
+        System.out.println("\nEditionSetTests.populate::DONE");
+    }
+
+    /**
+     * Create the edition at T2 if it has not already been created
+     */
+    public Person populateT2Editions(TemporalEntityManager em) {
+        EditionSet editionSet = em.setEffectiveTime( T2, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT2 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT2.getEffectivity().getStart() != T2) {
+            System.out.println("\nEditionSetTests.populateT2Edition:START");
+
+            editionSet.setDescription("EditionSetTests::Person@T2");
+            personEditionT2 = em.newEdition( personEditionT2);
+            personEditionT2.setName("Jimmy");
+            Address aT2 = em.newEdition( personEditionT2.getAddress());
+            aT2.setCity("Toronto");
+            aT2.setState("ON");
+            personEditionT2.setAddress(aT2);
+            Phone pT2 = em.newEdition( personEditionT2.getPhone("Home"));
+            personEditionT2.addPhone(pT2);
+            pT2.setNumber("222-222-2222");
+            em.persist(personEditionT2.addHobby(example.hobbies.get(GOLF), T2));
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT2Edition::DONE");
+        }
+
+        return personEditionT2;
+    }
+
+    /**
+     * Create the edition at T2 if it has not already been created
+     */
+    public Person populateT4Editions(TemporalEntityManager em) {
+        EditionSet editionSet = em.setEffectiveTime( T4, true);
+        Assert.assertNotNull(editionSet);
+
+        Person personEditionT4 = em.find(Person.class, getSample().getId());
+
+        if (personEditionT4.getEffectivity().getStart() != T4) {
+            System.out.println("\nEditionSetTests.populateT4Edition:START");
+
+            editionSet.setDescription("EditionSetTests::Person@T4");
+            personEditionT4 = em.newEdition( personEditionT4);
+            personEditionT4.setName("Jimbo");
+            Address aT4 = em.newEdition( personEditionT4.getAddress());
+            aT4.setCity("Ottawa");
+            personEditionT4.setAddress(aT4);
+            Phone pT4 = em.newEdition( personEditionT4.getPhone("Home"));
+            personEditionT4.addPhone(pT4);
+            pT4.setNumber("444-444-4444");
+            em.persist(personEditionT4.addHobby(example.hobbies.get(RUN), T4));
+            em.flush();
+
+            System.out.println("\nEditionSetTests.populateT4Edition::DONE");
+        }
+
+        return personEditionT4;
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/AllTests.java b/Temporal Entity Example/test-src/tests/internal/AllTests.java
new file mode 100644
index 0000000..c6125a5
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/AllTests.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Internal test suite verifying how EclipseLInk and the temporal extensions are working.
+ *
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+@RunWith(Suite.class)
+@SuiteClasses({ VerifyConfigTests.class, 
+                VerifySchemaManager.class,
+                TemporalHelperTests.class, 
+                TemporalEntityManagerTests.class, 
+                TemporalEntityTests.class,
+                //WrapperPolicyTests.class,
+                })
+public class AllTests {
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/TemporalEntityManagerTests.java b/Temporal Entity Example/test-src/tests/internal/TemporalEntityManagerTests.java
new file mode 100644
index 0000000..f20a375
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/TemporalEntityManagerTests.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import static example.PersonModelExample.T1;
+import static example.PersonModelExample.T3;
+import static example.PersonModelExample.T4;
+import static example.PersonModelExample.T5;
+import static example.PersonModelExample.T6;
+import static example.PersonModelExample.T7;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static temporal.Effectivity.BOT;
+import static temporal.Effectivity.EOT;
+
+import javax.persistence.EntityManager;
+
+import junit.framework.Assert;
+import model.PersonHobby;
+
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+import org.eclipse.persistence.sessions.DatabaseSession;
+import org.eclipse.persistence.sessions.UnitOfWork;
+import org.eclipse.persistence.sessions.server.ClientSession;
+import org.eclipse.persistence.sessions.server.Server;
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import tests.BaseTestCase;
+
+/**
+ * Verify the {@link TemporalEntityManager} API
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class TemporalEntityManagerTests extends BaseTestCase {
+
+    private void verifySetStartTime(TemporalEntityManager em, Long value) {
+        assertTrue(em.hasEffectiveTime());
+        assertNotNull(em.getEffectiveTime());
+        assertEquals(value, em.getEffectiveTime());
+
+        RepeatableWriteUnitOfWork uow = em.unwrap(RepeatableWriteUnitOfWork.class);
+        assertNotNull(uow);
+
+        ClientSession clientSession = (ClientSession) uow.getParent();
+
+        DatabaseSession session = em.unwrap(DatabaseSession.class);
+        assertNotSame(clientSession, session);
+
+        Server serverSession = em.unwrap(Server.class);
+        assertNotSame(clientSession, serverSession);
+        assertSame(session, serverSession);
+    }
+
+    @Test
+    public void verifyGetInstance() {
+        TemporalEntityManager em1 = getEntityManager();
+
+        Assert.assertTrue(em1.getProperties().containsKey(TemporalEntityManager.TEMPORAL_EM_PROPERTY));
+        Assert.assertFalse(em1.getProperties().containsKey(TemporalEntityManager.EFF_TS_PROPERTY));
+        assertFalse(em1.hasEffectiveTime());
+        assertNull(em1.getEffectiveTime());
+
+        EntityManager wrappedEm = em1.unwrap(EntityManager.class);
+        Assert.assertNotSame(em1, wrappedEm);
+
+        TemporalEntityManager em2 = TemporalEntityManager.getInstance(wrappedEm);
+        Assert.assertSame(em1, em2);
+
+        TemporalEntityManager em3 = TemporalEntityManager.getInstance(wrappedEm.unwrap(UnitOfWork.class));
+        Assert.assertSame(em1, em3);
+
+        TemporalEntityManager em4 = TemporalEntityManager.getInstance(em1);
+        Assert.assertSame(em1, em4);
+    }
+
+    @Test
+    public void verifySetStartTime() {
+        TemporalEntityManager em = getEntityManager();
+
+        assertFalse(em.hasEffectiveTime());
+        assertNull(em.getEffectiveTime());
+
+        em.setEffectiveTime(T1);
+
+        verifySetStartTime(em, T1);
+    }
+
+    @Test
+    public void verifyClearStartTime() {
+        TemporalEntityManager em = getEntityManager();
+        assertFalse(em.hasEffectiveTime());
+        assertNull(em.getEffectiveTime());
+
+        em.setEffectiveTime(T3);
+
+        verifySetStartTime(em, T3);
+
+        em.clearEffectiveTime();
+
+        assertFalse(em.hasEffectiveTime());
+        assertNull(em.getEffectiveTime());
+    }
+
+    @Test
+    public void verifyConcurrentSetStartTime() {
+        TemporalEntityManager em1 = getEntityManager();
+        TemporalEntityManager em2 = TemporalEntityManager.getInstance(getEMF().createEntityManager());
+
+        assertNotSame(em1, em2);
+
+        em1.setEffectiveTime(T4);
+
+        em2.setEffectiveTime(T5);
+
+        verifySetStartTime(em2, T5);
+        verifySetStartTime(em1, T4);
+    }
+
+    @Test
+    public void verifyConcurrentClearStartTime() {
+        TemporalEntityManager em1 = getEntityManager();
+        TemporalEntityManager em2 = TemporalEntityManager.getInstance(getEMF().createEntityManager());
+
+        assertNotSame(em1, em2);
+
+        em1.setEffectiveTime(T6);
+        em2.setEffectiveTime(T7);
+
+        verifySetStartTime(em2, T7);
+        verifySetStartTime(em1, T6);
+
+        em1.clearEffectiveTime();
+        verifySetStartTime(em2, T7);
+        assertFalse(em1.hasEffectiveTime());
+        assertNull(em1.getEffectiveTime());
+
+        em2.clearEffectiveTime();
+        assertFalse(em2.hasEffectiveTime());
+        assertNull(em2.getEffectiveTime());
+    }
+
+    @Test
+    public void verifyCurrentCreateTemporal() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+
+        PersonHobby ph = em.newTemporal(PersonHobby.class);
+
+        Assert.assertNotNull(ph);
+        Assert.assertNotNull(ph.getEffectivity());
+        Assert.assertEquals(BOT, ph.getEffectivity().getStart());
+        Assert.assertEquals(EOT, ph.getEffectivity().getEnd());
+    }
+
+    @Test
+    public void verifyFutureCreateTemporal() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T3, true);
+        em.getTransaction().begin();
+
+        PersonHobby ph = em.newTemporal(PersonHobby.class);
+
+        Assert.assertNotNull(ph);
+        Assert.assertNotNull(ph.getEffectivity());
+        Assert.assertEquals(T3, ph.getEffectivity().getStart());
+        Assert.assertEquals(EOT, ph.getEffectivity().getEnd());
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/TemporalEntityTests.java b/Temporal Entity Example/test-src/tests/internal/TemporalEntityTests.java
new file mode 100644
index 0000000..a27c535
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/TemporalEntityTests.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import static temporal.Effectivity.BOT;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import temporal.BaseTemporalEntity;
+import temporal.TemporalEntity;
+
+/**
+ * Simple tests verifying the functionality of the interfaces and base classes
+ * used in this temporal extension framework.
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+
+public class TemporalEntityTests {
+
+    @Test
+    public void verifyTestEntityConstructor() {
+        TestEntity entity = new TestEntityImpl();
+
+        Assert.assertNotNull(entity.getEffectivity());
+        Assert.assertNull(entity.getContinuity());
+        Assert.assertNull(entity.getPreviousEdition());
+        Assert.assertEquals(0, entity.getVersion());
+        Assert.assertEquals(BOT, entity.getEffectivity().getStart());
+    }
+
+    @Test
+    public void verifyTestEntityEditionConstructor() {
+        TestEntity entity = new TestEntityEdition();
+
+        Assert.assertNotNull(entity.getEffectivity());
+        Assert.assertNull(entity.getContinuity());
+        Assert.assertNull(entity.getPreviousEdition());
+        Assert.assertEquals(0, entity.getVersion());
+        Assert.assertEquals(BOT, entity.getEffectivity().getStart());
+    }
+
+    @Test
+    public void verifyTestEntityEditionViewConstructor() {
+        TestEntity entity = new TestEntityEditionView();
+
+        Assert.assertNotNull(entity.getEffectivity());
+        Assert.assertNull(entity.getContinuity());
+        Assert.assertNull(entity.getPreviousEdition());
+        Assert.assertEquals(0, entity.getVersion());
+        Assert.assertEquals(BOT, entity.getEffectivity().getStart());
+    }
+
+    @Test
+    public void testIsContinuity() {
+        TestEntity entity = new TestEntityEditionView();
+
+        Assert.assertFalse(entity.isContinuity());
+
+        entity.setId(1);
+        entity.setContinuity(entity);
+
+        Assert.assertTrue(entity.isContinuity());
+    }
+
+    /**
+     * Static test classes
+     */
+
+    public static interface TestEntity extends TemporalEntity<TestEntity> {
+        void setId(int id);
+    }
+
+    public static class TestEntityImpl extends BaseTemporalEntity<TestEntity> implements TestEntity {
+
+        @Override
+        public void setId(int id) {
+            super.setId(id);
+        }
+
+    }
+
+    public static class TestEntityEdition extends TestEntityImpl {
+
+    }
+
+    public static class TestEntityEditionView extends TestEntityEdition {
+
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/TemporalHelperTests.java b/Temporal Entity Example/test-src/tests/internal/TemporalHelperTests.java
new file mode 100644
index 0000000..c6ce20e
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/TemporalHelperTests.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import static example.PersonModelExample.T1;
+import static temporal.Effectivity.*;
+import static example.PersonModelExample.T3;
+import static example.PersonModelExample.T4;
+import static example.PersonModelExample.T5;
+import static example.PersonModelExample.T6;
+import static example.PersonModelExample.T7;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import junit.framework.Assert;
+
+import model.PersonHobby;
+
+import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
+import org.eclipse.persistence.sessions.DatabaseSession;
+import org.eclipse.persistence.sessions.server.ClientSession;
+import org.eclipse.persistence.sessions.server.Server;
+import org.junit.Test;
+
+import temporal.TemporalEntityManager;
+import temporal.TemporalHelper;
+import tests.BaseTestCase;
+
+/**
+ * Verify the helper methods on {@link TemporalHelper}
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class TemporalHelperTests extends BaseTestCase {
+
+    private void verifySetStartTime(TemporalEntityManager em, Long value) {
+        assertTrue(em.hasEffectiveTime());
+        assertNotNull(em.getEffectiveTime());
+        assertEquals(value, em.getEffectiveTime());
+
+        RepeatableWriteUnitOfWork uow = em.unwrap(RepeatableWriteUnitOfWork.class);
+        assertNotNull(uow);
+
+        ClientSession clientSession = (ClientSession) uow.getParent();
+
+        DatabaseSession session = em.unwrap(DatabaseSession.class);
+        assertNotSame(clientSession, session);
+
+        Server serverSession = em.unwrap(Server.class);
+        assertNotSame(clientSession, serverSession);
+        assertSame(session, serverSession);
+    }
+
+    @Test
+    public void verifySetStartTime() {
+        TemporalEntityManager em = getEntityManager();
+
+        assertFalse(em.hasEffectiveTime());
+        assertNull(em.getEffectiveTime());
+
+        em.setEffectiveTime(T1);
+
+        verifySetStartTime(em, T1);
+    }
+
+    @Test
+    public void verifyClearStartTime() {
+        TemporalEntityManager em = getEntityManager();
+        assertFalse(em.hasEffectiveTime());
+        assertNull(em.getEffectiveTime());
+
+        em.setEffectiveTime(T3);
+
+        verifySetStartTime(em, T3);
+
+        em.clearEffectiveTime();
+
+        assertFalse(em.hasEffectiveTime());
+        assertNull(em.getEffectiveTime());
+    }
+
+    @Test
+    public void verifyConcurrentSetStartTime() {
+        TemporalEntityManager em1 = getEntityManager();
+        TemporalEntityManager em2 = TemporalEntityManager.getInstance(getEMF().createEntityManager());
+
+        assertNotSame(em1, em2);
+
+        em1.setEffectiveTime(T4);
+
+        em2.setEffectiveTime(T5);
+
+        verifySetStartTime(em2, T5);
+        verifySetStartTime(em1, T4);
+    }
+
+    @Test
+    public void verifyConcurrentClearStartTime() {
+        TemporalEntityManager em1 = getEntityManager();
+        TemporalEntityManager em2 = TemporalEntityManager.getInstance(getEMF().createEntityManager());
+
+        assertNotSame(em1, em2);
+
+        em1.setEffectiveTime(T6);
+        em2.setEffectiveTime(T7);
+
+        verifySetStartTime(em2, T7);
+        verifySetStartTime(em1, T6);
+
+        em1.clearEffectiveTime();
+        verifySetStartTime(em2, T7);
+        assertFalse(em1.hasEffectiveTime());
+        assertNull(em1.getEffectiveTime());
+
+        em2.clearEffectiveTime();
+        assertFalse(em2.hasEffectiveTime());
+        assertNull(em2.getEffectiveTime());
+    }
+
+    @Test
+    public void verifyCurrentCreateTemporal() {
+        TemporalEntityManager em = getEntityManager();
+        em.getTransaction().begin();
+
+        PersonHobby ph = em.newTemporal(PersonHobby.class);
+
+        Assert.assertNotNull(ph);
+        Assert.assertNotNull(ph.getEffectivity());
+        Assert.assertEquals(BOT, ph.getEffectivity().getStart());
+        Assert.assertEquals(EOT, ph.getEffectivity().getEnd());
+    }
+
+    @Test
+    public void verifyFutureCreateTemporal() {
+        TemporalEntityManager em = getEntityManager();
+        em.setEffectiveTime(T3, true);
+        em.getTransaction().begin();
+
+        PersonHobby ph = em.newTemporal(PersonHobby.class);
+
+        Assert.assertNotNull(ph);
+        Assert.assertNotNull(ph.getEffectivity());
+        Assert.assertEquals(T3, ph.getEffectivity().getStart());
+        Assert.assertEquals(EOT, ph.getEffectivity().getEnd());
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/VerifyConfigTests.java b/Temporal Entity Example/test-src/tests/internal/VerifyConfigTests.java
new file mode 100644
index 0000000..a4a8809
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/VerifyConfigTests.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import junit.framework.Assert;
+import model.Address;
+import model.Hobby;
+import model.Person;
+import model.PersonHobby;
+import model.Phone;
+import model.entities.AddressEntity;
+import model.entities.PersonEntity;
+import model.entities.PhoneEntity;
+
+import org.eclipse.persistence.config.CacheIsolationType;
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.internal.weaving.PersistenceWeaved;
+import org.eclipse.persistence.internal.weaving.PersistenceWeavedChangeTracking;
+import org.eclipse.persistence.internal.weaving.PersistenceWeavedFetchGroups;
+import org.eclipse.persistence.internal.weaving.PersistenceWeavedLazy;
+import org.eclipse.persistence.jpa.JpaHelper;
+import org.eclipse.persistence.mappings.OneToManyMapping;
+import org.eclipse.persistence.mappings.OneToOneMapping;
+import org.eclipse.persistence.sessions.Session;
+import org.eclipse.persistence.sessions.server.Server;
+import org.junit.Test;
+
+import temporal.Effectivity;
+import temporal.TemporalEdition;
+import temporal.TemporalEntity;
+import temporal.TemporalHelper;
+import temporal.persistence.DescriptorHelper;
+import tests.BaseTestCase;
+
+/**
+ * Tests that verify the descriptors are setup as expected and that the
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class VerifyConfigTests extends BaseTestCase {
+
+    @Test
+    public void verifyDescriptorsExist() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        Assert.assertNotNull(session);
+        Assert.assertTrue(session.isConnected());
+        Assert.assertEquals(21, session.getDescriptors().size());
+
+        Assert.assertNotNull(session.getClassDescriptorForAlias("Person"));
+        Assert.assertNotNull(session.getClassDescriptor(PersonEntity.class));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("Address"));
+        Assert.assertNotNull(session.getClassDescriptor(AddressEntity.class));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("Phone"));
+        Assert.assertNotNull(session.getClassDescriptor(PhoneEntity.class));
+        Assert.assertNotNull(session.getClassDescriptor(Effectivity.class));
+
+        Assert.assertNotNull(session.getClassDescriptorForAlias("Hobby"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("PersonHobby"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("EditionSet"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("EditionSetEntry"));
+
+        Assert.assertNotNull(session.getClassDescriptorForAlias("PersonEdition"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("AddressEdition"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("PhoneEdition"));
+
+        Assert.assertNotNull(session.getClassDescriptorForAlias("PersonEditionView"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("AddressEditionView"));
+        Assert.assertNotNull(session.getClassDescriptorForAlias("PhoneEditionView"));
+    }
+
+    @Test
+    public void verifyInterface() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        Assert.assertSame(Person.class, session.getClassDescriptor(PersonEntity.class).getProperty(TemporalHelper.INTERFACE));
+        Assert.assertSame(Person.class, session.getClassDescriptor(Person.class).getProperty(TemporalHelper.INTERFACE));
+        Assert.assertSame(Address.class, session.getClassDescriptor(AddressEntity.class).getProperty(TemporalHelper.INTERFACE));
+        Assert.assertSame(Address.class, session.getClassDescriptor(Address.class).getProperty(TemporalHelper.INTERFACE));
+        Assert.assertSame(Phone.class, session.getClassDescriptor(PhoneEntity.class).getProperty(TemporalHelper.INTERFACE));
+        Assert.assertSame(Phone.class, session.getClassDescriptor(Phone.class).getProperty(TemporalHelper.INTERFACE));
+    }
+
+    @Test
+    public void verifyWeavingPerson() {
+        Assert.assertTrue(PersistenceWeaved.class.isAssignableFrom(PersonEntity.class));
+        Assert.assertTrue(PersistenceWeavedLazy.class.isAssignableFrom(PersonEntity.class));
+        Assert.assertTrue(PersistenceWeavedChangeTracking.class.isAssignableFrom(PersonEntity.class));
+        Assert.assertTrue(PersistenceWeavedFetchGroups.class.isAssignableFrom(PersonEntity.class));
+        Assert.assertFalse(TemporalEdition.class.isAssignableFrom(PersonEntity.class));
+    }
+
+    @Test
+    public void verifyWeavingAddress() {
+        Assert.assertTrue(PersistenceWeaved.class.isAssignableFrom(AddressEntity.class));
+        Assert.assertTrue(PersistenceWeavedLazy.class.isAssignableFrom(AddressEntity.class));
+        Assert.assertTrue(PersistenceWeavedChangeTracking.class.isAssignableFrom(AddressEntity.class));
+        Assert.assertTrue(PersistenceWeavedFetchGroups.class.isAssignableFrom(AddressEntity.class));
+        Assert.assertFalse(TemporalEdition.class.isAssignableFrom(AddressEntity.class));
+    }
+
+    @Test
+    public void verifyWeavingPhone() {
+        Assert.assertTrue(PersistenceWeaved.class.isAssignableFrom(PhoneEntity.class));
+        Assert.assertTrue(PersistenceWeavedLazy.class.isAssignableFrom(PhoneEntity.class));
+        Assert.assertTrue(PersistenceWeavedChangeTracking.class.isAssignableFrom(PhoneEntity.class));
+        Assert.assertTrue(PersistenceWeavedFetchGroups.class.isAssignableFrom(PhoneEntity.class));
+        Assert.assertFalse(TemporalEdition.class.isAssignableFrom(PhoneEntity.class));
+    }
+
+    @Test
+    public void verifyAttributeChangeTracking() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        assertAttributeChangeTracking(session, "Person");
+        assertAttributeChangeTracking(session, "Address");
+        assertAttributeChangeTracking(session, "Phone");
+    }
+
+    @Test
+    public void verifyEntityDescriptors() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        for (String alias : new String[] { "Person", "Address", "Phone" }) {
+            ClassDescriptor descriptor = session.getClassDescriptorForAlias(alias);
+
+            Assert.assertNotNull(descriptor);
+            Assert.assertNotNull(descriptor.getQueryManager().getAdditionalJoinExpression());
+            Assert.assertFalse(descriptor.shouldBeReadOnly());
+            Assert.assertFalse(descriptor.isIsolated());
+            Assert.assertTrue(descriptor.getObjectChangePolicy().isAttributeChangeTrackingPolicy());
+
+            Assert.assertEquals(1, descriptor.getPrimaryKeyFieldNames().size());
+            Assert.assertEquals("OID", descriptor.getPrimaryKeyFields().get(0).getName());
+
+            Assert.assertEquals(CacheIsolationType.PROTECTED, descriptor.getCacheIsolation());
+        }
+    }
+
+    /**
+     * Verify the {@link PersonHobby} and {@link Hobby} mappings are correct.
+     * These mappings are temporal but they are not {@link TemporalEntity}
+     */
+    @Test
+    public void verifyPersonHobbyMappings() {
+        Server session = JpaHelper.getServerSession(getEMF());
+        ClassDescriptor phDesc = session.getDescriptorForAlias("PersonHobby");
+        Assert.assertNotNull(phDesc);
+        
+        OneToOneMapping personMapping = (OneToOneMapping) phDesc.getMappingForAttributeName("person");
+        Assert.assertNotNull(personMapping);
+        Assert.assertSame(PersonEntity.class, personMapping.getReferenceClass());
+        
+        Assert.assertEquals(1, personMapping.getForeignKeyFields().size());
+        DatabaseField fkField = personMapping.getForeignKeyFields().firstElement();
+        Assert.assertEquals("PERSON_ID", fkField.getName());
+        
+        DatabaseField targetField = personMapping.getSourceToTargetKeyFields().get(fkField);
+        Assert.assertEquals("CID", targetField.getName());
+    }
+
+    @Test
+    public void verifyEditionDescriptors() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        for (String alias : new String[] { "Person", "Address", "Phone" }) {
+            ClassDescriptor descriptor = session.getClassDescriptorForAlias(alias + DescriptorHelper.EDITION);
+
+            Assert.assertNotNull(descriptor);
+            Assert.assertNotNull(descriptor.getQueryManager().getAdditionalJoinExpression());
+            Assert.assertFalse(descriptor.shouldBeReadOnly());
+            Assert.assertTrue(descriptor.isIsolated());
+            Assert.assertTrue(descriptor.getObjectChangePolicy().isAttributeChangeTrackingPolicy());
+
+            Assert.assertEquals(1, descriptor.getPrimaryKeyFieldNames().size());
+            Assert.assertEquals("OID", descriptor.getPrimaryKeyFields().get(0).getName());
+
+            Assert.assertEquals(CacheIsolationType.ISOLATED, descriptor.getCacheIsolation());
+        }
+    }
+
+    @Test
+    public void verifyEditionViewDescriptors() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        for (String alias : new String[] { "Person", "Address", "Phone" }) {
+            ClassDescriptor descriptor = session.getClassDescriptorForAlias(alias + DescriptorHelper.EDITION_VIEW);
+
+            Assert.assertNotNull(descriptor);
+            Assert.assertNull(descriptor.getQueryManager().getAdditionalJoinExpression());
+            Assert.assertTrue(descriptor.getObjectChangePolicy().isAttributeChangeTrackingPolicy());
+            Assert.assertTrue(descriptor.isIsolated());
+            Assert.assertEquals(1, descriptor.getPrimaryKeyFieldNames().size());
+            Assert.assertEquals("OID", descriptor.getPrimaryKeyFields().get(0).getName());
+
+            Assert.assertEquals(CacheIsolationType.ISOLATED, descriptor.getCacheIsolation());
+        }
+    }
+
+    private void assertAttributeChangeTracking(Session session, String alias) {
+        ClassDescriptor descriptor = session.getClassDescriptorForAlias(alias);
+        Assert.assertNotNull(descriptor);
+        Assert.assertTrue(descriptor.getObjectChangePolicy().isAttributeChangeTrackingPolicy());
+
+        if (TemporalEntity.class.isAssignableFrom(descriptor.getJavaClass()) && !descriptor.getAlias().endsWith(DescriptorHelper.EDITION)) {
+            assertAttributeChangeTracking(session, alias + DescriptorHelper.EDITION);
+        }
+    }
+
+    @Test
+    public void verifyPersonPhonesDescriptor() {
+        Server session = JpaHelper.getServerSession(getEMF());
+        ClassDescriptor descriptor = session.getClassDescriptorForAlias("Person");
+
+        Assert.assertNotNull(descriptor);
+        Assert.assertEquals(PersonEntity.class, descriptor.getJavaClass());
+
+        OneToManyMapping phonesMapping = (OneToManyMapping) descriptor.getMappingForAttributeName("phones");
+        Assert.assertNotNull(phonesMapping);
+
+        Assert.assertEquals("Phone", phonesMapping.getReferenceDescriptor().getAlias());
+        Assert.assertTrue(phonesMapping.isCacheable());
+
+        // TODO: Verify FK fields
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/VerifySchemaManager.java b/Temporal Entity Example/test-src/tests/internal/VerifySchemaManager.java
new file mode 100644
index 0000000..bf211c2
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/VerifySchemaManager.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import junit.framework.Assert;
+
+import org.eclipse.persistence.tools.schemaframework.ForeignKeyConstraint;
+import org.eclipse.persistence.tools.schemaframework.SchemaManager;
+import org.eclipse.persistence.tools.schemaframework.TableDefinition;
+import org.junit.Test;
+
+import temporal.persistence.TemporalSchemaManager;
+import tests.BaseTestCase;
+
+/**
+ * Verify the schema manager's table definitions
+ */
+public class VerifySchemaManager extends BaseTestCase {
+
+    private SchemaManager getSchemaManager() {
+        return (SchemaManager) getEMF().getProperties().get(SchemaManager.class.getName());
+    }
+
+    private TemporalSchemaManager getTemporalSchemaManager() {
+        return (TemporalSchemaManager) getSchemaManager();
+    }
+
+    @Test
+    public void verifySchemaManager() {
+        SchemaManager sm = getSchemaManager();
+        Assert.assertNotNull(sm);
+        Assert.assertTrue(sm instanceof TemporalSchemaManager);
+        Assert.assertSame(sm, getTemporalSchemaManager());
+        Assert.assertNotNull(getTemporalSchemaManager().getTableCreator());
+    }
+
+    @Test
+    public void verifyPhoneTable() {
+        TableDefinition td = getTemporalSchemaManager().getTableDefinition("TPHONE");
+        Assert.assertNotNull(td);
+
+        ForeignKeyConstraint fkc = td.getForeignKeyMap().get("FK_TPHONE_PERSON_ID");
+        Assert.assertNotNull(fkc);
+        Assert.assertEquals("OID", fkc.getTargetFields().get(0));
+    }
+
+    @Test
+    public void verifyPersonHobbyTable() {
+        TableDefinition td = getTemporalSchemaManager().getTableDefinition("TPERSON_HOBBY");
+        Assert.assertNotNull(td);
+
+        ForeignKeyConstraint fkc = td.getForeignKeyMap().get("FK_TPERSON_HOBBY_PERSON_ID");
+        Assert.assertNotNull(fkc);
+        Assert.assertEquals("OID", fkc.getTargetFields().get(0));
+    }
+
+    @Test
+    public void verifyPersonTable() {
+        TableDefinition td = getTemporalSchemaManager().getTableDefinition("TPERSON");
+        Assert.assertNotNull(td);
+
+        ForeignKeyConstraint fkc = td.getForeignKeyMap().get("FK_TPERSON_ADDR_ID");
+        Assert.assertNotNull(fkc);
+        Assert.assertEquals("OID", fkc.getTargetFields().get(0));
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/WrapperPolicyTests.java b/Temporal Entity Example/test-src/tests/internal/WrapperPolicyTests.java
new file mode 100644
index 0000000..d89200f
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/WrapperPolicyTests.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2012 Oracle. 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: dclarke - Bug 361016: Future Versions Examples
+ ******************************************************************************/
+package tests.internal;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+
+import junit.framework.Assert;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.jpa.JpaHelper;
+import org.eclipse.persistence.sessions.server.Server;
+import org.junit.Test;
+
+import temporal.TemporalHelper;
+import temporal.persistence.DescriptorHelper;
+import temporal.persistence.EditionWrapperPolicy;
+import tests.BaseTestCase;
+
+/**
+ * Verify the helper methods on {@link TemporalHelper}
+ * 
+ * @author dclarke
+ * @since EclipseLink 2.3.1
+ */
+public class WrapperPolicyTests extends BaseTestCase {
+
+    @Test
+    public void verifyConfig() {
+        Server session = JpaHelper.getServerSession(getEMF());
+
+        Assert.assertNotNull(session);
+
+        for (String alias : new String[] { "Person", "Address", "Phone" }) {
+            ClassDescriptor cd = session.getClassDescriptorForAlias(alias);
+            Assert.assertNotNull(cd);
+            Assert.assertTrue(cd.hasWrapperPolicy());
+            Assert.assertTrue(cd.getWrapperPolicy() instanceof EditionWrapperPolicy);
+
+            cd = session.getClassDescriptorForAlias(alias + DescriptorHelper.EDITION);
+            Assert.assertNotNull(cd);
+            Assert.assertTrue(cd.hasWrapperPolicy());
+            Assert.assertTrue(cd.getWrapperPolicy() instanceof EditionWrapperPolicy);
+        }
+    }
+
+    @Test
+    public void createEntityAndDescriptorLookupUsingProxy() {
+        Server session = JpaHelper.getServerSession(getEMF());
+        Assert.assertNotNull(session);
+
+        for (String alias : new String[] { "Person", "Address", "Phone" }) {
+            ClassDescriptor cd = session.getClassDescriptorForAlias(alias);
+            Assert.assertNotNull(cd);
+            
+            Object entity = cd.getInstantiationPolicy().buildNewInstance();
+            Assert.assertNotNull(entity);
+            Assert.assertFalse(cd.getWrapperPolicy().isWrapped(entity));
+            
+            Object wrappedEnObject = cd.getWrapperPolicy().wrapObject(entity, (AbstractSession) session);
+            
+            Assert.assertNotNull(wrappedEnObject);
+            Assert.assertTrue(cd.getWrapperPolicy().isWrapped(wrappedEnObject));
+            Assert.assertTrue(Proxy.isProxyClass(wrappedEnObject.getClass()));
+            InvocationHandler handler = Proxy.getInvocationHandler(wrappedEnObject);
+            Assert.assertTrue(handler instanceof EditionWrapperPolicy.Handler<?>);
+            
+            ClassDescriptor lookupCD = session.getClassDescriptor(wrappedEnObject);
+            Assert.assertNotNull(lookupCD);
+            Assert.assertSame(cd, lookupCD);
+        }
+    }
+
+    @Test
+    public void createEditionAndDescriptorLookupUsingProxy() {
+        Server session = JpaHelper.getServerSession(getEMF());
+        Assert.assertNotNull(session);
+
+        for (String alias : new String[] { "Person", "Address", "Phone" }) {
+            ClassDescriptor cd = session.getClassDescriptorForAlias(alias+ DescriptorHelper.EDITION);
+            Assert.assertNotNull(cd);
+            
+            Object entity = cd.getInstantiationPolicy().buildNewInstance();
+            Assert.assertNotNull(entity);
+            Assert.assertFalse(cd.getWrapperPolicy().isWrapped(entity));
+            
+            Object wrappedEnObject = cd.getWrapperPolicy().wrapObject(entity, (AbstractSession) session);
+            
+            Assert.assertNotNull(wrappedEnObject);
+            Assert.assertTrue(Proxy.isProxyClass(wrappedEnObject.getClass()));
+            InvocationHandler handler = Proxy.getInvocationHandler(wrappedEnObject);
+            Assert.assertTrue(handler instanceof EditionWrapperPolicy.Handler<?>);
+            
+            ClassDescriptor lookupCD = session.getClassDescriptor(wrappedEnObject);
+            Assert.assertNotNull(lookupCD);
+            Assert.assertSame(cd, lookupCD);
+        }
+    }
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/asm/ASMifyPersonEdition.java b/Temporal Entity Example/test-src/tests/internal/asm/ASMifyPersonEdition.java
new file mode 100644
index 0000000..7f2b90b
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/asm/ASMifyPersonEdition.java
@@ -0,0 +1,15 @@
+package tests.internal.asm;
+
+import org.eclipse.persistence.internal.libraries.asm.util.ASMifierClassVisitor;
+
+public class ASMifyPersonEdition {
+
+    /**
+     * @param args
+     * @throws Exception 
+     */
+    public static void main(String[] args) throws Exception {
+        ASMifierClassVisitor.main(new String[] { PersonEdition.class.getName()});
+    }
+
+}
diff --git a/Temporal Entity Example/test-src/tests/internal/asm/PersonEdition.java b/Temporal Entity Example/test-src/tests/internal/asm/PersonEdition.java
new file mode 100644
index 0000000..5d2fff0
--- /dev/null
+++ b/Temporal Entity Example/test-src/tests/internal/asm/PersonEdition.java
@@ -0,0 +1,7 @@
+package tests.internal.asm;
+
+import model.Person;
+
+public interface PersonEdition extends Person {
+
+}