001: /**
002: * EasyBeans
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: TransactionResolver.java 2057 2007-11-21 15:35:32Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.deployment.annotations.helper.bean;
025:
026: import static javax.ejb.TransactionManagementType.BEAN;
027:
028: import java.util.ArrayList;
029: import java.util.List;
030:
031: import javax.ejb.TransactionAttributeType;
032: import javax.ejb.TransactionManagementType;
033:
034: import org.ow2.easybeans.asm.Type;
035: import org.ow2.easybeans.deployment.annotations.JClassInterceptor;
036: import org.ow2.easybeans.deployment.annotations.JMethod;
037: import org.ow2.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata;
038: import org.ow2.easybeans.deployment.annotations.metadata.MethodAnnotationMetadata;
039: import org.ow2.easybeans.persistence.interceptors.NoTxMethodCallOnlyEntityManagerInterceptor;
040: import org.ow2.easybeans.transaction.interceptors.BMTStatefulTransactionInterceptor;
041: import org.ow2.easybeans.transaction.interceptors.BMTStatelessTransactionInterceptor;
042: import org.ow2.easybeans.transaction.interceptors.BMTTransactionInterceptor;
043: import org.ow2.easybeans.transaction.interceptors.CMTMandatoryTransactionInterceptor;
044: import org.ow2.easybeans.transaction.interceptors.CMTNeverTransactionInterceptor;
045: import org.ow2.easybeans.transaction.interceptors.CMTNotSupportedTransactionInterceptor;
046: import org.ow2.easybeans.transaction.interceptors.CMTRequiredTransactionInterceptor;
047: import org.ow2.easybeans.transaction.interceptors.CMTRequiresNewTransactionInterceptor;
048: import org.ow2.easybeans.transaction.interceptors.CMTSupportsTransactionInterceptor;
049: import org.ow2.easybeans.transaction.interceptors.ListenerSessionSynchronizationInterceptor;
050:
051: /**
052: * This class adds the interceptor for transaction on a given method.
053: * @author Florent Benoit
054: */
055: public final class TransactionResolver {
056:
057: /**
058: * Signature of EasyBeans interceptors.
059: */
060: private static final JMethod EASYBEANS_INTERCEPTOR = new JMethod(
061: 0,
062: "intercept",
063: "(Lorg/ow2/easybeans/api/EasyBeansInvocationContext;)Ljava/lang/Object;",
064: null, new String[] { "java/lang/Exception" });
065:
066: /**
067: * CMT Required transaction interceptor.
068: */
069: private static final String CMT_REQUIRED_INTERCEPTOR = Type
070: .getInternalName(CMTRequiredTransactionInterceptor.class);
071:
072: /**
073: * CMT Mandatory transaction interceptor.
074: */
075: private static final String CMT_MANDATORY_INTERCEPTOR = Type
076: .getInternalName(CMTMandatoryTransactionInterceptor.class);
077:
078: /**
079: * CMT Never transaction interceptor.
080: */
081: private static final String CMT_NEVER_INTERCEPTOR = Type
082: .getInternalName(CMTNeverTransactionInterceptor.class);
083:
084: /**
085: * CMT NotSupported transaction interceptor.
086: */
087: private static final String CMT_NOT_SUPPORTED_INTERCEPTOR = Type
088: .getInternalName(CMTNotSupportedTransactionInterceptor.class);
089:
090: /**
091: * CMT Supports transaction interceptor.
092: */
093: private static final String CMT_SUPPORTS_INTERCEPTOR = Type
094: .getInternalName(CMTSupportsTransactionInterceptor.class);
095:
096: /**
097: * CMT RequiresNew transaction interceptor.
098: */
099: private static final String CMT_REQUIRES_NEW_INTERCEPTOR = Type
100: .getInternalName(CMTRequiresNewTransactionInterceptor.class);
101:
102: /**
103: * BMT transaction interceptor.
104: */
105: private static final String BMT_INTERCEPTOR = Type
106: .getInternalName(BMTTransactionInterceptor.class);
107:
108: /**
109: * BMT stateful transaction interceptor.
110: */
111: private static final String BMT_STATEFUL_INTERCEPTOR = Type
112: .getInternalName(BMTStatefulTransactionInterceptor.class);
113:
114: /**
115: * BMT stateless transaction interceptor.
116: */
117: private static final String BMT_STATELESS_INTERCEPTOR = Type
118: .getInternalName(BMTStatelessTransactionInterceptor.class);
119:
120: /**
121: * ListenerSessionSynchronizationInterceptor transaction interceptor.
122: */
123: private static final String LISTENER_SESSION_SYNCHRO_INTERCEPTOR = Type
124: .getInternalName(ListenerSessionSynchronizationInterceptor.class);
125:
126: /**
127: * Interceptor used for transaction-scoped persistence context (when there is no transaction).
128: */
129: private static final String NOTX_TRANSACTION_SCOPED_INTERCEPTOR = Type
130: .getInternalName(NoTxMethodCallOnlyEntityManagerInterceptor.class);
131:
132: /**
133: * javax.ejb.SessionSynchronization interface.
134: */
135: private static final String SESSION_SYNCHRONIZATION_INTERFACE = "javax/ejb/SessionSynchronization";
136:
137: /**
138: * Helper class, no public constructor.
139: */
140: private TransactionResolver() {
141: }
142:
143: /**
144: * Adds the right transaction interceptor depending of the transactional
145: * attribute set by the user.
146: * @param bean the given bean on which set the transactional interceptor.
147: */
148: public static void resolve(final ClassAnnotationMetadata bean) {
149: TransactionAttributeType beanTxType = bean
150: .getTransactionAttributeType();
151: TransactionManagementType beanTxManaged = bean
152: .getTransactionManagementType();
153:
154: // Checks if Synchronization is needed for this stateful bean
155: boolean addSynchro = false;
156: if (bean.isStateful()) {
157: String[] interfaces = bean.getInterfaces();
158: if (interfaces != null) {
159: for (String itf : interfaces) {
160: if (SESSION_SYNCHRONIZATION_INTERFACE.equals(itf)) {
161: addSynchro = true;
162: break;
163: }
164: }
165: }
166:
167: }
168:
169: for (MethodAnnotationMetadata method : bean
170: .getMethodAnnotationMetadataCollection()) {
171:
172: List<JClassInterceptor> interceptors = method
173: .getInterceptors();
174: if (interceptors == null) {
175: interceptors = new ArrayList<JClassInterceptor>();
176: }
177:
178: // Bean managed or container managed ?
179: if (beanTxManaged.equals(BEAN)) {
180: // BMT
181: if (bean.isStateful()) {
182: interceptors.add(new JClassInterceptor(
183: BMT_STATEFUL_INTERCEPTOR,
184: EASYBEANS_INTERCEPTOR));
185: } else if (bean.isStateless()) {
186: interceptors.add(new JClassInterceptor(
187: BMT_STATELESS_INTERCEPTOR,
188: EASYBEANS_INTERCEPTOR));
189: } else {
190: interceptors.add(new JClassInterceptor(
191: BMT_INTERCEPTOR, EASYBEANS_INTERCEPTOR));
192: }
193: // Add interceptor for EntityManager
194: interceptors.add(new JClassInterceptor(
195: NOTX_TRANSACTION_SCOPED_INTERCEPTOR,
196: EASYBEANS_INTERCEPTOR));
197: } else {
198: // CMT
199: TransactionAttributeType methodTx = method
200: .getTransactionAttributeType();
201:
202: // Set method tx attribute to the class tx attribute if none was
203: // set.
204: if (methodTx == null) {
205: if (!method.isInherited()) {
206: methodTx = beanTxType;
207: } else {
208: // inherited method, take value of the original class
209: methodTx = method
210: .getOriginalClassAnnotationMetadata()
211: .getTransactionAttributeType();
212: }
213: }
214:
215: switch (methodTx) {
216: case MANDATORY:
217: interceptors.add(new JClassInterceptor(
218: CMT_MANDATORY_INTERCEPTOR,
219: EASYBEANS_INTERCEPTOR));
220: break;
221: case NEVER:
222: interceptors.add(new JClassInterceptor(
223: CMT_NEVER_INTERCEPTOR,
224: EASYBEANS_INTERCEPTOR));
225: interceptors.add(new JClassInterceptor(
226: NOTX_TRANSACTION_SCOPED_INTERCEPTOR,
227: EASYBEANS_INTERCEPTOR));
228: break;
229: case NOT_SUPPORTED:
230: interceptors.add(new JClassInterceptor(
231: CMT_NOT_SUPPORTED_INTERCEPTOR,
232: EASYBEANS_INTERCEPTOR));
233: interceptors.add(new JClassInterceptor(
234: NOTX_TRANSACTION_SCOPED_INTERCEPTOR,
235: EASYBEANS_INTERCEPTOR));
236: break;
237: case REQUIRED:
238: interceptors.add(new JClassInterceptor(
239: CMT_REQUIRED_INTERCEPTOR,
240: EASYBEANS_INTERCEPTOR));
241: break;
242: case REQUIRES_NEW:
243: interceptors.add(new JClassInterceptor(
244: CMT_REQUIRES_NEW_INTERCEPTOR,
245: EASYBEANS_INTERCEPTOR));
246: break;
247: case SUPPORTS:
248: interceptors.add(new JClassInterceptor(
249: CMT_SUPPORTS_INTERCEPTOR,
250: EASYBEANS_INTERCEPTOR));
251: interceptors.add(new JClassInterceptor(
252: NOTX_TRANSACTION_SCOPED_INTERCEPTOR,
253: EASYBEANS_INTERCEPTOR));
254: break;
255: default:
256: throw new IllegalStateException(
257: "Invalid tx attribute on method '"
258: + method.getMethodName()
259: + "', value = '" + methodTx + "'.");
260: }
261:
262: // Add listener interceptor for stateul bean only if the bean implements SessionSynchronization interface
263: if (addSynchro) {
264: interceptors.add(new JClassInterceptor(
265: LISTENER_SESSION_SYNCHRO_INTERCEPTOR,
266: EASYBEANS_INTERCEPTOR));
267: }
268: // End CMT
269: }
270: method.setInterceptors(interceptors);
271: }
272: }
273: }
|