PageRenderTime 1098ms CodeModel.GetById 88ms app.highlight 125ms RepoModel.GetById 1ms app.codeStats 1ms

/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}