KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb3 > SessionContainer


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * 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 package org.jboss.ejb3;
23
24 import java.lang.reflect.Method JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import javax.ejb.EJBObject JavaDoc;
30 import javax.ejb.Handle JavaDoc;
31 import javax.ejb.LocalHome JavaDoc;
32 import javax.ejb.RemoteHome JavaDoc;
33 import org.jboss.aop.AspectManager;
34 import org.jboss.aop.Dispatcher;
35 import org.jboss.aop.MethodInfo;
36 import org.jboss.aop.advice.Interceptor;
37 import org.jboss.aop.joinpoint.Invocation;
38 import org.jboss.aop.joinpoint.InvocationResponse;
39 import org.jboss.aop.util.MethodHashing;
40 import org.jboss.aspects.asynch.FutureHolder;
41 import org.jboss.ejb3.interceptor.InterceptorInfoRepository;
42 import org.jboss.ejb3.remoting.IsLocalInterceptor;
43 import org.jboss.ejb3.stateful.StatefulContainerInvocation;
44 import org.jboss.logging.Logger;
45 import org.jboss.serial.io.MarshalledObjectForLocalCalls;
46
47 /**
48  * Comment
49  *
50  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
51  * @version $Revision: 56592 $
52  */

53 public abstract class SessionContainer extends EJBContainer
54 {
55    @SuppressWarnings JavaDoc("unused")
56    private static final Logger log = Logger.getLogger(SessionContainer.class);
57
58    protected ProxyDeployer proxyDeployer;
59    protected Map JavaDoc clusterFamilies = new HashMap JavaDoc();
60
61    public class InvokedMethod
62    {
63       public InvokedMethod(boolean localInterface, Method JavaDoc method)
64       {
65          isLocalInterface = localInterface;
66          this.method = method;
67       }
68
69       public boolean isLocalInterface;
70       public Method JavaDoc method;
71    }
72
73    protected ThreadLocalStack<InvokedMethod> invokedMethod = new ThreadLocalStack<InvokedMethod>();
74
75    public SessionContainer(ClassLoader JavaDoc cl, String JavaDoc beanClassName, String JavaDoc ejbName, AspectManager manager,
76                            Hashtable JavaDoc ctxProperties, InterceptorInfoRepository interceptorRepository,
77                            Ejb3Deployment deployment)
78    {
79       super(Ejb3Module.BASE_EJB3_JMX_NAME + ",name=" + ejbName, manager, cl, beanClassName, ejbName, ctxProperties, interceptorRepository, deployment);
80       proxyDeployer = new ProxyDeployer(this);
81    }
82
83    public Class JavaDoc getInvokedBusinessInterface()
84    {
85       InvokedMethod method = invokedMethod.get();
86       if (method == null) throw new IllegalStateException JavaDoc("getInvokedBusinessInterface() being invoked outside of a business invocation");
87       if (method.method == null) throw new IllegalStateException JavaDoc("getInvokedBusinessInterface() being invoked outside of a business invocation");
88       if (method.isLocalInterface) return method.method.getDeclaringClass();
89       Class JavaDoc[] remoteInterfaces = ProxyFactoryHelper.getRemoteInterfaces(this);
90       for (Class JavaDoc intf : remoteInterfaces)
91       {
92          try
93          {
94             intf.getMethod(method.method.getName(), method.method.getParameterTypes());
95             return intf;
96          }
97          catch (NoSuchMethodException JavaDoc ignored)
98          {
99             // continue
100
}
101       }
102       throw new IllegalStateException JavaDoc("Unable to find geInvokedBusinessInterface()");
103    }
104
105    @Override JavaDoc
106    public void instantiated()
107    {
108       super.instantiated();
109       proxyDeployer.initializeRemoteBindingMetadata();
110       proxyDeployer.initializeLocalBindingMetadata();
111    }
112
113    @Override JavaDoc
114    public void processMetadata(DependencyPolicy dependencyPolicy)
115    {
116       super.processMetadata(dependencyPolicy);
117    }
118
119    public void start() throws Exception JavaDoc
120    {
121       super.start();
122       // So that Remoting layer can reference this container easily.
123
Dispatcher.singleton.registerTarget(getObjectName().getCanonicalName(), this);
124       proxyDeployer.start();
125    }
126
127    public Map JavaDoc getClusterFamilies()
128    {
129       return clusterFamilies;
130    }
131
132    public void stop() throws Exception JavaDoc
133    {
134       try
135       {
136          proxyDeployer.stop();
137       }
138       catch (Exception JavaDoc ignore)
139       {
140       }
141       try
142       {
143          Dispatcher.singleton.unregisterTarget(getObjectName().getCanonicalName());
144       }
145       catch (Exception JavaDoc ignore)
146       {
147       }
148    }
149
150    protected void createMethodMap()
151    {
152       super.createMethodMap();
153       try
154       {
155          RemoteHome JavaDoc home = (RemoteHome JavaDoc) resolveAnnotation(RemoteHome JavaDoc.class);
156          if (home != null)
157          {
158             Method JavaDoc[] declaredMethods = home.value().getMethods();
159             for (int i = 0; i < declaredMethods.length; i++)
160             {
161                long hash = MethodHashing.methodHash(declaredMethods[i]);
162                advisedMethods.put(hash, declaredMethods[i]);
163             }
164
165             declaredMethods = javax.ejb.EJBObject JavaDoc.class.getMethods();
166             for (int i = 0; i < declaredMethods.length; i++)
167             {
168                long hash = MethodHashing.methodHash(declaredMethods[i]);
169                advisedMethods.put(hash, declaredMethods[i]);
170             }
171          }
172
173          LocalHome JavaDoc localHome = (LocalHome JavaDoc) resolveAnnotation(LocalHome JavaDoc.class);
174          if (localHome != null)
175          {
176             Method JavaDoc[] declaredMethods = localHome.value().getMethods();
177             for (int i = 0; i < declaredMethods.length; i++)
178             {
179                long hash = MethodHashing.methodHash(declaredMethods[i]);
180                advisedMethods.put(hash, declaredMethods[i]);
181             }
182
183             declaredMethods = javax.ejb.EJBLocalObject JavaDoc.class.getMethods();
184             for (int i = 0; i < declaredMethods.length; i++)
185             {
186                long hash = MethodHashing.methodHash(declaredMethods[i]);
187                advisedMethods.put(hash, declaredMethods[i]);
188             }
189          }
190       }
191       catch (Exception JavaDoc e)
192       {
193          throw new RuntimeException JavaDoc(e);
194       }
195    }
196
197    protected boolean isHomeMethod(Method JavaDoc method)
198    {
199       if (javax.ejb.EJBHome JavaDoc.class.isAssignableFrom(method.getDeclaringClass())) return true;
200       if (javax.ejb.EJBLocalHome JavaDoc.class.isAssignableFrom(method.getDeclaringClass())) return true;
201       return false;
202    }
203
204    protected boolean isEJBObjectMethod(Method JavaDoc method)
205    {
206       if (method.getDeclaringClass().getName().equals("javax.ejb.EJBObject"))
207          return true;
208
209       if (method.getDeclaringClass().getName().equals("javax.ejb.EJBLocalObject"))
210          return true;
211
212       return false;
213    }
214
215    protected boolean isHandleMethod(Method JavaDoc method)
216    {
217       if (method.getDeclaringClass().getName().equals("javax.ejb.Handle"))
218          return true;
219
220       return false;
221    }
222
223    public static InvocationResponse marshallException(Invocation invocation, Throwable JavaDoc exception, Map JavaDoc responseContext) throws Throwable JavaDoc
224    {
225       if (!invocation.getMetaData().hasTag(IsLocalInterceptor.IS_LOCAL)) throw exception;
226
227       InvocationResponse response = new InvocationResponse();
228       response.setContextInfo(responseContext);
229
230       response.addAttachment(IsLocalInterceptor.IS_LOCAL_EXCEPTION, new MarshalledObjectForLocalCalls(exception));
231
232       return response;
233    }
234
235    public static InvocationResponse marshallResponse(Invocation invocation, Object JavaDoc rtn, Map JavaDoc responseContext)
236            throws java.io.IOException JavaDoc
237    {
238       InvocationResponse response;
239       // marshall return value
240
if (rtn != null && invocation.getMetaData().hasTag(IsLocalInterceptor.IS_LOCAL))
241       {
242          response = new InvocationResponse(new MarshalledObjectForLocalCalls(rtn));
243       }
244       else
245       {
246          response = new InvocationResponse(rtn);
247       }
248       response.setContextInfo(responseContext);
249       return response;
250    }
251    
252    /**
253     * Invoke a method on the virtual EJB bean. The method must be one of the methods defined in one
254     * of the business interfaces (or home interface) of the bean.
255     *
256     * TODO: work in progress
257     *
258     * @param factory the originating end point
259     * @param id unique identifier (primary key), can be null for stateless
260     * @param method the business or home method to invoke
261     * @param args the arguments for the method
262     * @param provider for asynchronous usage
263     */

264    public Object JavaDoc invoke(ProxyFactory factory, Object JavaDoc id, Method JavaDoc method, Object JavaDoc args[], FutureHolder provider) throws Throwable JavaDoc
265    {
266       ClassLoader JavaDoc oldLoader = Thread.currentThread().getContextClassLoader();
267       ThreadLocalENCFactory.push(enc);
268       try
269       {
270          long hash = MethodHashing.calculateHash(method);
271          MethodInfo info = (MethodInfo) methodInterceptors.get(hash);
272          if (info == null)
273          {
274             throw new RuntimeException JavaDoc(
275                     "Could not resolve beanClass method from proxy call: "
276                             + method.toString());
277          }
278
279          Method JavaDoc unadvisedMethod = info.getUnadvisedMethod();
280
281          if (unadvisedMethod != null && isHomeMethod(unadvisedMethod))
282          {
283             return invokeHomeMethod(factory, info, args);
284          }
285          else if (unadvisedMethod != null && isEJBObjectMethod(unadvisedMethod))
286          {
287             return invokeEJBObjectMethod(factory, id, info, args);
288          }
289
290          Interceptor[] aspects = info.getInterceptors();
291          // FIXME: Ahem, stateful container invocation works on all.... (violating contract though)
292
EJBContainerInvocation nextInvocation = new StatefulContainerInvocation(info, aspects, id);
293          nextInvocation.setAdvisor(this);
294          nextInvocation.setArguments(args);
295          
296          // allow a container to supplement information into an invocation
297
nextInvocation = populateInvocation(nextInvocation);
298
299          ProxyUtils.addLocalAsynchronousInfo(nextInvocation, provider);
300          try
301          {
302             invokedMethod.push(new InvokedMethod(true, method));
303             return nextInvocation.invokeNext();
304          }
305          finally
306          {
307             invokedMethod.pop();
308          }
309       }
310       finally
311       {
312          Thread.currentThread().setContextClassLoader(oldLoader);
313          ThreadLocalENCFactory.pop();
314       }
315    }
316    
317    /**
318     * TODO: work in progress (refactor both invokeHomeMethod's, localHomeInvoke)
319     */

320    private Object JavaDoc invokeHomeMethod(ProxyFactory factory, MethodInfo info, Object JavaDoc args[]) throws Exception JavaDoc
321    {
322       Method JavaDoc unadvisedMethod = info.getUnadvisedMethod();
323       if (unadvisedMethod.getName().equals("create"))
324       {
325          Class JavaDoc[] initParameterTypes = {};
326          Object JavaDoc[] initParameterValues = {};
327          if (unadvisedMethod.getParameterTypes().length > 0)
328          {
329             initParameterTypes = unadvisedMethod.getParameterTypes();
330             initParameterValues = args;
331          }
332
333          Object JavaDoc id = createSession(initParameterTypes, initParameterValues);
334          
335          Object JavaDoc proxy = factory.createProxy(id);
336
337          return proxy;
338       }
339       else if (unadvisedMethod.getName().equals("remove"))
340       {
341          if(args[0] instanceof Handle JavaDoc)
342             removeHandle((Handle JavaDoc) args[0]);
343          else
344             destroySession(args[0]);
345
346          return null;
347       }
348       else
349       {
350          throw new IllegalArgumentException JavaDoc("illegal home method " + unadvisedMethod);
351       }
352    }
353    
354    /**
355     * Create session to an EJB bean.
356     *
357     * @param initParameterTypes the parameter types used by the home's create method
358     * @param initParameterValues the arguments for the home's create method
359     * @return the identifier of the session
360     */

361    abstract protected Object JavaDoc createSession(Class JavaDoc initParameterTypes[], Object JavaDoc initParameterValues[]);
362    
363    /**
364     * Destroy a created session.
365     *
366     * @param id the identifier of the session
367     */

368    protected void destroySession(Object JavaDoc id)
369    {
370       throw new RuntimeException JavaDoc("NYI");
371    }
372    
373    protected Object JavaDoc invokeEJBObjectMethod(ProxyFactory factory, Object JavaDoc id, MethodInfo info, Object JavaDoc args[]) throws Exception JavaDoc
374    {
375       Method JavaDoc unadvisedMethod = info.getUnadvisedMethod();
376       if(unadvisedMethod.getName().equals("getEJBHome"))
377       {
378          return factory.createHomeProxy();
379       }
380       if(unadvisedMethod.getName().equals("getPrimaryKey"))
381       {
382          return id;
383       }
384       if(unadvisedMethod.getName().equals("isIdentical"))
385       {
386          // object has no identity
387
if(id == null)
388             return false;
389          
390          EJBObject JavaDoc bean = (EJBObject JavaDoc) args[0];
391
392          Object JavaDoc primaryKey = bean.getPrimaryKey();
393          if(primaryKey == null)
394             return false;
395
396          boolean isIdentical = id.equals(primaryKey);
397
398          return isIdentical;
399       }
400       if (unadvisedMethod.getName().equals("remove"))
401       {
402          destroySession(id);
403
404          return null;
405       }
406       throw new RuntimeException JavaDoc("NYI");
407    }
408    
409    /**
410     * Allow a container sub class to supplement an invocation. Per default nothing to supplement.
411     *
412     * @param invocation
413     * @return
414     */

415    protected EJBContainerInvocation populateInvocation(EJBContainerInvocation invocation)
416    {
417       return invocation;
418    }
419    
420    abstract protected void removeHandle(Handle JavaDoc handle) throws Exception JavaDoc;
421 }
Popular Tags