A simple EJB 3 + Servlet application

In previous post, I wrote a simple EJB3 bean invoked from a standalone java client. Standalone java client is convenient for prototyping and testing purpose. The most common way to invoke EJB is from a web app. Here I will add such a simple web app to invoke the foo-ejb module written in previous post.

Steps 1 - 5 are the same as in previous post, except in step 2, foo/Client.java is not needed here.

6. Servlet class

package foo;
import java.io.*;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;

public class FooServlet extends HttpServlet {
private FooRemote foo;

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("<title>Servlet FooServlet</title>");
out.println("<h1>FooRemote.echo returned: " + foo.echo("From FooServlet") + "</h1>");

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
7. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

8. Make sure foo.FooRemote.class is in the webapp's classpath. For example, C:\simple-ejb\build\classes directory is included in the webapp's classpath.

9. Build the webapp to produce a simple-web.war with the following content:
10. Make sure the ejb jar is already deployed (in step 5). Start glassfish server and deploy the war file:
set JAVAEE_HOME=C:\glassfish
%JAVAEE_HOME%\bin\asadmin.bat start-domain
C:\simple-web\dist> copy simple-web.war %JAVAEE_HOME%\domains\domain1\autodeploy
Another way to deploy the war is using asadmin command:

C:\simple-web\dist> %JAVAEE_HOME%\bin\asadmin deploy simple-web.war
11. Run it by entering the following url in browser:

Update: Starting from EJB 3.1, EJB classes can be packaged in WAR files. So if the target server supports EJB 3.1, the ejb jar file in this example can be merged into WAR (typically by putting all EJB classes under WEB-INF/classes).


Don said...

Thanks for the example. Very helpful. It turns out that the web.xml file has to be version 2.5 or newer (as it is in your example). Annotations in the servlet are ignored if the web.xml is version 2.4 or older. I originally created my servlet with Eclipse 3.2, which provided a version 2.4 web.xml, and the servlet threw a null pointer exception when it tried to call the EJB.

Anonymous said...

Thanks for this example, it helped me so much. I had had some problemn with EJB anotation, but this example explain clearly how to call the EJB by Servlet.
I'm sorry by my bad English, I'm from Brasil.

Anonymous said...

The first example worked as described in the post. Thanks!

This second example is giving some trouble. Step 8 is about the webapp's classpath. There is no mention of how to properly configure the class into the classpath. After reading about classloaders, I would assume that the war file contents would be avaiable to the webapp. Also, there is no mention of what index.jsp contains. Is this just a courtesy description file of the webapp? i.e. its contents are not important to the functioning of the webapp.

javahowto said...

For this sample, index.jsp is not really needed. It was put there to show where static web content (jsp pages, images, etc) can reside, relative to class files.

A web app classloader is guaranteed to have access to all class files under WEB-INF/classes, and all jar files under WEB-INF/lib. These 2 locations should suffice for most webapps. You can also install common library jars in the appserver to make it available to all deployed apps.

Anton Shaykin said...

Thank you for example. However I wasn't able to run servlet. After I copied .war archive into server\default\deploy directory I got a whole bunch of errors in the server log, so I'll post it here. I put all the contents of \common\lib into the classes folder (I also have foo.FooRemote and foo.FooServlet classes in that folder). So here is the log:
2009-12-17 01:08:07,223 INFO [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/simple-web]] (http- Marking servlet FooServlet as unavailable
2009-12-17 01:08:07,227 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/simple-web].[FooServlet]] (http- Allocate exception for servlet FooServlet
javax.naming.NameNotFoundException: foo.FooRemote not bound
at org.jnp.server.NamingServer.getBinding(NamingServer.java:771)
at org.jnp.server.NamingServer.getBinding(NamingServer.java:779)
at org.jnp.server.NamingServer.getObject(NamingServer.java:785)
at org.jnp.server.NamingServer.lookup(NamingServer.java:443)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:726)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at org.jnp.interfaces.NamingContext.resolveLink(NamingContext.java:1346)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:817)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686)
at org.jboss.ejb3.JndiUtil.lookup(JndiUtil.java:44)
at org.jboss.injection.JndiPropertyInjector.lookup(JndiPropertyInjector.java:75)
at org.jboss.injection.JndiPropertyInjector.inject(JndiPropertyInjector.java:99)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.processInjectors(TomcatInjectionContainer.java:366)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:271)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:265)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:256)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1006)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:777)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:129)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)

javahowto said...

Have you already deployed the ejb jar? It should be deployed before the war, since the web app references the target ejb.

Anton Shaykin said...

ejb-har is also located in server\default\deploy folder. So I think it should be deployed automatically.

javahowto said...

Can you try deploying to jboss all config? The default config may not support ejb 3.0 autodeploy, at least I had this problem in the past.

raja said...

to be used

Anonymous said...

what would be required if the two parts were to be located on separate servers?

Anonymous said...

thanks for the example. i have a question, i have only one web project consists of servlet, bean, interface, entity, persistence and web.xml classes. i need to make jar before run it?

javahowto said...

Depends on your appserver, you may not need to package war file. The purpose of a WAR packaging is to provide a portable means to deploy all appservers. Some servers have a directory-based (no packaging needed) deployment. Java IDEs either do directory-based deploy, or package your project behind the scene.

Anonymous said...

thank u very much. i had an exception but i solved it, thanks again

Anonymous said...

You are the best!! Thank you a lot! I was a desperate ejb student!

Arka said...

@ first comment by don: Yes the web app version should be 2.5 or greater.

But even with this version I am getting null pointer exception i.e. it's not able to inject ejb.

Surprisingly it was working fine in the begining, but suddenly it started giving me this error.

As far as deploying the EJB/Jar first, is concerned, I have the war and jar both in an EAR. is there anyway I can control the sequence of deployment?

my main confusion is, how can it work in the begining and not afterwards?

Anna said...

Great and Useful Article.

Online Java Course

Java Online Training

Java Course Online

J2EE training

online J2EE training

Best Recommended books for Spring framework

Java Interview Questions

Java Training Institutes in Chennai

Java Training in Chennai

J2EE Training in Chennai

java j2ee training institutes in chennai

eMexoT said...

Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

Internet Of Things training in electronic city