KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > jdo > TransactionAwarePersistenceManagerFactoryProxy


1 /*
2  * Copyright 2002-2007 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
17 package org.springframework.orm.jdo;
18
19 import java.lang.reflect.InvocationHandler JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Proxy JavaDoc;
23
24 import javax.jdo.PersistenceManager;
25 import javax.jdo.PersistenceManagerFactory;
26
27 import org.springframework.beans.factory.FactoryBean;
28 import org.springframework.util.ClassUtils;
29
30 /**
31  * Proxy for a target JDO {@link javax.jdo.PersistenceManagerFactory},
32  * returning the current thread-bound PersistenceManager (the Spring-managed
33  * transactional PersistenceManager or a the single OpenPersistenceManagerInView
34  * PersistenceManager) on <code>getPersistenceManager()</code>, if any.
35  *
36  * <p>Essentially, <code>getPersistenceManager()</code> calls get seamlessly
37  * forwarded to {@link PersistenceManagerFactoryUtils#getPersistenceManager}.
38  * Furthermore, <code>PersistenceManager.close</code> calls get forwarded to
39  * {@link PersistenceManagerFactoryUtils#releasePersistenceManager}.
40  *
41  * <p>The main advantage of this proxy is that it allows DAOs to work with a
42  * plain JDO PersistenceManagerFactory reference, while still participating in
43  * Spring's (or a J2EE server's) resource and transaction management. DAOs will
44  * only rely on the JDO API in such a scenario, without any Spring dependencies.
45  *
46  * <p>Note that the behavior of this proxy matches the behavior that the JDO spec
47  * defines for a PersistenceManagerFactory as exposed by a JCA connector, when
48  * deployed in a J2EE server. Hence, DAOs could seamlessly switch between a JNDI
49  * PersistenceManagerFactory and this proxy for a local PersistenceManagerFactory,
50  * receiving the reference through Dependency Injection. This will work without
51  * any Spring API dependencies in the DAO code!
52  *
53  * <p>It is usually preferable to write your JDO-based DAOs with Spring's
54  * {@link JdoTemplate}, offering benefits such as consistent data access
55  * exceptions instead of JDOExceptions at the DAO layer. However, Spring's
56  * resource and transaction management (and Dependency Injection) will work
57  * for DAOs written against the plain JDO API as well.
58  *
59  * <p>Of course, you can still access the target PersistenceManagerFactory
60  * even when your DAOs go through this proxy, by defining a bean reference
61  * that points directly at your target PersistenceManagerFactory bean.
62  *
63  * @author Juergen Hoeller
64  * @since 1.2
65  * @see javax.jdo.PersistenceManagerFactory#getPersistenceManager()
66  * @see javax.jdo.PersistenceManager#close()
67  * @see PersistenceManagerFactoryUtils#getPersistenceManager
68  * @see PersistenceManagerFactoryUtils#releasePersistenceManager
69  */

70 public class TransactionAwarePersistenceManagerFactoryProxy implements FactoryBean {
71
72     private PersistenceManagerFactory target;
73
74     private boolean allowCreate = true;
75
76     private PersistenceManagerFactory proxy;
77
78
79     /**
80      * Set the target JDO PersistenceManagerFactory that this proxy should
81      * delegate to. This should be the raw PersistenceManagerFactory, as
82      * accessed by JdoTransactionManager.
83      * @see org.springframework.orm.jdo.JdoTransactionManager
84      */

85     public void setTargetPersistenceManagerFactory(PersistenceManagerFactory target) {
86         this.target = target;
87         Class JavaDoc[] ifcs = ClassUtils.getAllInterfaces(target);
88         this.proxy = (PersistenceManagerFactory) Proxy.newProxyInstance(
89                 getClass().getClassLoader(), ifcs, new TransactionAwareFactoryInvocationHandler());
90     }
91
92     /**
93      * Return the target JDO PersistenceManagerFactory that this proxy delegates to.
94      */

95     public PersistenceManagerFactory getTargetPersistenceManagerFactory() {
96         return this.target;
97     }
98
99     /**
100      * Set whether the PersistenceManagerFactory proxy is allowed to create
101      * a non-transactional PersistenceManager when no transactional
102      * PersistenceManager can be found for the current thread.
103      * <p>Default is "true". Can be turned off to enforce access to
104      * transactional PersistenceManagers, which safely allows for DAOs
105      * written to get a PersistenceManager without explicit closing
106      * (i.e. a <code>PersistenceManagerFactory.getPersistenceManager()</code>
107      * call without corresponding <code>PersistenceManager.close()</code> call).
108      * @see PersistenceManagerFactoryUtils#getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean)
109      */

110     public void setAllowCreate(boolean allowCreate) {
111         this.allowCreate = allowCreate;
112     }
113
114     /**
115      * Return whether the PersistenceManagerFactory proxy is allowed to create
116      * a non-transactional PersistenceManager when no transactional
117      * PersistenceManager can be found for the current thread.
118      */

119     protected boolean isAllowCreate() {
120         return allowCreate;
121     }
122
123
124     public Object JavaDoc getObject() {
125         return this.proxy;
126     }
127
128     public Class JavaDoc getObjectType() {
129         return PersistenceManagerFactory.class;
130     }
131
132     public boolean isSingleton() {
133         return true;
134     }
135
136
137     /**
138      * Invocation handler that delegates getPersistenceManager calls on the
139      * PersistenceManagerFactory proxy to PersistenceManagerFactoryUtils
140      * for being aware of thread-bound transactions.
141      */

142     private class TransactionAwareFactoryInvocationHandler implements InvocationHandler JavaDoc {
143
144         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
145             // Invocation on PersistenceManagerFactory interface coming in...
146
PersistenceManagerFactory target = getTargetPersistenceManagerFactory();
147
148             if (method.getName().equals("getPersistenceManager")) {
149                 PersistenceManager pm =
150                         PersistenceManagerFactoryUtils.doGetPersistenceManager(target, isAllowCreate());
151                 Class JavaDoc[] ifcs = ClassUtils.getAllInterfaces(pm);
152                 return (PersistenceManager) Proxy.newProxyInstance(
153                         getClass().getClassLoader(), ifcs, new TransactionAwareInvocationHandler(pm, target));
154             }
155             else if (method.getName().equals("equals")) {
156                 // Only consider equal when proxies are identical.
157
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
158             }
159             else if (method.getName().equals("hashCode")) {
160                 // Use hashCode of PersistenceManagerFactory proxy.
161
return new Integer JavaDoc(hashCode());
162             }
163
164             // Invoke method on target PersistenceManagerFactory.
165
try {
166                 return method.invoke(target, args);
167             }
168             catch (InvocationTargetException JavaDoc ex) {
169                 throw ex.getTargetException();
170             }
171         }
172     }
173
174
175     /**
176      * Invocation handler that delegates close calls on PersistenceManagers to
177      * PersistenceManagerFactoryUtils for being aware of thread-bound transactions.
178      */

179     private static class TransactionAwareInvocationHandler implements InvocationHandler JavaDoc {
180
181         private final PersistenceManager target;
182
183         private final PersistenceManagerFactory persistenceManagerFactory;
184
185         public TransactionAwareInvocationHandler(PersistenceManager target, PersistenceManagerFactory pmf) {
186             this.target = target;
187             this.persistenceManagerFactory = pmf;
188         }
189
190         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
191             // Invocation on PersistenceManager interface coming in...
192

193             if (method.getName().equals("equals")) {
194                 // Only consider equal when proxies are identical.
195
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
196             }
197             else if (method.getName().equals("hashCode")) {
198                 // Use hashCode of PersistenceManager proxy.
199
return new Integer JavaDoc(hashCode());
200             }
201             else if (method.getName().equals("close")) {
202                 // Handle close method: only close if not within a transaction.
203
if (this.persistenceManagerFactory != null) {
204                     PersistenceManagerFactoryUtils.doReleasePersistenceManager(
205                             this.target, this.persistenceManagerFactory);
206                 }
207                 return null;
208             }
209
210             // Invoke method on target PersistenceManager.
211
try {
212                 return method.invoke(this.target, args);
213             }
214             catch (InvocationTargetException JavaDoc ex) {
215                 throw ex.getTargetException();
216             }
217         }
218     }
219
220 }
221
Popular Tags