/jboss-as-7.1.1.Final/ejb3/src/main/java/org/jboss/as/ejb3/component/stateful/StatefulComponentDescription.java
Java | 374 lines | 275 code | 55 blank | 44 comment | 49 complexity | b76dc7f355f17b31cf9178963a71caba MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
1/*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2010, Red Hat, Inc., and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22
23package org.jboss.as.ejb3.component.stateful;
24
25
26import static org.jboss.as.ejb3.EjbMessages.MESSAGES;
27
28import java.lang.reflect.Method;
29import java.util.Collection;
30import java.util.Collections;
31import java.util.HashMap;
32import java.util.Map;
33
34import javax.ejb.EJBLocalObject;
35import javax.ejb.EJBObject;
36import javax.ejb.TransactionManagementType;
37
38import org.jboss.as.ee.component.Component;
39import org.jboss.as.ee.component.ComponentConfiguration;
40import org.jboss.as.ee.component.ComponentConfigurator;
41import org.jboss.as.ee.component.ComponentDescription;
42import org.jboss.as.ee.component.ComponentInstanceInterceptorFactory;
43import org.jboss.as.ee.component.ViewConfiguration;
44import org.jboss.as.ee.component.ViewConfigurator;
45import org.jboss.as.ee.component.ViewDescription;
46import org.jboss.as.ee.component.interceptors.InterceptorOrder;
47import org.jboss.as.ee.component.serialization.WriteReplaceInterface;
48import org.jboss.as.ejb3.cache.CacheInfo;
49import org.jboss.as.ejb3.component.EJBViewDescription;
50import org.jboss.as.ejb3.component.MethodIntf;
51import org.jboss.as.ejb3.component.interceptors.ComponentTypeIdentityInterceptorFactory;
52import org.jboss.as.ejb3.component.session.SessionBeanComponentDescription;
53import org.jboss.as.ejb3.deployment.EjbJarDescription;
54import org.jboss.as.ejb3.tx.StatefulBMTInterceptor;
55import org.jboss.as.server.deployment.DeploymentPhaseContext;
56import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
57import org.jboss.as.server.deployment.reflect.ClassIndex;
58import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
59import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
60import org.jboss.invocation.ImmediateInterceptorFactory;
61import org.jboss.invocation.Interceptor;
62import org.jboss.invocation.InterceptorFactory;
63import org.jboss.invocation.InterceptorFactoryContext;
64import org.jboss.invocation.proxy.MethodIdentifier;
65import org.jboss.metadata.ejb.spec.SessionBeanMetaData;
66import org.jboss.modules.ModuleLoader;
67import org.jboss.msc.service.ServiceName;
68
69/**
70 * User: jpai
71 */
72public class StatefulComponentDescription extends SessionBeanComponentDescription {
73
74 private Method afterBegin;
75 private Method afterCompletion;
76 private Method beforeCompletion;
77 private final Map<MethodIdentifier, StatefulRemoveMethod> removeMethods = new HashMap<MethodIdentifier, StatefulRemoveMethod>();
78 private StatefulTimeoutInfo statefulTimeout;
79 private CacheInfo cache;
80
81 /**
82 * Map of init method, to the corresponding home create method on the home interface
83 */
84 private Map<Method, String> initMethods = new HashMap<Method, String>(0);
85
86 public class StatefulRemoveMethod {
87 private final MethodIdentifier methodIdentifier;
88 private final boolean retainIfException;
89
90 StatefulRemoveMethod(final MethodIdentifier method, final boolean retainIfException) {
91 if (method == null) {
92 throw MESSAGES.removeMethodIsNull();
93 }
94 this.methodIdentifier = method;
95 this.retainIfException = retainIfException;
96 }
97
98 public MethodIdentifier getMethodIdentifier() {
99 return methodIdentifier;
100 }
101
102 public boolean isRetainIfException() {
103 return retainIfException;
104 }
105
106 @Override
107 public boolean equals(Object o) {
108 if (this == o) return true;
109 if (o == null || getClass() != o.getClass()) return false;
110
111 StatefulRemoveMethod that = (StatefulRemoveMethod) o;
112
113 if (!methodIdentifier.equals(that.methodIdentifier)) return false;
114
115 return true;
116 }
117
118 @Override
119 public int hashCode() {
120 return methodIdentifier.hashCode();
121 }
122 }
123
124 /**
125 * Construct a new instance.
126 *
127 * @param componentName the component name
128 * @param componentClassName the component instance class name
129 * @param ejbJarDescription the module description
130 */
131 public StatefulComponentDescription(final String componentName, final String componentClassName, final EjbJarDescription ejbJarDescription,
132 final ServiceName deploymentUnitServiceName, final SessionBeanMetaData descriptorData) {
133 super(componentName, componentClassName, ejbJarDescription, deploymentUnitServiceName, descriptorData);
134
135 addInitMethodInvokingInterceptor();
136 }
137
138 private void addInitMethodInvokingInterceptor() {
139 getConfigurators().addFirst(new ComponentConfigurator() {
140 @Override
141 public void configure(DeploymentPhaseContext context, ComponentDescription description, ComponentConfiguration configuration) throws DeploymentUnitProcessingException {
142 configuration.addPostConstructInterceptor(StatefulInitMethodInterceptorFactory.INSTANCE, InterceptorOrder.ComponentPostConstruct.SFSB_INIT_METHOD);
143 }
144 });
145 }
146
147 private void addStatefulSessionSynchronizationInterceptor() {
148 // we must run before the DefaultFirstConfigurator
149 getConfigurators().addFirst(new ComponentConfigurator() {
150 @Override
151 public void configure(DeploymentPhaseContext context, ComponentDescription description, ComponentConfiguration configuration) throws DeploymentUnitProcessingException {
152 final InterceptorFactory interceptorFactory = StatefulSessionSynchronizationInterceptor.factory(getTransactionManagementType());
153 configuration.addComponentInterceptor(interceptorFactory, InterceptorOrder.Component.SYNCHRONIZATION_INTERCEPTOR, false);
154 }
155 });
156
157 }
158
159 @Override
160 public ComponentConfiguration createConfiguration(final ClassIndex classIndex, final ClassLoader moduleClassLoader, final ModuleLoader moduleLoader) {
161
162 final ComponentConfiguration statefulComponentConfiguration = new ComponentConfiguration(this, classIndex, moduleClassLoader, moduleLoader);
163 // setup the component create service
164 statefulComponentConfiguration.setComponentCreateServiceFactory(new StatefulComponentCreateServiceFactory());
165
166 if (getTransactionManagementType() == TransactionManagementType.BEAN) {
167 getConfigurators().add(new ComponentConfigurator() {
168 @Override
169 public void configure(final DeploymentPhaseContext context, final ComponentDescription description, final ComponentConfiguration configuration) throws DeploymentUnitProcessingException {
170 final ComponentInstanceInterceptorFactory bmtComponentInterceptorFactory = new ComponentInstanceInterceptorFactory() {
171 @Override
172 protected Interceptor create(Component component, InterceptorFactoryContext context) {
173 if (!(component instanceof StatefulSessionComponent)) {
174 throw MESSAGES.componentNotInstanceOfSessionComponent(component, component.getComponentClass(), "stateful");
175 }
176 return new StatefulBMTInterceptor((StatefulSessionComponent) component);
177 }
178 };
179 configuration.addComponentInterceptor(bmtComponentInterceptorFactory, InterceptorOrder.Component.BMT_TRANSACTION_INTERCEPTOR, false);
180 }
181 });
182 }
183 addStatefulSessionSynchronizationInterceptor();
184
185 return statefulComponentConfiguration;
186 }
187
188 @Override
189 public boolean allowsConcurrentAccess() {
190 return true;
191 }
192
193 public Method getAfterBegin() {
194 return afterBegin;
195 }
196
197 public Method getAfterCompletion() {
198 return afterCompletion;
199 }
200
201 public Method getBeforeCompletion() {
202 return beforeCompletion;
203 }
204
205 @Override
206 public SessionBeanType getSessionBeanType() {
207 return SessionBeanComponentDescription.SessionBeanType.STATEFUL;
208 }
209
210 public void setAfterBegin(final Method afterBegin) {
211 this.afterBegin = afterBegin;
212 }
213
214 public void setAfterCompletion(final Method afterCompletion) {
215 this.afterCompletion = afterCompletion;
216 }
217
218 public void setBeforeCompletion(final Method afterCompletion) {
219 this.beforeCompletion = afterCompletion;
220 }
221
222 @Override
223 protected void setupViewInterceptors(EJBViewDescription view) {
224 // let super do its job
225 super.setupViewInterceptors(view);
226 // add the @Remove method interceptor
227 this.addRemoveMethodInterceptor(view);
228 // setup the instance associating interceptors
229 this.addStatefulInstanceAssociatingInterceptor(view);
230
231 this.addViewSerializationInterceptor(view);
232
233 if (view.getMethodIntf() == MethodIntf.REMOTE) {
234 view.getConfigurators().add(new ViewConfigurator() {
235 @Override
236 public void configure(final DeploymentPhaseContext context, final ComponentConfiguration componentConfiguration, final ViewDescription description, final ViewConfiguration configuration) throws DeploymentUnitProcessingException {
237 final String earApplicationName = componentConfiguration.getComponentDescription().getModuleDescription().getEarApplicationName();
238 configuration.setViewInstanceFactory(new StatefulRemoteViewInstanceFactory(earApplicationName, componentConfiguration.getModuleName(), componentConfiguration.getComponentDescription().getModuleDescription().getDistinctName(), componentConfiguration.getComponentName()));
239 }
240 });
241 }
242 }
243
244 @Override
245 protected ViewConfigurator getSessionBeanObjectViewConfigurator() {
246 return StatefulSessionBeanObjectViewConfigurator.INSTANCE;
247 }
248
249 private void addViewSerializationInterceptor(final ViewDescription view) {
250 view.setSerializable(true);
251 view.setUseWriteReplace(true);
252 view.getConfigurators().add(new ViewConfigurator() {
253 @Override
254 public void configure(final DeploymentPhaseContext context, final ComponentConfiguration componentConfiguration, final ViewDescription description, final ViewConfiguration configuration) throws DeploymentUnitProcessingException {
255 final DeploymentReflectionIndex index = context.getDeploymentUnit().getAttachment(org.jboss.as.server.deployment.Attachments.REFLECTION_INDEX);
256 ClassReflectionIndex<WriteReplaceInterface> classIndex = index.getClassIndex(WriteReplaceInterface.class);
257 for (Method method : classIndex.getMethods()) {
258 configuration.addClientInterceptor(method, new StatefulWriteReplaceInterceptor.Factory(configuration.getViewServiceName().getCanonicalName()), InterceptorOrder.Client.WRITE_REPLACE);
259 }
260 }
261 });
262 }
263
264 public void addRemoveMethod(final MethodIdentifier removeMethod, final boolean retainIfException) {
265 if (removeMethod == null) {
266 throw MESSAGES.removeMethodIsNull();
267 }
268 this.removeMethods.put(removeMethod, new StatefulRemoveMethod(removeMethod, retainIfException));
269 }
270
271 public Collection<StatefulRemoveMethod> getRemoveMethods() {
272 return this.removeMethods.values();
273 }
274
275 public StatefulTimeoutInfo getStatefulTimeout() {
276 return statefulTimeout;
277 }
278
279 public void setStatefulTimeout(final StatefulTimeoutInfo statefulTimeout) {
280 this.statefulTimeout = statefulTimeout;
281 }
282
283 private void addStatefulInstanceAssociatingInterceptor(final EJBViewDescription view) {
284 view.getConfigurators().add(new ViewConfigurator() {
285 @Override
286 public void configure(final DeploymentPhaseContext context, final ComponentConfiguration componentConfiguration, ViewDescription description, ViewConfiguration viewConfiguration) throws DeploymentUnitProcessingException {
287 EJBViewDescription ejbViewDescription = (EJBViewDescription) view;
288 //if this is a home interface we add a different interceptor
289 if (ejbViewDescription.getMethodIntf() == MethodIntf.HOME || ejbViewDescription.getMethodIntf() == MethodIntf.LOCAL_HOME) {
290 for (Method method : viewConfiguration.getProxyFactory().getCachedMethods()) {
291 if ((method.getName().equals("hashCode") && method.getParameterTypes().length == 0) ||
292 method.getName().equals("equals") && method.getParameterTypes().length == 1 &&
293 method.getParameterTypes()[0] == Object.class) {
294 viewConfiguration.addClientInterceptor(method, ComponentTypeIdentityInterceptorFactory.INSTANCE, InterceptorOrder.Client.EJB_EQUALS_HASHCODE);
295 }
296 }
297 } else {
298 // interceptor factory return an interceptor which sets up the session id on component view instance creation
299 final InterceptorFactory sessionIdGeneratingInterceptorFactory = StatefulComponentSessionIdGeneratingInterceptorFactory.INSTANCE;
300
301 // add the session id generating interceptor to the start of the *post-construct interceptor chain of the ComponentViewInstance*
302 viewConfiguration.addClientPostConstructInterceptor(sessionIdGeneratingInterceptorFactory, InterceptorOrder.ClientPostConstruct.INSTANCE_CREATE);
303
304 for (Method method : viewConfiguration.getProxyFactory().getCachedMethods()) {
305 if ((method.getName().equals("hashCode") && method.getParameterTypes().length == 0) ||
306 method.getName().equals("equals") && method.getParameterTypes().length == 1 &&
307 method.getParameterTypes()[0] == Object.class) {
308 viewConfiguration.addClientInterceptor(method, StatefulIdentityInterceptorFactory.INSTANCE, InterceptorOrder.Client.EJB_EQUALS_HASHCODE);
309 }
310 }
311 }
312 }
313 });
314 if (view.getMethodIntf() != MethodIntf.LOCAL_HOME && view.getMethodIntf() != MethodIntf.HOME) {
315 view.getConfigurators().add(new ViewConfigurator() {
316 @Override
317 public void configure(DeploymentPhaseContext context, ComponentConfiguration componentConfiguration, ViewDescription description, ViewConfiguration configuration) throws DeploymentUnitProcessingException {
318 // add the instance associating interceptor to the *start of the invocation interceptor chain*
319 configuration.addClientInterceptor(StatefulComponentIdInterceptor.Factory.INSTANCE, InterceptorOrder.Client.ASSOCIATING_INTERCEPTOR);
320 configuration.addViewInterceptor(StatefulComponentInstanceInterceptor.FACTORY, InterceptorOrder.View.ASSOCIATING_INTERCEPTOR);
321 }
322 });
323 }
324
325 }
326
327 private void addRemoveMethodInterceptor(final ViewDescription view) {
328 view.getConfigurators().add(new ViewConfigurator() {
329 @Override
330 public void configure(DeploymentPhaseContext context, ComponentConfiguration componentConfiguration, ViewDescription description, ViewConfiguration configuration) throws DeploymentUnitProcessingException {
331 final StatefulComponentDescription statefulComponentDescription = (StatefulComponentDescription) componentConfiguration.getComponentDescription();
332 final Collection<StatefulRemoveMethod> removeMethods = statefulComponentDescription.getRemoveMethods();
333 if (removeMethods.isEmpty()) {
334 return;
335 }
336 for (final Method viewMethod : configuration.getProxyFactory().getCachedMethods()) {
337 final MethodIdentifier viewMethodIdentifier = MethodIdentifier.getIdentifierForMethod(viewMethod);
338 for (final StatefulRemoveMethod removeMethod : removeMethods) {
339 if (removeMethod.methodIdentifier.equals(viewMethodIdentifier)) {
340
341 //we do not want to add this if it is the Ejb(Local)Object.remove() method, as that is handed elsewhere
342 final boolean object = EJBObject.class.isAssignableFrom(configuration.getViewClass()) || EJBLocalObject.class.isAssignableFrom(configuration.getViewClass());
343 if (!object || !viewMethodIdentifier.getName().equals("remove") || viewMethodIdentifier.getParameterTypes().length != 0) {
344 configuration.addViewInterceptor(viewMethod, new ImmediateInterceptorFactory(new StatefulRemoveInterceptor(removeMethod.retainIfException)), InterceptorOrder.View.SESSION_REMOVE_INTERCEPTOR);
345 }
346 break;
347 }
348 }
349 }
350 }
351 });
352 }
353
354 public void addInitMethod(final Method method, final String createMethod) {
355 initMethods.put(method, createMethod);
356 }
357
358 public Map<Method, String> getInitMethods() {
359 return Collections.unmodifiableMap(initMethods);
360 }
361
362 public CacheInfo getCache() {
363 return this.cache;
364 }
365
366 public void setCache(CacheInfo cache) {
367 this.cache = cache;
368 }
369
370 @Override
371 public boolean isPassivationApplicable() {
372 return true;
373 }
374}