jpauserset now working.
[utils] / test / enterprise / src / main / java / org / wamblee / support / persistence / TransactionProxyFactory.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.support.persistence;
17
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Proxy;
22
23 import javax.management.RuntimeErrorException;
24 import javax.persistence.EntityManager;
25
26 import org.wamblee.support.ThreadSpecificProxyFactory;
27 import org.wamblee.support.persistence.JpaBuilder.JpaUnitOfWork;
28
29 /**
30  * This utility makes sure that each invocation on a certain interface is
31  * carried out within a JPA unit of work.
32  * 
33  * Use {@link #getTransactionScopedEntityManager()} to get the transaction
34  * scoped entity manager to pass to services.
35  * 
36  * @param T
37  *            Type of interface to proxy.
38  * 
39  * @author Erik Brakkee
40  */
41 public class TransactionProxyFactory<T> {
42
43     private class UnitOfWorkInvocationHandler<T> implements InvocationHandler {
44
45         private T service;
46
47         public UnitOfWorkInvocationHandler(T aService) {
48             service = aService;
49         }
50
51         @Override
52         public Object invoke(Object aProxy, final Method aMethod,
53             final Object[] aArgs) throws Throwable {
54             return TransactionProxyFactory.this.jpaBuilder
55                 .execute(new JpaUnitOfWork<Object>() {
56                     @Override
57                     public Object execute(EntityManager aEm) throws Exception {
58                         try {
59                             ENTITY_MANAGER.set(aEm);
60                             return aMethod.invoke(service, aArgs);
61                         } catch (InvocationTargetException e) {
62                             Throwable cause = e.getCause();
63                             if (cause instanceof Exception) {
64                                 throw (Exception) cause;
65                             } else if (cause instanceof Error) {
66                                 throw (Error) cause;
67                             }
68                             // last resort.
69                             throw new RuntimeException(e);
70                         } finally {
71                             ENTITY_MANAGER.set(null);
72                         }
73                     }
74                 });
75         }
76
77     }
78
79     private static final ThreadSpecificProxyFactory<EntityManager> ENTITY_MANAGER = new ThreadSpecificProxyFactory<EntityManager>(
80         EntityManager.class);
81
82     private JpaBuilder jpaBuilder;
83     private Class<T> clazz;
84
85     /**
86      * Constructs the transaction proxy.
87      * 
88      * @param aJpaBuilder
89      */
90     public TransactionProxyFactory(JpaBuilder aJpaBuilder, Class<T> aClass) {
91         jpaBuilder = aJpaBuilder;
92         clazz = aClass;
93     }
94
95     public EntityManager getTransactionScopedEntityManager() {
96         return ENTITY_MANAGER.getProxy();
97     }
98
99     public T getProxy(T aService) {
100         InvocationHandler handler = new UnitOfWorkInvocationHandler<T>(aService);
101         Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(),
102             new Class[] { clazz });
103         T proxy;
104         try {
105             proxy = (T) proxyClass.getConstructor(
106                 new Class[] { InvocationHandler.class }).newInstance(
107                 new Object[] { handler });
108             return proxy;
109         } catch (Exception e) {
110             throw new RuntimeException("Could not create proxy for " +
111                 clazz.getName(), e);
112         }
113     }
114 }