Riddles with EJB 3.1

EJB 3.1 aims to further simplify EJB programming model, introducing a series of new features like no-interface local view, .war file packaging, singleton bean, cron-like schedule-based timer, asynchronous invocation, etc.  Some of them have already been implemented by GlassFish V3.  Ken's blog has more details on many proposed new features in EJB 3.1. Mahesh from GlassFish EJB container team gave a preview of EJB 3.1 container in GlassFish v3 TP2.  In this post, I will share a riddles webapp to showcase the use of certain EJB 3.1 features and how they interact with web-tier components like Servlet, JSP, and JSTL.

1, Download GlassFish V3 Technology Preview 2 (TP2) at GlassFish download page.  See the installation instructions for installation steps, and the Quick Start Guide to get up and running quickly. 

For NetBeans 6.1 users, this can be completely automated with GlassFish V3 plugin (see ludo's blog).  Eclipse plugin for GlassFish V3 TP2 is also available (see Arun's blog).

2. Install EJB container on top of V3 TP2 by running <glassfish_home>/bin/updatetool.  Follow on-screen instructions, and choose to install glassfishv3-ejb from Available Add-ons.

3. Start V3 TP2 by running <glassfish_home>/bin/asadmin start-domain, or from within NetBeans or Eclipse.

4. Create a webapp named riddles.  The exact steps vary depending on IDE, but it simply contains:

The stateless bean class RiddleBean is annotated with @Stateless but implements no interfaces.  All public methods (only getRiddle method in this case) in the bean class and its superclasses are exposed as business methods.  @PostConstruct method is invoked after the bean instance is created and before any business method invocation.  It initializes riddle data in classpath with class.getResourceAsStream().

@Stateless
public class RiddleBean {
public Riddle getRiddle() {
String data = riddleData[rand.nextInt(riddleData.length)];
return new Riddle(data);
}

@PostConstruct
private void postConstruct() {
//read riddle data with getResourceAsStream
}

RiddleServlet acts as the client of RiddleBean EJB, a reference of which is injected into RiddleServlet.  With no-interface local view, the client references EJB with its bean class type.  But the client must still obtain the reference either through injection or lookup, not new operator.

The servlet does not create any response; it merely sets the injected bean reference into application scope so that it is available for JSP pages.  The purpose is to demonstrate the use of @EJB injection.  Alternatively, this servlet can be replaced with a context listener or filter, or totally removed by declaring <ejb-ref> in web.xml.

public class RiddleServlet extends HttpServlet {
@EJB private RiddleBean riddleBean;

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
getServletContext().setAttribute("riddleBean", riddleBean);
getServletContext().getRequestDispatcher("/riddle.jsp";).forward(request, response);
}

riddle.jsp shows how easy it is to invoke EJB methods with JSP expression language (EL) , without using any java code.  The expression ${riddleBean.riddle} has the same effect as calling riddleBean.getRiddle().  The return vaue, a value object of type Riddle, is stored as riddle in page scope.

<c:set var="riddle" value="${riddleBean.riddle}" scope="page" />
... ...
<p><h4>Q: ${riddle.question}</h4></p>
<p><h4>A: ${riddle.answer}</h4></p>

In your project, EJB source files reside in the same place as servlet and other web component classes.  With .war packaging, EJB classes can be packaged under WEB-INF/classes or inside a jar file under WEB-INF/lib, just like any other .war classes.  It's no different than an ordinary .war, with no EJB interfaces (not even local business interface), no ejb-jar.xml, no ejb-jar, and no EAR.  This is the content of the war file after building the project:

WEB-INF/classes/riddle/Riddle.class
WEB-INF/classes/riddle/RiddleBean.class
WEB-INF/classes/riddle/RiddleServlet.class
WEB-INF/web.xml
riddle.jsp 

As for the riddle data file riddles.txt, you can package it inside the .war as WEB-INF/classes/riddles.txt.  Or you can jar it up as riddles.jar and copy riddles.jar to $GLASSFISH_HOME/domains/domain1/lib.  Any jars in this directory will be made available to all apps in domain1.  In GlassFish V2, I used to directly copy classes and resources to domain1/lib/classes without the wrapper jar, but this doesn't seem to be supported yet.  riddles.txt must follow certain format to be parsed properly (A: Q: %):

FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS:
A: To be or not to be.
Q: What is the square root of 4b\^2?
%

In my Ubuntu machine, I just use /usr/share/games/fortunes/riddles file.  riddles.war with sample riddles can be downloaded here.

5. Deploy riddles.war using autodeploy or asadmin deploy:

cp riddles.war $GLASSFISH_HOME/domains/domain1/autodeployor 
$GLASSFISH_HOME/bin/asadmin deploy riddles.war

Optionally, verify that the .war is deployed with

 $GLASSFISH_HOME/bin/asadmin list-components

6. Play riddles with EJB 3.1 at http://localhost:8080/riddles/

Riddles with EJB 3.1 snapshot

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Cheng Fang

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today