KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > net > axis > server > EJBProvider


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7
8 // $Id: EJBProvider.java,v 1.20.4.2 2005/03/02 14:19:51 tdiesler Exp $
9

10 package org.jboss.net.axis.server;
11
12 import org.jboss.axis.AxisFault;
13 import org.jboss.axis.MessageContext;
14 import org.jboss.axis.description.OperationDesc;
15 import org.jboss.axis.description.ServiceDesc;
16 import org.jboss.axis.handlers.soap.SOAPService;
17 import org.jboss.axis.message.SOAPEnvelopeAxisImpl;
18
19 import javax.naming.NamingException JavaDoc;
20 import javax.servlet.http.HttpSessionBindingEvent JavaDoc;
21 import javax.servlet.http.HttpSessionBindingListener JavaDoc;
22 import javax.xml.rpc.server.ServiceLifecycle JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26
27 /**
28  * <p>
29  * A JBoss-compatible EJB Provider that exposes the methods of
30  * any session bean as a web service endpoint.
31  * </p>
32  * <p>
33  * Basically it is a slimmed downed derivative of
34  * the Axis-EJBProvider without the usual, corba-related configuration mumbo-jumbo
35  * that is operating under the presumption that the right classloader has already been set
36  * by the request flow chain (@see org.jboss.net.axis.SetClassLoaderHandler).
37  * </p>
38  * <p>
39  * Since Version 1.5 and thanks to Kevin Conner, we now also support
40  * stateful beans that are tied to the service scope (you should reasonably
41  * choose scope="session" in the <service/> tag of the corresponding web-service.xml)
42  * Note that by using a jaxp lifecycle handler we synchronize with
43  * web service scopes that can be shorter-lived than the surrounding http-session.
44  * However, as I understood Kevin and from my observations, it seems that Axis
45  * and hence the jaxp lifecycle does not get notified upon http-session expiration.
46  * Hence our lifecycle listener currently implements the http session
47  * lifecycle, too (which is not very transport-agnostic, but who cares
48  * at the moment).
49  * </p>
50  * <p>
51  * EJBProvider is able to recognize an {@link WsdlAwareHttpActionHandler} in its
52  * transport chain such that it will set the soap-action headers in the wsdl.
53  * </p>
54  * @author <a HREF="mailto:Christoph.Jung@infor.de">Christoph G. Jung</a>
55  * @since 5. Oktober 2001, 13:02
56  * @version $Revision: 1.20.4.2 $
57  */

58
59 public class EJBProvider extends org.jboss.axis.providers.java.EJBProvider
60 {
61
62    //
63
// Attributes
64
//
65

66    /** the real remote class we are shielding */
67    protected Class JavaDoc remoteClass;
68
69    /** we are caching the home for perfomance purposes */
70    protected Object JavaDoc ejbHome;
71
72    /** we are caching the create method for perfomance purposes */
73    protected Method JavaDoc ejbCreateMethod;
74
75    //
76
// Constructors
77
//
78

79    /** Creates new EJBProvider */
80    public EJBProvider()
81    {
82    }
83
84    //
85
// Helper Methods
86
//
87

88    /**
89     * access home factory via jndi if
90     * reference is not yet cached
91     */

92
93    protected synchronized Object JavaDoc getEJBHome(String JavaDoc jndiName)
94            throws NamingException JavaDoc
95    {
96       if (ejbHome == null)
97       {
98          // Get the EJB Home object from JNDI
99
ejbHome = this.getCachedContext().lookup(jndiName);
100       }
101       return ejbHome;
102    }
103
104    /**
105     * access home factory via jndi if
106     * reference is not yet cached
107     */

108
109    protected synchronized Method JavaDoc getEJBCreateMethod(String JavaDoc jndiName)
110            throws NamingException JavaDoc, NoSuchMethodException JavaDoc
111    {
112       if (ejbCreateMethod == null)
113       {
114          Object JavaDoc ejbHome = getEJBHome(jndiName);
115          ejbCreateMethod =
116                  ejbHome.getClass().getMethod("create", empty_class_array);
117       }
118
119       return ejbCreateMethod;
120    }
121
122    /**
123     * Return the object which implements the service lifecycle. Makes the usual
124     * lookup->create call w/o the PortableRemoteDaDaDa for the sake of Corba.
125     * @param msgContext the message context
126     * @param clsName The JNDI name of the EJB home class
127     * @return an object that implements the service
128     */

129    protected Object JavaDoc makeNewServiceObject(MessageContext msgContext,
130                                          String JavaDoc clsName)
131            throws Exception JavaDoc
132    {
133
134       // abuse the clsName as jndi lookup name
135
Object JavaDoc ejbHome = getEJBHome(clsName);
136       // Invoke the create method of the ejbHome class without actually
137
// touching any EJB classes (i.e. no cast to EJBHome)
138
Method JavaDoc createMethod = getEJBCreateMethod(clsName);
139       // shield behind the lifecycle service
140
return new EJBServiceLifeCycle(createMethod.invoke(ejbHome, empty_object_array));
141    }
142
143    /**
144     * Return the class name of the service, note that this could be called
145     * outside the correct chain, e.g., by the url mapper. Hence we need
146     * to find the right classloader.
147     */

148
149    protected synchronized Class JavaDoc getServiceClass(String JavaDoc beanJndiName,
150                                                 SOAPService service,
151                                                 MessageContext msgContext)
152            throws AxisFault
153    {
154       if (remoteClass == null)
155       {
156
157          try
158          {
159             remoteClass = getEJBCreateMethod(beanJndiName).getReturnType();
160          }
161          catch (NamingException JavaDoc e)
162          {
163             throw new AxisFault("Could not find home in JNDI", e);
164          }
165          catch (NoSuchMethodException JavaDoc e)
166          {
167             throw new AxisFault("Could not find create method at home ;-)", e);
168          }
169       }
170
171       return remoteClass;
172    }
173
174    //
175
// Public API
176
//
177

178    /**
179     * Generate the WSDL for this service.
180     * We need to rearrange the classloader stuff for that purpose similar
181     * as we did with the service class interface
182     */

183
184    public void generateWSDL(MessageContext msgContext) throws AxisFault
185    {
186
187       // check whether there is an http action header present
188
if (msgContext != null)
189       {
190
191          boolean isSoapAction =
192                  msgContext.getProperty(Constants.ACTION_HANDLER_PRESENT_PROPERTY)
193                  == Boolean.TRUE;
194
195          // yes, then loop through the operation descriptions
196
for (Iterator JavaDoc alloperations =
197                  msgContext
198                  .getService()
199                  .getServiceDescription()
200                  .getOperations()
201                  .iterator();
202               alloperations.hasNext();
203                  )
204          {
205             OperationDesc opDesc = (OperationDesc)alloperations.next();
206             // and add a soap action tag with the name of the service
207
opDesc.setSoapAction(isSoapAction ? msgContext.getService().getName() : null);
208          }
209       }
210
211       super.generateWSDL(msgContext);
212    }
213
214    /**
215     * Override processMessage of super class in order
216     * to unpack the service object from the lifecycle
217     */

218    public void processMessage(MessageContext msgContext,
219                               SOAPEnvelopeAxisImpl reqEnv,
220                               SOAPEnvelopeAxisImpl resEnv,
221                               Object JavaDoc obj)
222            throws Exception JavaDoc
223    {
224       super.processMessage(msgContext,
225               reqEnv,
226               resEnv,
227               ((EJBServiceLifeCycle)obj).serviceObject);
228    }
229
230    /*
231     * Adds the correct stop classes and soap-action annotations to wsdl generation
232     * @see org.jboss.axis.providers.java.EJBProvider#initServiceDesc(org.jboss.axis.handlers.soap.SOAPService,org.jboss.axis.MessageContext)
233     */

234    public void initServiceDesc(SOAPService service, MessageContext msgContext)
235            throws AxisFault
236    {
237       // The service class used to fill service description is the EJB Remote/Local Interface
238
// we add EJBObject and EJBLocalObject as stop classes because we don't want any of their methods in the wsdl ...
239
// once the stop classes are right, we can generate meta-data for only the wanted methods
240

241       ServiceDesc serviceDescription = service.getServiceDescription();
242       ArrayList JavaDoc stopClasses = serviceDescription.getStopClasses();
243       if (stopClasses == null)
244          stopClasses = new ArrayList JavaDoc();
245       stopClasses.add("javax.ejb.EJBObject");
246       stopClasses.add("javax.ejb.EJBLocalObject");
247       serviceDescription.setStopClasses(stopClasses);
248
249       super.initServiceDesc(service, msgContext);
250    }
251
252    //
253
// Inner Classes
254
//
255

256    /**
257     * This is the lifecycle object that is registered in the
258     * message scope and that shields the proper bean reference
259     */

260
261    protected static class EJBServiceLifeCycle
262            implements ServiceLifecycle JavaDoc, HttpSessionBindingListener JavaDoc
263    {
264
265       //
266
// Attributes
267
//
268

269       /** may be local or remote object */
270       protected Object JavaDoc serviceObject;
271
272       //
273
// Constructors
274
//
275

276       /** constructs a new lifecycle */
277       protected EJBServiceLifeCycle(Object JavaDoc serviceObject)
278       {
279          this.serviceObject = serviceObject;
280       }
281
282       //
283
// Public API
284
//
285

286       /**
287        * call remove
288        * @see javax.xml.rpc.server.ServiceLifecycle#destroy()
289        */

290       public void destroy()
291       {
292          try
293          {
294             if (serviceObject instanceof javax.ejb.EJBObject JavaDoc)
295             {
296                try
297                {
298                   ((javax.ejb.EJBObject JavaDoc)serviceObject).remove();
299                }
300                catch (java.rmi.RemoteException JavaDoc e)
301                {
302                }
303             }
304             else
305             {
306                ((javax.ejb.EJBLocalObject JavaDoc)serviceObject).remove();
307             }
308          }
309          catch (javax.ejb.RemoveException JavaDoc e)
310          {
311          }
312          catch (Exception JavaDoc e)
313          {
314             // if we keep the instance too long, removal might happen after
315
// undeployment of the bean. Also the cached bean reference might be
316
// invalid after redeployment of the referenced bean.
317
// In such a case method invocation can cause different runtime
318
// exceptions in jboss (e.g. NullPointerException,
319
// UndeclaredThrowableException, ..). Anyway as we are no longer using
320
// the bean reference these exceptions can be ignored.
321
}
322       }
323
324       /**
325        * Nothing to be done
326        * @see javax.xml.rpc.server.ServiceLifecycle#init(Object)
327        */

328       public void init(Object JavaDoc arg0)
329       {
330       }
331
332       /**
333        * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
334        */

335       public void valueBound(HttpSessionBindingEvent JavaDoc arg0)
336       {
337          init(arg0);
338       }
339
340       /**
341        * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
342        */

343       public void valueUnbound(HttpSessionBindingEvent JavaDoc arg0)
344       {
345          destroy();
346       }
347
348    } // EJBServiceLifeCycle
349

350 } // EJBProvider
351
Popular Tags