After several attempts at using deployment descriptors for my sample EJB3.0 app I have decided to go the other route (as recommended to me by someone here a few days ago) and chosen Annotations!
From what I have found I think I've done it correct. The only problem is the presentation level (JSPs / Servlets for now) can not see the EJB Module classes. I can import them in the Servlet, but when executing the app I get a:-
Exception: javax.naming.NamingException: ejb ref resolution error for remote business interfacecom.myproject.sample1.SampleRemote [Root exception is java.lang.ClassNotFoundException: com.myproject.sample1.SampleRemote]
Ideally I want to deploy the WAR and EJB Jar as separate apps, because long term I'm thinking of having them on separate machines.
I have deployed this to a Sun Java WebApp 9.0 Server
So basically I need to know how to call a EJB (using Remote Interface) from a Servlet within a separate App?
Once again, many thanks for any help. [ October 15, 2007: Message edited by: Keith Seller ]
Just to add to this, I read in TheServerSide forums a thread with someone having the same problem as me and it was usggested that WAR files can not call EJBs from separate JARS!
Is this true? I find it very hard to believe because that surely defeats the entire point of the Remote Interface!!!
They suggested copying the EJB jar (ejb_module.jar in my case) or at least it's interfaces into a new JAR file which is then copied into the lib folder of the WAR file. This seems like madness! Surely if I do that, I might as well have all the classes under the same WAR/JAR and forget Remote Interfacing?
Taken from theserverside.com ----------------------------- So a WAR in the same EAR of an EJB-jar can see automatically the EJB-jar classes/interfaces (this is also common behaviour since EJB 2.0). WARs in different EARs can't.
There are several workarounds. But first of all, you need to package the EJB "client" classes (interfaces, VOs etc.) into a separate JAR (let's call it "ejb-client.jar"). The possibilities are:
1. (I dislike this) You can put this ejb-client.jar in the server classpath, by editing the "startWebLogic.bat" file (curiously, there is no "lib/ext" folder in WLS8);
2. You can copy this ejb-client.jar into the WEB-INF/lib folder of each web application (I think BEA recommends this procedure);
3. You can try to fiddle with the application manifest file Class-Path entry, inserting a path like "../EJBEAR.ear/ejb-jar.jar"), therefore putting the EJBs original JAR in the client application classloader (there is no need of an ejb-client.jar then). This is a bit too low level, and it is hard to figure out the correct Class-Path entry;
[ October 16, 2007: Message edited by: Keith Seller ]
i have tried what I think the above was suggesting, which is create another JAR file fir the EJB Interfaces and imported this into the Client WAR WEB-INF/lib folder.
I have deployed both the EJB jar and Client war files again and tried running the app.
The problem is,as soon as I make a call to a Remote Iterface Method i get the following error: [#|2007-10-16T14:07:36.173+0100|SEVERE|sun-appserver-pe9.0|javax.enterprise.system.container.web|_ThreadID=12;_ThreadName=httpWorkerThread-8080-0;_RequestID=27abee96-8da0-487d-81a1-26788c38a6b7;|StandardWrapperValve[SampleServlet]: Servlet.service() for servlet SampleServlet threw exception java.lang.NullPointerException at com.myproject.servlets.SampleServlet.doPost(SampleServlet.java:23) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:397) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:278) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:536) at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:240) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:179) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:73) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:182) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566) at com.sun.enterprise.web.VirtualServerPipeline.invoke(VirtualServerPipeline.java:120) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:137) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:566) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:536) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939) at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:231) at com.sun.enterprise.web.connector.grizzly.ProcessorTask.invokeAdapter(ProcessorTask.java:667) at com.sun.enterprise.web.connector.grizzly.ProcessorTask.processNonBlocked(ProcessorTask.java:574) at com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:844) at com.sun.enterprise.web.connector.grizzly.ReadTask.executeProcessorTask(ReadTask.java:287) at com.sun.enterprise.web.connector.grizzly.ReadTask.doTask(ReadTask.java:212) at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:252) at com.sun.enterprise.web.connector.grizzly.WorkerThread.run(WorkerThread.java:75)
So something is still obviously wrong.
Also how would the remote Interface on the WAR know where the EJB Bean is under the JAR?
Got it working, I now have a war file calling EJBs from a jar file (for now on the same WebApp) but looking at the properties I just change the hostname/port if it's on a different machine. It was this bit of code under GlassFish EJB FAQs that sorted it. Properties props = new Properties(); props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory"); props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming"); props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
// optional. Defaults to localhost. Only needed if web server is running // on a different host than the appserver props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
// optional. Defaults to 3700. Only needed if target orb port is not 3700. props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
If you want to deploy the WAR and EJB Jar as separate apps separate machines, then all EJB call will be Remote Call , in this case @EJB annotaction will not work.Write Jndi lookup call for remote interface in WAR application which will act as delegare , will gave you remote object , by this object you can call EJb Bean methods in your servlet.