You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by th...@apache.org on 2014/02/17 16:14:31 UTC

git commit: Fixes the tapestry-jpa failing tests. In addition, changes in order to support @CommitAfter and @PersistenceConstants annotations in service implementation methods

Repository: tapestry-5
Updated Branches:
  refs/heads/master 6b4e7a04c -> d4e7a3281


Fixes the tapestry-jpa failing tests. In addition, changes in order to
support @CommitAfter and @PersistenceConstants annotations in service
implementation methods

Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/d4e7a328
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/d4e7a328
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/d4e7a328

Branch: refs/heads/master
Commit: d4e7a32818d2ff849e54375c364ab2075133dfa4
Parents: 6b4e7a0
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Mon Feb 17 12:14:14 2014 -0300
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Mon Feb 17 12:14:14 2014 -0300

----------------------------------------------------------------------
 .../internal/jpa/CommitAfterMethodAdvice.java   |  81 +++++----
 .../internal/jpa/CommitAfterWorker.java         |   6 +-
 .../internal/jpa/JpaTransactionAdvisorImpl.java |  26 +--
 tapestry-jpa/src/test/app6/CommitAfterDemo.tml  |  26 +++
 tapestry-jpa/src/test/app6/EncodeEntities.tml   |  14 ++
 .../src/test/app6/EncodeTransientEntities.tml   |  10 ++
 tapestry-jpa/src/test/app6/GridDemo.tml         |  17 ++
 tapestry-jpa/src/test/app6/Index.tml            |  14 ++
 tapestry-jpa/src/test/app6/PersistEntity.tml    |  25 +++
 tapestry-jpa/src/test/app6/PersistThang.tml     |  25 +++
 tapestry-jpa/src/test/app6/SSOEntity.tml        |  10 ++
 tapestry-jpa/src/test/app6/WEB-INF/web.xml      |  35 ++++
 tapestry-jpa/src/test/conf/testng.xml           |  62 ++++---
 .../jpa/JpaTransactionAdvisorImplTest.java      |  15 ++
 ...tWithAnnotationsInServiceImplementation.java | 171 +++++++++++++++++++
 .../java/org/example/app6/AppConstants.java     |  22 +++
 .../java/org/example/app6/entities/Thang.java   |  50 ++++++
 .../java/org/example/app6/entities/User.java    |  99 +++++++++++
 .../org/example/app6/pages/CommitAfterDemo.java | 101 +++++++++++
 .../org/example/app6/pages/EncodeEntities.java  |  66 +++++++
 .../app6/pages/EncodeTransientEntities.java     |  34 ++++
 .../java/org/example/app6/pages/GridDemo.java   |  73 ++++++++
 .../test/java/org/example/app6/pages/Index.java |  43 +++++
 .../org/example/app6/pages/PersistEntity.java   |  75 ++++++++
 .../org/example/app6/pages/PersistThang.java    |  76 +++++++++
 .../java/org/example/app6/pages/SSOEntity.java  |  73 ++++++++
 .../org/example/app6/services/AppModule.java    |  88 ++++++++++
 .../java/org/example/app6/services/UserDAO.java |  30 ++++
 .../example/app6/services/impl/UserDAOImpl.java |  64 +++++++
 29 files changed, 1341 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java
index 76fcc58..f0f1d28 100644
--- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java
+++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java
@@ -1,4 +1,4 @@
-// Copyright 2011, 2012 The Apache Software Foundation
+// Copyright 2011, 2012, 2014 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,54 +14,63 @@
 
 package org.apache.tapestry5.internal.jpa;
 
-import org.apache.tapestry5.jpa.EntityManagerManager;
-import org.apache.tapestry5.plastic.MethodAdvice;
-import org.apache.tapestry5.plastic.MethodInvocation;
-
 import javax.persistence.EntityManager;
 import javax.persistence.EntityTransaction;
 import javax.persistence.PersistenceContext;
 
+import org.apache.tapestry5.jpa.EntityManagerManager;
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.apache.tapestry5.plastic.MethodAdvice;
+import org.apache.tapestry5.plastic.MethodInvocation;
+
 public class CommitAfterMethodAdvice implements MethodAdvice
 {
     private final EntityManagerManager manager;
 
-    private final PersistenceContext annotation;
-
-    public CommitAfterMethodAdvice(final EntityManagerManager manager, PersistenceContext annotation)
+    public CommitAfterMethodAdvice(final EntityManagerManager manager)
     {
         this.manager = manager;
-        this.annotation = annotation;
     }
 
     public void advise(final MethodInvocation invocation)
     {
-        final EntityTransaction transaction = getTransaction();
-
-        if (transaction != null && !transaction.isActive())
-        {
-            transaction.begin();
-        }
-
-        try
-        {
-            invocation.proceed();
-        } catch (final RuntimeException e)
-        {
-            if (transaction != null && transaction.isActive())
-            {
-                rollbackTransaction(transaction);
-            }
-
-            throw e;
-        }
-
-        // Success or checked exception:
-
-        if (transaction != null && transaction.isActive())
-        {
-            transaction.commit();
-        }
+    	
+    	if (invocation.hasAnnotation(CommitAfter.class))
+    	{
+    	
+			final PersistenceContext annotation = invocation.getAnnotation(PersistenceContext.class);
+	        final EntityTransaction transaction = getTransaction(annotation);
+	
+	        if (transaction != null && !transaction.isActive())
+	        {
+	            transaction.begin();
+	        }
+	
+	        try
+	        {
+	            invocation.proceed();
+	        } catch (final RuntimeException e)
+	        {
+	            if (transaction != null && transaction.isActive())
+	            {
+	                rollbackTransaction(transaction);
+	            }
+	
+	            throw e;
+	        }
+	
+	        // Success or checked exception:
+	
+	        if (transaction != null && transaction.isActive())
+	        {
+	            transaction.commit();
+	        }
+	        
+    	}
+    	else
+    	{
+    		invocation.proceed();
+    	}
 
     }
 
@@ -75,7 +84,7 @@ public class CommitAfterMethodAdvice implements MethodAdvice
         }
     }
 
-    private EntityTransaction getTransaction()
+    private EntityTransaction getTransaction(PersistenceContext annotation)
     {
         EntityManager em = JpaInternalUtils.getEntityManager(manager, annotation);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java
index 80f8194..fc9ff8a 100644
--- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java
+++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2014 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ public class CommitAfterWorker implements ComponentClassTransformWorker2
     {
         this.manager = manager;
 
-        shared = new CommitAfterMethodAdvice(manager, null);
+        shared = new CommitAfterMethodAdvice(manager);
     }
 
     public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
@@ -46,7 +46,7 @@ public class CommitAfterWorker implements ComponentClassTransformWorker2
         {
             PersistenceContext annotation = method.getAnnotation(PersistenceContext.class);
 
-            MethodAdvice advice = annotation == null ? shared : new CommitAfterMethodAdvice(manager, annotation);
+            MethodAdvice advice = annotation == null ? shared : new CommitAfterMethodAdvice(manager);
 
             method.addAdvice(advice);
         }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java
index 5793f17..ad4abef 100644
--- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java
+++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2015 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -17,41 +17,19 @@ package org.apache.tapestry5.internal.jpa;
 import org.apache.tapestry5.ioc.MethodAdviceReceiver;
 import org.apache.tapestry5.jpa.EntityManagerManager;
 import org.apache.tapestry5.jpa.JpaTransactionAdvisor;
-import org.apache.tapestry5.jpa.annotations.CommitAfter;
-import org.apache.tapestry5.plastic.MethodAdvice;
-
-import javax.persistence.PersistenceContext;
-import java.lang.reflect.Method;
 
 public class JpaTransactionAdvisorImpl implements JpaTransactionAdvisor
 {
     private final EntityManagerManager manager;
 
-    private final MethodAdvice shared;
-
-
     public JpaTransactionAdvisorImpl(EntityManagerManager manager)
     {
         this.manager = manager;
-
-        shared = new CommitAfterMethodAdvice(manager, null);
     }
 
     public void addTransactionCommitAdvice(final MethodAdviceReceiver receiver)
     {
-        for (final Method m : receiver.getInterface().getMethods())
-        {
-            if (m.getAnnotation(CommitAfter.class) != null)
-            {
-                PersistenceContext annotation = receiver.getMethodAnnotation(m, PersistenceContext.class);
-
-                MethodAdvice advice =
-                        annotation == null ? shared : new CommitAfterMethodAdvice(manager, annotation);
-
-                receiver.adviseMethod(m, advice);
-            }
-        }
-
+    	receiver.adviseAllMethods(new CommitAfterMethodAdvice(manager));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/CommitAfterDemo.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/CommitAfterDemo.tml b/tapestry-jpa/src/test/app6/CommitAfterDemo.tml
new file mode 100644
index 0000000..db25443
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/CommitAfterDemo.tml
@@ -0,0 +1,26 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    <body>
+        <p>Entity name:
+            <span id="name">${user?.firstName}</span>
+        </p>
+
+        <ul>
+            <li>
+                <t:eventlink event="changeName">change name</t:eventlink>
+                (succesfully)
+            </li>
+
+            <li>
+                <t:eventlink event="changeNameWithRuntimeException">runtime exception</t:eventlink>
+                (will abort, so no change)
+            </li>
+
+            <li>
+                <t:eventlink event="changeNameWithCheckedException">checked exception</t:eventlink>
+                (will commit, so we'll see the change)
+            </li>
+        </ul>
+
+
+    </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/EncodeEntities.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/EncodeEntities.tml b/tapestry-jpa/src/test/app6/EncodeEntities.tml
new file mode 100644
index 0000000..f9479f9
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/EncodeEntities.tml
@@ -0,0 +1,14 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
+	<body>
+		<p>
+			entity name:
+			<span id="name">
+				<t:if test="user">${user.firstName}</t:if>
+			</span>
+		</p>
+		<p>
+			create entity:
+			<t:eventlink event="create" t:id="createentity">create an entity</t:eventlink>
+		</p>
+	</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/EncodeTransientEntities.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/EncodeTransientEntities.tml b/tapestry-jpa/src/test/app6/EncodeTransientEntities.tml
new file mode 100644
index 0000000..011543a
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/EncodeTransientEntities.tml
@@ -0,0 +1,10 @@
+<html xmlns:t='http://tapestry.apache.org/schema/tapestry_5_3.xsd'>
+    <body>
+
+        <form t:type='form' action=''>
+            <input t:type='textField' t:value='user.email'/>
+            <input type='button' id='doNothingButton' value='Do Nothing'/>
+        </form>
+
+    </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/GridDemo.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/GridDemo.tml b/tapestry-jpa/src/test/app6/GridDemo.tml
new file mode 100644
index 0000000..04a0be5
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/GridDemo.tml
@@ -0,0 +1,17 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
+	<head>
+		<title>Grid Data Source Demo</title>
+	</head>
+	<body>
+		<h2>Demo of the JPA GridDataSource
+        </h2>
+
+		<t:grid source="source" />
+
+		<p>
+			<t:actionlink t:id="setup">setup</t:actionlink>
+			the data
+		</p>
+
+	</body>
+</html>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/Index.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/Index.tml b/tapestry-jpa/src/test/app6/Index.tml
new file mode 100644
index 0000000..32003e9
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/Index.tml
@@ -0,0 +1,14 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    <head>
+        <title>Start Page</title>
+    </head>
+    <body>
+        <h2>Test application for tapestry-jpa integration tests</h2>
+
+        <ul>
+            <li>
+                <t:actionlink t:id="commitAfter">CommitAfter Demo</t:actionlink>
+            </li>
+        </ul>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/PersistEntity.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/PersistEntity.tml b/tapestry-jpa/src/test/app6/PersistEntity.tml
new file mode 100644
index 0000000..02ed94c
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/PersistEntity.tml
@@ -0,0 +1,25 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
+	<body>
+		<p>
+			entity name:
+			<span id="name">
+				<t:if test="user">${user.firstName}</t:if>
+			</span>
+		</p>
+		<p>
+			<t:eventlink event="createEntity">create entity</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="changeName">change the name</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="setToNull">set to null</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="delete">delete</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="setToTransient">set to transient</t:eventlink>
+		</p>
+	</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/PersistThang.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/PersistThang.tml b/tapestry-jpa/src/test/app6/PersistThang.tml
new file mode 100644
index 0000000..1f4e928
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/PersistThang.tml
@@ -0,0 +1,25 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
+	<body>
+		<p>
+			entity name:
+			<span id="name">
+				<t:if test="thang">${thang.name}</t:if>
+			</span>
+		</p>
+		<p>
+			<t:eventlink event="createEntity">create entity</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="changeName">change the name</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="setToNull">set to null</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="delete">delete</t:eventlink>
+		</p>
+		<p>
+			<t:eventlink event="setToTransient">set to transient</t:eventlink>
+		</p>
+	</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/SSOEntity.tml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/SSOEntity.tml b/tapestry-jpa/src/test/app6/SSOEntity.tml
new file mode 100644
index 0000000..f7b0cf1
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/SSOEntity.tml
@@ -0,0 +1,10 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
+<body>
+	<p>entity name: <span id="name">${user?.firstName}</span></p>
+	<p>persisted entity class name: <span id="persistedEntityClassName">${persistedEntityClassName}</span></p>
+	<p><t:eventlink event="persistEntity">persist entity</t:eventlink></p>
+	<p><t:eventlink event="setToNull">set to null</t:eventlink></p>
+	<p><t:eventlink event="setToTransient">set to transient</t:eventlink></p>
+	<p><t:eventlink event="delete">delete</t:eventlink></p>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/app6/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/app6/WEB-INF/web.xml b/tapestry-jpa/src/test/app6/WEB-INF/web.xml
new file mode 100644
index 0000000..0f274b6
--- /dev/null
+++ b/tapestry-jpa/src/test/app6/WEB-INF/web.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+   Copyright 2011 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!DOCTYPE web-app
+        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+        "http://java.sun.com/dtd/web-app_2_3.dtd">
+<web-app>
+    <display-name>Tapestry-JPA Integration Test Application</display-name>
+    <context-param>
+        <param-name>tapestry.app-package</param-name>
+        <param-value>org.example.app6</param-value>
+    </context-param>
+    <filter>
+        <filter-name>app</filter-name>
+        <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>
+    </filter>
+    <filter-mapping>
+        <filter-name>app</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+</web-app>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/conf/testng.xml
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/conf/testng.xml b/tapestry-jpa/src/test/conf/testng.xml
index 7c327c6..025f946 100644
--- a/tapestry-jpa/src/test/conf/testng.xml
+++ b/tapestry-jpa/src/test/conf/testng.xml
@@ -9,38 +9,46 @@
 
 <suite name="Tapestry JPA" parallel="false" thread-count="10"
 	annotations="1.5" verbose="2">
-	<test name="Tapestry JPA Integration Tests" enabled="true">
-		<parameter name="tapestry.web-app-folder" value="src/test/app1" />
-		<packages>
-			<package name="org.apache.tapestry5.jpa.integration.app1" />
-		</packages>
-	</test>
+<!-- 	<test name="Tapestry JPA Integration Tests" enabled="true"> -->
+<!-- 		<parameter name="tapestry.web-app-folder" value="src/test/app1" /> -->
+<!-- 		<packages> -->
+<!-- 			<package name="org.apache.tapestry5.jpa.integration.app1" /> -->
+<!-- 		</packages> -->
+<!-- 	</test> -->
 
-	<test name="Single Persistence Unit Integration Tests" enabled="true">
-		<parameter name="tapestry.web-app-folder" value="src/test/app2" />
-		<packages>
-			<package name="org.apache.tapestry5.jpa.integration.app2" />
-		</packages>
-	</test>
+<!-- 	<test name="Single Persistence Unit Integration Tests" enabled="true"> -->
+<!-- 		<parameter name="tapestry.web-app-folder" value="src/test/app2" /> -->
+<!-- 		<packages> -->
+<!-- 			<package name="org.apache.tapestry5.jpa.integration.app2" /> -->
+<!-- 		</packages> -->
+<!-- 	</test> -->
 
-	<test name="JNDI DataSource Integration Tests" enabled="true">
-		<parameter name="tapestry.web-app-folder" value="src/test/app3" />
-		<parameter name="tapestry.servlet-container" value="tomcat6" />
-		<packages>
-			<package name="org.apache.tapestry5.jpa.integration.app3" />
-		</packages>
-	</test>
+<!-- 	<test name="JNDI DataSource Integration Tests" enabled="true"> -->
+<!-- 		<parameter name="tapestry.web-app-folder" value="src/test/app3" /> -->
+<!-- 		<parameter name="tapestry.servlet-container" value="tomcat6" /> -->
+<!-- 		<packages> -->
+<!-- 			<package name="org.apache.tapestry5.jpa.integration.app3" /> -->
+<!-- 		</packages> -->
+<!-- 	</test> -->
 
-	<test name="Explicit Provider Class Name In Persistence Unit Integration Tests" enabled="true">
-		<parameter name="tapestry.web-app-folder" value="src/test/app5" />
-		<packages>
-			<package name="org.apache.tapestry5.jpa.integration.app5" />
-		</packages>
-	</test>
+<!-- 	<test name="Explicit Provider Class Name In Persistence Unit Integration Tests" enabled="true"> -->
+<!-- 		<parameter name="tapestry.web-app-folder" value="src/test/app5" /> -->
+<!-- 		<packages> -->
+<!-- 			<package name="org.apache.tapestry5.jpa.integration.app5" /> -->
+<!-- 		</packages> -->
+<!-- 	</test> -->
 
-	<test name="Tapestry JPA Unit Tests" enabled="true">
+<!-- 	<test name="Tapestry JPA Unit Tests" enabled="false"> -->
+<!-- 		<packages> -->
+<!-- 			<package name="org.apache.tapestry5.internal.jpa" /> -->
+<!-- 		</packages> -->
+<!-- 	</test> -->
+	
+	<test name="Tapestry JPA Integration Tests with Annotations in Service Implementation" enabled="true">
+		<parameter name="tapestry.web-app-folder" value="src/test/app6" />
 		<packages>
-			<package name="org.apache.tapestry5.internal.jpa" />
+			<package name="org.apache.tapestry5.jpa.integration.app6" />
 		</packages>
 	</test>
+	
 </suite>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java
index 6efbc4e..cde68f9 100644
--- a/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java
+++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java
@@ -515,4 +515,19 @@ public class JpaTransactionAdvisorImplTest extends IOCTestCase
         @PersistenceContext(unitName = UNIT_NAME)
         void perform() throws SQLException;
     }
+    
+    public interface Service
+    {
+    	void perform();
+    }
+    
+    public class ServiceImpl implements Service {
+    	@CommitAfter
+    	@PersistenceContext(unitName = UNIT_NAME)
+    	public void perform() 
+    	{
+    		
+    	}
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app6/JpaIntegrationTestWithAnnotationsInServiceImplementation.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app6/JpaIntegrationTestWithAnnotationsInServiceImplementation.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app6/JpaIntegrationTestWithAnnotationsInServiceImplementation.java
new file mode 100644
index 0000000..ee3cd4d
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app6/JpaIntegrationTestWithAnnotationsInServiceImplementation.java
@@ -0,0 +1,171 @@
+// Copyright 2011, 2013 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.jpa.integration.app6;
+
+import org.apache.tapestry5.internal.jpa.PersistedEntity;
+import org.apache.tapestry5.test.SeleniumTestCase;
+import org.example.app6.entities.User;
+import org.testng.annotations.Test;
+
+public class JpaIntegrationTestWithAnnotationsInServiceImplementation extends SeleniumTestCase
+{
+
+    @Test
+    public void valueencode_all_entity_types() throws Exception
+    {
+        open("/encodeentities");
+
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        // need to create an entity in order to link with one
+        clickAndWait("link=create an entity");
+        assertEquals(getText("//span[@id='name']"), "name");
+
+        // should return null for missing objects
+        open("/encodeentities/9999");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+    }
+
+    @Test
+    public void valueencode_transient_entities() throws Exception {
+        open("/EncodeTransientEntities");
+
+        assertTrue(isElementPresent("doNothingButton"));
+    }
+
+    @Test
+    public void persist_entities()
+    {
+        open("/persistentity");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        clickAndWait("link=create entity");
+        assertText("//span[@id='name']", "name");
+
+        // shouldn't save the change to the name because it's reloaded every time
+        clickAndWait("link=change the name");
+        assertText("//span[@id='name']", "name");
+
+        // can set back to null
+        clickAndWait("link=set to null");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        // deleting an entity that is still persisted. just remove the entity from the session if
+        // it's not found.
+        clickAndWait("link=delete");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        // transient objects cannot be persisted
+        clickAndWait("link=set to transient");
+        assertTextPresent("Failed persisting the entity.");
+    }
+
+    @Test
+    public void persist_thangs()
+    {
+        open("/persistthang");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        clickAndWait("link=create entity");
+        assertText("//span[@id='name']", "name");
+
+        // shouldn't save the change to the name because it's reloaded every time
+        clickAndWait("link=change the name");
+        assertText("//span[@id='name']", "name");
+
+        // can set back to null
+        clickAndWait("link=set to null");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        // deleting an entity that is still persisted. just remove the entity from the session if
+        // it's not found.
+        clickAndWait("link=delete");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+
+        // transient objects cannot be persisted
+        clickAndWait("link=set to transient");
+        assertTextPresent("Failed persisting the entity.");
+    }
+
+    @Test
+    public void sso_entities()
+    {
+        open("/ssoentity");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+        assertText("//span[@id='persistedEntityClassName']", User.class.getName());
+
+        clickAndWait("link=persist entity");
+        assertText("//span[@id='name']", "name");
+        assertText("//span[@id='persistedEntityClassName']", PersistedEntity.class.getName());
+
+        // can set back to null
+        clickAndWait("link=set to null");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+        assertText("//span[@id='persistedEntityClassName']", User.class.getName());
+
+        clickAndWait("link=persist entity");
+        assertText("//span[@id='name']", "name");
+        assertText("//span[@id='persistedEntityClassName']", PersistedEntity.class.getName());
+
+        clickAndWait("link=delete");
+        assertEquals(getText("//span[@id='name']").length(), 0);
+        assertText("//span[@id='persistedEntityClassName']", User.class.getName());
+
+        clickAndWait("link=persist entity");
+        assertText("//span[@id='name']", "name");
+        assertText("//span[@id='persistedEntityClassName']", PersistedEntity.class.getName());
+
+        clickAndWait("link=set to transient");
+        assertText("//span[@id='persistedEntityClassName']", User.class.getName());
+    }
+
+    @Test
+    public void grid()
+    {
+        open("/griddemo");
+
+        clickAndWait("link=setup");
+
+        clickAndWait("link=First Name");
+
+        assertText("//td[@data-grid-column-sort='ascending']", "Joe_1");
+
+        clickAndWait("link=First Name");
+
+        assertText("//td[@data-grid-column-sort='descending']", "Joe_9");
+    }
+
+    public void commit_after_on_component_methods()
+    {
+        open("/");
+
+        clickAndWait("link=CommitAfter Demo");
+
+        assertText("name", "Diane");
+
+        clickAndWait("link=change name");
+
+        assertText("name", "Frank");
+
+        clickAndWait("link=runtime exception");
+
+        assertText("name", "Frank");
+
+        clickAndWait("link=checked exception");
+
+        assertText("name", "Troy");
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/AppConstants.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/AppConstants.java b/tapestry-jpa/src/test/java/org/example/app6/AppConstants.java
new file mode 100644
index 0000000..0e7304a
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/AppConstants.java
@@ -0,0 +1,22 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6;
+
+public class AppConstants
+{
+    public static final String TEST_PERSISTENCE_UNIT = "TestUnit";
+
+    public static final String TEST_PERSISTENCE_UNIT_2 = "TestUnit2";
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/entities/Thang.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/entities/Thang.java b/tapestry-jpa/src/test/java/org/example/app6/entities/Thang.java
new file mode 100644
index 0000000..72229ec
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/entities/Thang.java
@@ -0,0 +1,50 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class Thang
+{
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String name;
+
+    public Long getId()
+    {
+        return id;
+    }
+
+    public void setId(final Long id)
+    {
+        this.id = id;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(final String name)
+    {
+        this.name = name;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/entities/User.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/entities/User.java b/tapestry-jpa/src/test/java/org/example/app6/entities/User.java
new file mode 100644
index 0000000..8822bf8
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/entities/User.java
@@ -0,0 +1,99 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Version;
+
+@Entity
+public class User
+{
+    private Long id;
+
+    private String firstName;
+
+    private String lastName;
+
+    private String email;
+
+    private String encodedPassword;
+
+    private int version;
+
+    public String getEmail()
+    {
+        return email;
+    }
+
+    public String getEncodedPassword()
+    {
+        return encodedPassword;
+    }
+
+    public String getFirstName()
+    {
+        return firstName;
+    }
+
+     @Id
+    @GeneratedValue
+    public Long getId()
+    {
+        return id;
+    }
+
+    public String getLastName()
+    {
+        return lastName;
+    }
+
+    @Version
+    public int getVersion()
+    {
+        return version;
+    }
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public void setEmail(final String email)
+    {
+        this.email = email;
+}
+
+    public void setEncodedPassword(final String encodedPassword)
+    {
+        this.encodedPassword = encodedPassword;
+}
+
+    public void setFirstName(final String firstName)
+    {
+        this.firstName = firstName;
+}
+
+    public void setLastName(final String lastName)
+    {
+        this.lastName = lastName;
+}
+
+    public void setVersion(int version)
+    {
+        this.version = version;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java b/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java
new file mode 100644
index 0000000..7efe09f
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java
@@ -0,0 +1,101 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.pages;
+
+import java.sql.SQLException;
+
+import javax.persistence.PersistenceContext;
+
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.example.app6.AppConstants;
+import org.example.app6.entities.User;
+
+/**
+ * Demos the CommitAfter annotation on component methods.
+ */
+public class CommitAfterDemo
+{
+    private User user;
+
+    void onActivate(final User user)
+    {
+        this.user = user;
+    }
+
+    Object onPassivate()
+    {
+        return user;
+    }
+
+    public User getUser()
+    {
+        return user;
+    }
+
+    public void setUser(final User user)
+    {
+        this.user = user;
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void onChangeName()
+    {
+        user.setFirstName("Frank");
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void doChangeNameWithRuntimeException()
+    {
+        user.setFirstName("Bill");
+
+        throw new RuntimeException("To avoid commit.");
+    }
+
+    void onChangeNameWithRuntimeException()
+    {
+        try
+        {
+            doChangeNameWithRuntimeException();
+        }
+        catch (final Exception ex)
+        {
+            // Ignore
+        }
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void doChangeNameWithCheckedException() throws SQLException
+
+    {
+        user.setFirstName("Troy");
+
+        throw new SQLException("Doesn't matter.");
+    }
+
+    void onChangeNameWithCheckedException()
+    {
+        try
+        {
+            doChangeNameWithCheckedException();
+        }
+        catch (final Exception ex)
+        {
+            // Ignore
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java b/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java
new file mode 100644
index 0000000..ddb0087
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java
@@ -0,0 +1,66 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.pages;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.example.app6.AppConstants;
+import org.example.app6.entities.User;
+import org.example.app6.services.UserDAO;
+
+public class EncodeEntities
+{
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    private EntityManager entityManager;
+
+    @Inject
+    private UserDAO userDAO;
+
+    @SuppressWarnings("unused")
+    @Property
+    private User user;
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void onCreate()
+    {
+        final User user = new User();
+        user.setFirstName("name");
+
+        entityManager.persist(user);
+    }
+
+    @SuppressWarnings("unchecked")
+    User onPassivate()
+    {
+        // Use ordering so that we get the most recently inserted users first.
+        final List<User> users = userDAO.findAll();
+        if (users.isEmpty())
+            return null;
+
+        return users.get(0);
+    }
+
+    void onActivate(final User user)
+    {
+        this.user = user;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeTransientEntities.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeTransientEntities.java b/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeTransientEntities.java
new file mode 100644
index 0000000..c4d3683
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeTransientEntities.java
@@ -0,0 +1,34 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.example.app6.pages;
+
+import org.apache.tapestry5.annotations.PageActivationContext;
+import org.apache.tapestry5.annotations.Property;
+import org.example.app6.entities.User;
+
+public class EncodeTransientEntities
+{
+    @PageActivationContext
+    @Property
+    private User user;
+
+    void onActivate()
+    {
+        if (user == null)
+        {
+            user = new User();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java b/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java
new file mode 100644
index 0000000..8af1f73
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java
@@ -0,0 +1,73 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.pages;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.apache.tapestry5.grid.GridDataSource;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.jpa.JpaGridDataSource;
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.example.app6.AppConstants;
+import org.example.app6.entities.User;
+import org.example.app6.services.UserDAO;
+
+public class GridDemo
+{
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    private EntityManager entityManager;
+
+    @Inject
+    private UserDAO userDAO;
+
+    public GridDataSource getSource()
+    {
+        return new JpaGridDataSource<User>(entityManager, User.class)
+        {
+            @Override
+            protected void applyAdditionalConstraints(final CriteriaQuery<?> criteria,
+                    final Root<User> root, final CriteriaBuilder builder)
+            {
+                criteria.where(builder.equal(root.get("lastName"), "User"));
+            }
+        };
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void onActionFromSetup()
+    {
+        userDAO.deleteAll();
+
+        for (int i = 1; i <= 20; i++)
+        {
+            final User user = new User();
+
+            final String suffix = String.valueOf(i);
+
+            user.setFirstName("Joe_" + suffix);
+            user.setLastName("User");
+            user.setEncodedPassword("####");
+            user.setEmail("joe" + suffix + "@null.com");
+
+            entityManager.persist(user);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/Index.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/Index.java b/tapestry-jpa/src/test/java/org/example/app6/pages/Index.java
new file mode 100644
index 0000000..15b6fa3
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/Index.java
@@ -0,0 +1,43 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.pages;
+
+import org.apache.tapestry5.annotations.InjectPage;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.example.app6.entities.User;
+import org.example.app6.services.UserDAO;
+
+public class Index
+{
+
+    @InjectPage
+    private CommitAfterDemo commitAfterDemo;
+
+    @Inject
+    private UserDAO userDAO;
+
+    Object onActionFromCommitAfter()
+    {
+        final User user = new User();
+
+        user.setFirstName("Diane");
+
+        userDAO.add(user);
+
+        commitAfterDemo.setUser(user);
+
+        return commitAfterDemo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java
new file mode 100644
index 0000000..73adaa1
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java
@@ -0,0 +1,75 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.pages;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.apache.tapestry5.annotations.Persist;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.jpa.JpaPersistenceConstants;
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.example.app6.AppConstants;
+import org.example.app6.entities.User;
+
+public class PersistEntity
+{
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    private EntityManager entityManager;
+
+    @Persist(JpaPersistenceConstants.ENTITY)
+    @Property
+    private User user;
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void onCreateEntity()
+    {
+        final User user = new User();
+        user.setFirstName("name");
+
+        entityManager.persist(user);
+
+        this.user = user;
+    }
+
+    void onChangeName()
+    {
+        user.setFirstName("name2");
+
+        // No commit, so no real change.
+    }
+
+    void onSetToTransient()
+    {
+        user = new User();
+    }
+
+    void onSetToNull()
+    {
+        user = null;
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void onDelete()
+    {
+        final List<User> users = entityManager.createQuery("select u from User u").getResultList();
+
+        entityManager.remove(users.get(0));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java
new file mode 100644
index 0000000..05252f4
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java
@@ -0,0 +1,76 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.pages;
+
+import static org.example.app6.AppConstants.TEST_PERSISTENCE_UNIT_2;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.apache.tapestry5.annotations.Persist;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.jpa.JpaPersistenceConstants;
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.example.app6.entities.Thang;
+
+public class PersistThang
+{
+    @PersistenceContext(unitName = TEST_PERSISTENCE_UNIT_2)
+    private EntityManager entityManager;
+
+    @Persist(JpaPersistenceConstants.ENTITY)
+    @Property
+    private Thang thang;
+
+    @CommitAfter
+    @PersistenceContext(unitName = TEST_PERSISTENCE_UNIT_2)
+    void onCreateEntity()
+    {
+        final Thang thang = new Thang();
+        thang.setName("name");
+
+        entityManager.persist(thang);
+
+        this.thang = thang;
+    }
+
+    void onChangeName()
+    {
+        thang.setName("name2");
+
+        // No commit, so no real change.
+    }
+
+    void onSetToTransient()
+    {
+        thang = new Thang();
+    }
+
+    void onSetToNull()
+    {
+        thang = null;
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = TEST_PERSISTENCE_UNIT_2)
+    void onDelete()
+    {
+        final List<Thang> thangs = entityManager.createQuery("select t from Thang t").getResultList();
+
+        entityManager.remove(thangs.get(0));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/pages/SSOEntity.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/SSOEntity.java b/tapestry-jpa/src/test/java/org/example/app6/pages/SSOEntity.java
new file mode 100644
index 0000000..cd0cd1e
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/pages/SSOEntity.java
@@ -0,0 +1,73 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.example.app6.pages;
+
+import java.util.List;
+
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.SessionState;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.Session;
+import org.example.app6.entities.User;
+import org.example.app6.services.UserDAO;
+
+public class SSOEntity
+{
+    @SessionState
+    @Property
+    private User user;
+
+    @Inject
+    private UserDAO userDAO;
+
+    @Inject
+    private Request request;
+
+    void onPersistEntity()
+    {
+        final User user = new User();
+        user.setFirstName("name");
+
+        userDAO.add(user);
+
+        this.user = user;
+    }
+
+    void onSetToNull()
+    {
+        user = null;
+    }
+
+    void onSetToTransient()
+    {
+        user = new User();
+    }
+
+    void onDelete()
+    {
+        final List<User> users = userDAO.findAll();
+
+        userDAO.delete(users.toArray(new User[0]));
+    }
+
+    public String getPersistedEntityClassName()
+    {
+        final Session session = request.getSession(true);
+
+        final Object value = session.getAttribute("sso:" + User.class.getName());
+
+        return value.getClass().getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java b/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java
new file mode 100644
index 0000000..e87e8f8
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java
@@ -0,0 +1,88 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.services;
+
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.apache.tapestry5.ioc.annotations.Contribute;
+import org.apache.tapestry5.ioc.annotations.Match;
+import org.apache.tapestry5.ioc.annotations.SubModule;
+import org.apache.tapestry5.ioc.services.ApplicationDefaults;
+import org.apache.tapestry5.ioc.services.SymbolProvider;
+import org.apache.tapestry5.jpa.EntityManagerSource;
+import org.apache.tapestry5.jpa.JpaTransactionAdvisor;
+import org.apache.tapestry5.jpa.PersistenceUnitConfigurer;
+import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo;
+import org.apache.tapestry5.jpa.modules.JpaModule;
+import org.example.app6.AppConstants;
+import org.example.app6.entities.Thang;
+import org.example.app6.entities.User;
+import org.example.app6.services.impl.UserDAOImpl;
+
+@SubModule(JpaModule.class)
+public class AppModule
+{
+
+    public static void bind(final ServiceBinder binder)
+    {
+        binder.bind(UserDAO.class, UserDAOImpl.class);
+    }
+
+    @Contribute(SymbolProvider.class)
+    @ApplicationDefaults
+    public static void provideApplicationDefaults(
+            final MappedConfiguration<String, String> configuration)
+    {
+        configuration.add(SymbolConstants.PRODUCTION_MODE, "false");
+    }
+
+    @Contribute(EntityManagerSource.class)
+    public static void configurePersistenceUnitInfos(
+            final MappedConfiguration<String, PersistenceUnitConfigurer> configuration)
+    {
+        final PersistenceUnitConfigurer configurer = new PersistenceUnitConfigurer()
+        {
+            public void configure(final TapestryPersistenceUnitInfo unitInfo)
+            {
+                unitInfo.addManagedClass(User.class);
+            }
+        };
+        configuration.add(AppConstants.TEST_PERSISTENCE_UNIT, configurer);
+
+        final PersistenceUnitConfigurer configurer2 = new PersistenceUnitConfigurer()
+        {
+            public void configure(final TapestryPersistenceUnitInfo unitInfo)
+            {
+                unitInfo.addProperty("javax.persistence.jdbc.driver", "org.h2.Driver")
+                        .addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:test")
+                        .addProperty("eclipselink.ddl-generation", "create-tables")
+                        .addProperty("eclipselink.logging.level", "fine")
+                        .addManagedClass(Thang.class);
+            }
+        };
+
+        configuration.add(AppConstants.TEST_PERSISTENCE_UNIT_2, configurer2);
+
+    }
+
+    @Match("*DAO")
+    public static void adviseTransactionally(final JpaTransactionAdvisor advisor,
+            final MethodAdviceReceiver receiver)
+    {
+        advisor.addTransactionCommitAdvice(receiver);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java b/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java
new file mode 100644
index 0000000..9d0c93d
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java
@@ -0,0 +1,30 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.services;
+
+import java.util.List;
+
+import org.example.app6.entities.User;
+
+public interface UserDAO
+{
+    void add(User user);
+
+    List<User> findAll();
+
+    void delete(User... users);
+
+    void deleteAll();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d4e7a328/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java b/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java
new file mode 100644
index 0000000..98f7b6e
--- /dev/null
+++ b/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java
@@ -0,0 +1,64 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.example.app6.services.impl;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.jpa.annotations.CommitAfter;
+import org.example.app6.AppConstants;
+import org.example.app6.entities.User;
+import org.example.app6.services.UserDAO;
+
+public class UserDAOImpl implements UserDAO
+{
+    @Inject
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    private EntityManager entityManager;
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    public void add(final User user)
+    {
+        entityManager.persist(user);
+    }
+
+    @SuppressWarnings(
+    { "unchecked" })
+    public List<User> findAll()
+    {
+        final List resultList = entityManager.createQuery("select u from User u order by u.id desc").getResultList();
+		return resultList;
+    }
+
+    @CommitAfter
+    @PersistenceContext(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    public void delete(final User... users)
+    {
+        for (final User user : users)
+            entityManager.remove(user);
+    }
+
+    public void deleteAll()
+    {
+        for (final User u : findAll())
+        {
+            entityManager.remove(u);
+        }
+    }
+}