You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by dr...@apache.org on 2011/03/10 17:59:01 UTC

svn commit: r1080279 - in /tapestry/tapestry5/trunk/tapestry-jpa/src: main/java/org/apache/tapestry5/internal/jpa/ main/java/org/apache/tapestry5/jpa/ test/conf/ test/java/org/apache/tapestry5/internal/ test/java/org/apache/tapestry5/internal/jpa/ test...

Author: drobiazko
Date: Thu Mar 10 16:59:00 2011
New Revision: 1080279

URL: http://svn.apache.org/viewvc?rev=1080279&view=rev
Log:
TAP5-1472: Added JPA based GridDataSource and transaction advisor for @CommitAfter annotation

Added:
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaGridDataSource.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/CommitAfterDemo.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/GridDemo.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/Index.java   (with props)
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/CommitAfterDemo.tml
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/GridDemo.tml
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/Index.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java
    tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaModule.java
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/conf/testng.xml
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/JpaIntegrationTest.java
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/SSOEntity.java
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/AppModule.java
    tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/UserDAO.java

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,88 @@
+// 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.
+
+package org.apache.tapestry5.internal.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.PersistenceUnit;
+
+import org.apache.tapestry5.ioc.Invocation;
+import org.apache.tapestry5.ioc.MethodAdvice;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.jpa.EntityManagerManager;
+
+public class CommitAfterMethodAdvice implements MethodAdvice
+{
+
+    private final EntityManagerManager manager;
+
+    public CommitAfterMethodAdvice(final EntityManagerManager manager)
+    {
+        super();
+        this.manager = manager;
+    }
+
+    public void advise(final Invocation invocation)
+    {
+        final EntityTransaction transaction = getTransaction(invocation);
+
+        if (transaction != null && !transaction.isActive())
+        {
+            transaction.begin();
+        }
+
+        try
+        {
+            invocation.proceed();
+        }
+        catch (final RuntimeException e)
+        {
+            if (transaction != null && transaction.isActive())
+            {
+                transaction.rollback();
+            }
+
+            throw e;
+        }
+
+        // Success or checked exception:
+
+        if (transaction != null && transaction.isActive())
+        {
+            transaction.commit();
+        }
+
+    }
+
+    private EntityTransaction getTransaction(final Invocation invocation)
+    {
+
+        final PersistenceUnit persistenceUnit = invocation
+                .getMethodAnnotation(PersistenceUnit.class);
+
+        if (persistenceUnit == null)
+            return null;
+
+        final String unitName = persistenceUnit.unitName();
+
+        if (InternalUtils.isBlank(unitName))
+            return null;
+
+        final EntityManager em = manager.getEntityManager(unitName);
+
+        return em.getTransaction();
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java Thu Mar 10 16:59:00 2011
@@ -14,10 +14,6 @@
 
 package org.apache.tapestry5.internal.jpa;
 
-import javax.persistence.EntityManager;
-import javax.persistence.EntityTransaction;
-import javax.persistence.PersistenceUnit;
-
 import org.apache.tapestry5.jpa.CommitAfter;
 import org.apache.tapestry5.jpa.EntityManagerManager;
 import org.apache.tapestry5.model.MutableComponentModel;
@@ -29,66 +25,11 @@ import org.apache.tapestry5.services.Tra
 
 public class CommitAfterWorker implements ComponentClassTransformWorker
 {
-    private final EntityManagerManager manager;
-
-    private final ComponentMethodAdvice advice = new ComponentMethodAdvice()
-    {
-        public void advise(final ComponentMethodInvocation invocation)
-        {
-
-            final EntityTransaction transaction = getTransaction(invocation);
-
-            if (transaction != null && !transaction.isActive())
-            {
-                transaction.begin();
-            }
-
-            try
-            {
-                invocation.proceed();
-
-                // Success or checked exception:
-
-                if (transaction != null && transaction.isActive())
-                {
-                    transaction.commit();
-                }
-            }
-            catch (final RuntimeException e)
-            {
-                if (transaction != null && transaction.isActive())
-                {
-                    transaction.rollback();
-                }
-
-                throw e;
-            }
-        }
-
-        private EntityTransaction getTransaction(final ComponentMethodInvocation invocation)
-        {
-
-            final PersistenceUnit persistenceUnit = invocation
-                    .getMethodAnnotation(PersistenceUnit.class);
-
-            if (persistenceUnit == null)
-                return null;
-
-            final String unitName = persistenceUnit.unitName();
-
-            if (unitName == null)
-                return null;
-
-            final EntityManager em = manager.getEntityManager(unitName);
-
-            return em.getTransaction();
-        }
-
-    };
+    private final CommitAfterMethodAdvice advice;
 
     public CommitAfterWorker(final EntityManagerManager manager)
     {
-        this.manager = manager;
+        advice = new CommitAfterMethodAdvice(manager);
     }
 
     public void transform(final ClassTransformation transformation,
@@ -97,7 +38,15 @@ public class CommitAfterWorker implement
         for (final TransformMethod method : transformation
                 .matchMethodsWithAnnotation(CommitAfter.class))
         {
-            method.addAdvice(advice);
+            method.addAdvice(new ComponentMethodAdvice()
+            {
+
+                public void advise(final ComponentMethodInvocation invocation)
+                {
+                    advice.advise(invocation);
+
+                }
+            });
         }
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java Thu Mar 10 16:59:00 2011
@@ -60,6 +60,7 @@ public class EntityApplicationStatePersi
     public <T> void set(final Class<T> ssoClass, final T sso)
     {
         final String key = buildKey(ssoClass);
+
         Object entity;
 
         if (sso != null)

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,49 @@
+// 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.
+
+package org.apache.tapestry5.internal.jpa;
+
+import java.lang.reflect.Method;
+
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.jpa.CommitAfter;
+import org.apache.tapestry5.jpa.EntityManagerManager;
+import org.apache.tapestry5.jpa.JpaTransactionAdvisor;
+
+public class JpaTransactionAdvisorImpl implements JpaTransactionAdvisor
+{
+
+    private final CommitAfterMethodAdvice advice;
+
+    public JpaTransactionAdvisorImpl(final EntityManagerManager manager)
+    {
+        advice = new CommitAfterMethodAdvice(manager);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addTransactionCommitAdvice(final MethodAdviceReceiver receiver)
+    {
+        for (final Method m : receiver.getInterface().getMethods())
+        {
+            if (m.getAnnotation(CommitAfter.class) != null)
+            {
+                receiver.adviseMethod(m, advice);
+            }
+        }
+
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaGridDataSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaGridDataSource.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaGridDataSource.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaGridDataSource.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,146 @@
+// 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.
+
+package org.apache.tapestry5.jpa;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Path;
+import javax.persistence.criteria.Root;
+
+import org.apache.tapestry5.grid.GridDataSource;
+import org.apache.tapestry5.grid.SortConstraint;
+
+/**
+ * A simple implementation of {@link org.apache.tapestry5.grid.GridDataSource} based on a
+ * {@linkplain javax.persistence.EntityManager} and a known
+ * entity class. This implementation does support multiple
+ * {@link org.apache.tapestry5.grid.SortConstraint sort
+ * constraints}.
+ * <p/>
+ * This class is <em>not</em> thread-safe; it maintains internal state.
+ * <p/>
+ * Typically, an instance of this object is created fresh as needed (that is, it is not stored
+ * between requests).
+ */
+public class JpaGridDataSource<E> implements GridDataSource
+{
+
+    private final EntityManager entityManager;
+
+    private final Class<E> entityType;
+
+    private int startIndex;
+
+    private List<E> preparedResults;
+
+    public JpaGridDataSource(final EntityManager entityManager, final Class<E> entityType)
+    {
+        super();
+        this.entityManager = entityManager;
+        this.entityType = entityType;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getAvailableRows()
+    {
+        final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
+
+        CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
+
+        final Root<E> root = criteria.from(entityType);
+
+        criteria = criteria.select(builder.count(root));
+
+        applyAdditionalConstraints(criteria, root, builder);
+
+        return entityManager.createQuery(criteria).getSingleResult().intValue();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void prepare(final int startIndex, final int endIndex,
+            final List<SortConstraint> sortConstraints)
+    {
+        final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
+
+        final CriteriaQuery<E> criteria = builder.createQuery(entityType);
+
+        final Root<E> root = criteria.from(entityType);
+
+        applyAdditionalConstraints(criteria.select(root), root, builder);
+
+        for (final SortConstraint constraint : sortConstraints)
+        {
+
+            final String propertyName = constraint.getPropertyModel().getPropertyName();
+
+            final Path<Object> propertyPath = root.get(propertyName);
+
+            switch (constraint.getColumnSort())
+            {
+
+                case ASCENDING:
+
+                    criteria.orderBy(builder.asc(propertyPath));
+                    break;
+
+                case DESCENDING:
+                    criteria.orderBy(builder.desc(propertyPath));
+                    break;
+
+                default:
+            }
+        }
+
+        final TypedQuery<E> query = entityManager.createQuery(criteria);
+
+        query.setFirstResult(startIndex);
+        query.setMaxResults(endIndex - startIndex + 1);
+
+        this.startIndex = startIndex;
+
+        preparedResults = query.getResultList();
+
+    }
+
+    protected void applyAdditionalConstraints(final CriteriaQuery<?> criteria, final Root<E> root,
+            final CriteriaBuilder builder)
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getRowValue(final int index)
+    {
+        return preparedResults.get(index - startIndex);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Class<E> getRowType()
+    {
+        return entityType;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaGridDataSource.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaModule.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaModule.java Thu Mar 10 16:59:00 2011
@@ -28,6 +28,7 @@ import org.apache.tapestry5.internal.jpa
 import org.apache.tapestry5.internal.jpa.EntityManagerObjectProvider;
 import org.apache.tapestry5.internal.jpa.EntityManagerSourceImpl;
 import org.apache.tapestry5.internal.jpa.EntityPersistentFieldStrategy;
+import org.apache.tapestry5.internal.jpa.JpaTransactionAdvisorImpl;
 import org.apache.tapestry5.internal.jpa.JpaValueEncoder;
 import org.apache.tapestry5.internal.jpa.PersistenceUnitWorker;
 import org.apache.tapestry5.internal.services.PersistentFieldManager;
@@ -36,6 +37,7 @@ import org.apache.tapestry5.ioc.MappedCo
 import org.apache.tapestry5.ioc.ObjectProvider;
 import org.apache.tapestry5.ioc.OrderedConfiguration;
 import org.apache.tapestry5.ioc.ScopeConstants;
+import org.apache.tapestry5.ioc.ServiceBinder;
 import org.apache.tapestry5.ioc.annotations.Contribute;
 import org.apache.tapestry5.ioc.annotations.Scope;
 import org.apache.tapestry5.ioc.annotations.Startup;
@@ -59,6 +61,11 @@ import org.slf4j.Logger;
 
 public class JpaModule
 {
+    public static void bind(final ServiceBinder binder)
+    {
+        binder.bind(JpaTransactionAdvisor.class, JpaTransactionAdvisorImpl.class);
+    }
+
     public static EntityManagerSource buildEntityManagerSource(final Logger logger,
             final Map<String, PersistenceUnitConfigurer> configuration,
             final RegistryShutdownHub hub)

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,39 @@
+// 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.
+
+package org.apache.tapestry5.jpa;
+
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+
+/**
+ * Service that can create an interceptor that wraps around a service implementation. After invoking
+ * service methods
+ * marked by {@link org.apache.tapestry5.jpa.CommitAfter} the current transaction is committed.
+ * Declared exceptions will also {@linkplain javax.persistence.EntityTransaction#commit() commit the
+ * transaction}; runtime exceptions will {@linkplain javax.persistence.EntityTransaction#rollback()
+ * roll back the transaction}.
+ * 
+ * @since 5.3.0
+ */
+public interface JpaTransactionAdvisor
+{
+    /**
+     * Identifies any methods with the {@link org.apache.tapestry5.jpa.CommitAfter} annotation and
+     * applies the transaction logic to those methods.
+     * 
+     * @param receiver
+     *            advice receiver
+     */
+    void addTransactionCommitAdvice(MethodAdviceReceiver receiver);
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/conf/testng.xml?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/conf/testng.xml Thu Mar 10 16:59:00 2011
@@ -1,25 +1,24 @@
 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<!-- 
-   Copyright 2011 The Apache Software Foundation
+<!-- 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. -->
 
-   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
+<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/webapp" />
+		<packages>
+			<package name="org.apache.tapestry5.jpa.integration" />
+		</packages>
+	</test>
 
-       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.
--->
-
-<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/webapp"/>
-        <packages>
-            <package name="org.apache.tapestry5.jpa.integration"/>
-        </packages>
-    </test>
+	<test name="Tapestry JPA Unit Tests" enabled="true">
+		<packages>
+			<package name="org.apache.tapestry5.internal.jpa" />
+		</packages>
+	</test>
 </suite>

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,427 @@
+// 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.
+
+package org.apache.tapestry5.internal.jpa;
+
+import java.sql.SQLException;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.PersistenceUnit;
+
+import org.apache.tapestry5.ioc.IOCUtilities;
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.services.AspectDecorator;
+import org.apache.tapestry5.ioc.services.AspectInterceptorBuilder;
+import org.apache.tapestry5.ioc.test.IOCTestCase;
+import org.apache.tapestry5.ioc.test.TestBase;
+import org.apache.tapestry5.jpa.CommitAfter;
+import org.apache.tapestry5.jpa.EntityManagerManager;
+import org.apache.tapestry5.jpa.JpaTransactionAdvisor;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class JpaTransactionAdvisorImplTest extends IOCTestCase
+{
+    private static final String UNIT_NAME = "FooUnit";
+
+    private Registry registry;
+
+    private AspectDecorator aspectDecorator;
+
+    @BeforeClass
+    public void setup()
+    {
+        registry = IOCUtilities.buildDefaultRegistry();
+
+        aspectDecorator = registry.getService(AspectDecorator.class);
+    }
+
+    @AfterClass
+    public void shutdown()
+    {
+        registry.shutdown();
+
+        aspectDecorator = null;
+        registry = null;
+    }
+
+    @Test
+    public void undecorated()
+    {
+        final VoidService delegate = newMock(VoidService.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+
+        final AspectInterceptorBuilder<VoidService> builder = aspectDecorator.createBuilder(
+                VoidService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final VoidService interceptor = builder.build();
+
+        delegate.undecorated();
+
+        replay();
+        interceptor.undecorated();
+        verify();
+    }
+
+    @Test
+    public void persistence_unit_missing()
+    {
+        final VoidService delegate = newMock(VoidService.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+
+        final AspectInterceptorBuilder<VoidService> builder = aspectDecorator.createBuilder(
+                VoidService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final VoidService interceptor = builder.build();
+
+        delegate.persistenceUnitMissing();
+
+        replay();
+        interceptor.persistenceUnitMissing();
+        verify();
+    }
+
+    @Test
+    public void persistence_unit_name_missing()
+    {
+        final VoidService delegate = newMock(VoidService.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+
+        final AspectInterceptorBuilder<VoidService> builder = aspectDecorator.createBuilder(
+                VoidService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final VoidService interceptor = builder.build();
+
+        delegate.persistenceUnitNameMissing();
+
+        replay();
+        interceptor.persistenceUnitNameMissing();
+        verify();
+    }
+
+    @Test
+    public void transaction_inactive()
+    {
+        final VoidService delegate = newMock(VoidService.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+
+        final AspectInterceptorBuilder<VoidService> builder = aspectDecorator.createBuilder(
+                VoidService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final VoidService interceptor = builder.build();
+
+        train_getAndBeginTransaction(manager, entityManager, transaction);
+
+        delegate.voidMethod();
+
+        train_commitActiveTransaction(transaction);
+
+        replay();
+        interceptor.voidMethod();
+        verify();
+    }
+
+    @Test
+    public void void_method()
+    {
+        final VoidService delegate = newMock(VoidService.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+
+        final AspectInterceptorBuilder<VoidService> builder = aspectDecorator.createBuilder(
+                VoidService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final VoidService interceptor = builder.build();
+
+        train_getActiveTransaction(manager, entityManager, transaction);
+
+        delegate.voidMethod();
+
+        train_commitActiveTransaction(transaction);
+
+        replay();
+        interceptor.voidMethod();
+        verify();
+    }
+
+    @Test
+    public void void_method_with_param()
+    {
+        final VoidService delegate = newMock(VoidService.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+
+        final AspectInterceptorBuilder<VoidService> builder = aspectDecorator.createBuilder(
+                VoidService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final VoidService interceptor = builder.build();
+
+        train_getActiveTransaction(manager, entityManager, transaction);
+        delegate.voidMethodWithParam(777);
+        train_commitActiveTransaction(transaction);
+
+        replay();
+        interceptor.voidMethodWithParam(777);
+        verify();
+    }
+
+    @Test
+    public void runtime_exception_will_abort_transaction() throws Exception
+    {
+        final Performer delegate = newMock(Performer.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+        final RuntimeException re = new RuntimeException("Unexpected.");
+
+        final AspectInterceptorBuilder<Performer> builder = aspectDecorator.createBuilder(
+                Performer.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final Performer interceptor = builder.build();
+
+        train_getActiveTransaction(manager, entityManager, transaction);
+        delegate.perform();
+        TestBase.setThrowable(re);
+        train_rollBackActiveTransaction(transaction);
+
+        replay();
+        try
+        {
+            interceptor.perform();
+            TestBase.unreachable();
+        }
+        catch (final RuntimeException ex)
+        {
+            Assert.assertSame(ex, re);
+        }
+
+        verify();
+    }
+
+    @Test
+    public void checked_exception_will_commit_transaction() throws Exception
+    {
+        final Performer delegate = newMock(Performer.class);
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+        final SQLException se = new SQLException("Checked.");
+
+        final AspectInterceptorBuilder<Performer> builder = aspectDecorator.createBuilder(
+                Performer.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final Performer interceptor = builder.build();
+
+        train_getActiveTransaction(manager, entityManager, transaction);
+        delegate.perform();
+        TestBase.setThrowable(se);
+        train_commitActiveTransaction(transaction);
+
+        replay();
+        try
+        {
+            interceptor.perform();
+            TestBase.unreachable();
+        }
+        catch (final SQLException ex)
+        {
+            Assert.assertSame(ex, se);
+        }
+
+        verify();
+    }
+
+    @Test
+    public void return_type_method()
+    {
+        final ReturnTypeService delegate = newTestService();
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+
+        final AspectInterceptorBuilder<ReturnTypeService> builder = aspectDecorator.createBuilder(
+                ReturnTypeService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final ReturnTypeService interceptor = builder.build();
+
+        train_getActiveTransaction(manager, entityManager, transaction);
+        delegate.returnTypeMethod();
+        train_commitActiveTransaction(transaction);
+
+        replay();
+        Assert.assertEquals(interceptor.returnTypeMethod(), "Foo");
+        verify();
+    }
+
+    @Test
+    public void return_type_method_with_param()
+    {
+        final ReturnTypeService delegate = newTestService();
+        final EntityManagerManager manager = newMock(EntityManagerManager.class);
+        final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager);
+        final EntityManager entityManager = newMock(EntityManager.class);
+        final EntityTransaction transaction = newMock(EntityTransaction.class);
+
+        final AspectInterceptorBuilder<ReturnTypeService> builder = aspectDecorator.createBuilder(
+                ReturnTypeService.class, delegate, "foo.Bar");
+
+        advisor.addTransactionCommitAdvice(builder);
+
+        final ReturnTypeService interceptor = builder.build();
+
+        train_getActiveTransaction(manager, entityManager, transaction);
+        delegate.returnTypeMethodWithParam(5, 3);
+        train_commitActiveTransaction(transaction);
+
+        replay();
+        Assert.assertEquals(interceptor.returnTypeMethodWithParam(5, 3), 8);
+        verify();
+    }
+
+    private void train_getAndBeginTransaction(final EntityManagerManager manager,
+            final EntityManager entityManager, final EntityTransaction transaction)
+    {
+        train_getTransaction(manager, entityManager, transaction, false);
+        transaction.begin();
+    }
+
+    private void train_getActiveTransaction(final EntityManagerManager manager,
+            final EntityManager entityManager, final EntityTransaction transaction)
+    {
+        train_getTransaction(manager, entityManager, transaction, true);
+    }
+
+    private void train_getTransaction(final EntityManagerManager manager,
+            final EntityManager entityManager, final EntityTransaction transaction,
+            final boolean isActive)
+    {
+        expect(manager.getEntityManager(UNIT_NAME)).andReturn(entityManager);
+        expect(entityManager.getTransaction()).andReturn(transaction);
+        expect(transaction.isActive()).andReturn(isActive);
+    }
+
+    private void train_commitActiveTransaction(final EntityTransaction transaction)
+    {
+        expect(transaction.isActive()).andReturn(true);
+        transaction.commit();
+    }
+
+    private void train_rollBackActiveTransaction(final EntityTransaction transaction)
+    {
+        expect(transaction.isActive()).andReturn(true);
+        transaction.rollback();
+    }
+
+    private JpaTransactionAdvisor newJpaTransactionAdvisor(final EntityManagerManager manager)
+    {
+        return new JpaTransactionAdvisorImpl(manager);
+    }
+
+    private ReturnTypeService newTestService()
+    {
+        return new ReturnTypeService()
+        {
+
+            public String returnTypeMethod()
+            {
+                return "Foo";
+            }
+
+            public int returnTypeMethodWithParam(final int first, final int second)
+            {
+                return first + second;
+            }
+
+            @Override
+            public String toString()
+            {
+                return "Baz";
+            }
+        };
+    }
+
+    public interface ReturnTypeService
+    {
+        @CommitAfter
+        @PersistenceUnit(unitName = UNIT_NAME)
+        String returnTypeMethod();
+
+        @CommitAfter
+        @PersistenceUnit(unitName = UNIT_NAME)
+        int returnTypeMethodWithParam(int first, int second);
+
+        String toString();
+    }
+
+    public interface VoidService
+    {
+        void undecorated();
+
+        @CommitAfter
+        @PersistenceUnit
+        void persistenceUnitMissing();
+
+        @CommitAfter
+        void persistenceUnitNameMissing();
+
+        @CommitAfter
+        @PersistenceUnit(unitName = UNIT_NAME)
+        void voidMethod();
+
+        @CommitAfter
+        @PersistenceUnit(unitName = UNIT_NAME)
+        void voidMethodWithParam(long id);
+    }
+
+    public interface Performer
+    {
+        @CommitAfter
+        @PersistenceUnit(unitName = UNIT_NAME)
+        void perform() throws SQLException;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/JpaIntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/JpaIntegrationTest.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/JpaIntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/JpaIntegrationTest.java Thu Mar 10 16:59:00 2011
@@ -96,4 +96,42 @@ public class JpaIntegrationTest extends 
         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[@class='firstName t-sort-column-ascending']", "Joe_1");
+
+        clickAndWait("link=First Name");
+
+        assertText("//td[@class='firstName t-sort-column-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");
+
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/CommitAfterDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/CommitAfterDemo.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/CommitAfterDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/CommitAfterDemo.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,87 @@
+package org.example.app.pages;
+
+import java.sql.SQLException;
+
+import javax.persistence.PersistenceUnit;
+
+import org.apache.tapestry5.jpa.CommitAfter;
+import org.example.app.AppConstants;
+import org.example.app.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
+    @PersistenceUnit(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
+    void onChangeName()
+    {
+        user.setFirstName("Frank");
+    }
+
+    @CommitAfter
+    @PersistenceUnit(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
+    @PersistenceUnit(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
+        }
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/CommitAfterDemo.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/GridDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/GridDemo.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/GridDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/GridDemo.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,73 @@
+// Copyright 2008 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.app.pages;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceUnit;
+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.CommitAfter;
+import org.apache.tapestry5.jpa.JpaGridDataSource;
+import org.example.app.AppConstants;
+import org.example.app.entities.User;
+import org.example.app.services.UserDAO;
+
+public class GridDemo
+{
+    @PersistenceUnit(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
+    @PersistenceUnit(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);
+        }
+
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/GridDemo.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/Index.java?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/Index.java (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/Index.java Thu Mar 10 16:59:00 2011
@@ -0,0 +1,43 @@
+// Copyright 2007 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.app.pages;
+
+import org.apache.tapestry5.annotations.InjectPage;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.example.app.entities.User;
+import org.example.app.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;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/Index.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/SSOEntity.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/SSOEntity.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/SSOEntity.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/pages/SSOEntity.java Thu Mar 10 16:59:00 2011
@@ -15,15 +15,11 @@ package org.example.app.pages;
 
 import java.util.List;
 
-import javax.persistence.PersistenceUnit;
-
 import org.apache.tapestry5.annotations.Property;
 import org.apache.tapestry5.annotations.SessionState;
 import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.jpa.CommitAfter;
 import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.Session;
-import org.example.app.AppConstants;
 import org.example.app.entities.User;
 import org.example.app.services.UserDAO;
 
@@ -39,8 +35,6 @@ public class SSOEntity
     @Inject
     private Request request;
 
-    @CommitAfter
-    @PersistenceUnit(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
     void onPersistEntity()
     {
         final User user = new User();
@@ -61,8 +55,6 @@ public class SSOEntity
         user = new User();
     }
 
-    @CommitAfter
-    @PersistenceUnit(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
     void onDelete()
     {
         final List<User> users = userDAO.findAll();

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/AppModule.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/AppModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/AppModule.java Thu Mar 10 16:59:00 2011
@@ -16,12 +16,15 @@ package org.example.app.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.JpaModule;
+import org.apache.tapestry5.jpa.JpaTransactionAdvisor;
 import org.example.app.services.impl.UserDAOImpl;
 
 @SubModule(JpaModule.class)
@@ -40,4 +43,11 @@ public class AppModule
     {
         configuration.add(SymbolConstants.PRODUCTION_MODE, "false");
     }
+
+    @Match("*DAO")
+    public static void adviseTransactionally(final JpaTransactionAdvisor advisor,
+            final MethodAdviceReceiver receiver)
+    {
+        advisor.addTransactionCommitAdvice(receiver);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/UserDAO.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/UserDAO.java?rev=1080279&r1=1080278&r2=1080279&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/UserDAO.java (original)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/java/org/example/app/services/UserDAO.java Thu Mar 10 16:59:00 2011
@@ -2,14 +2,22 @@ package org.example.app.services;
 
 import java.util.List;
 
+import javax.persistence.PersistenceUnit;
+
+import org.apache.tapestry5.jpa.CommitAfter;
+import org.example.app.AppConstants;
 import org.example.app.entities.User;
 
 public interface UserDAO
 {
+    @CommitAfter
+    @PersistenceUnit(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
     void add(User user);
 
     List<User> findAll();
 
+    @CommitAfter
+    @PersistenceUnit(unitName = AppConstants.TEST_PERSISTENCE_UNIT)
     void delete(User... users);
 
     void deleteAll();

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/CommitAfterDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/CommitAfterDemo.tml?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/CommitAfterDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/CommitAfterDemo.tml Thu Mar 10 16:59:00 2011
@@ -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

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/GridDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/GridDemo.tml?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/GridDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/GridDemo.tml Thu Mar 10 16:59:00 2011
@@ -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>

Added: tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/Index.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/Index.tml?rev=1080279&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/Index.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-jpa/src/test/webapp/Index.tml Thu Mar 10 16:59:00 2011
@@ -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>