In this lab, you will create a stateful session bean that lets a teacher enter test scores into an application. The teacher will enter scores in batches, and is interested knowing how many scores were in the batch and the average score. The batch information is not terribly important, however, so the application does not save the data persistently. Therefore, you will use a stateful session bean instead of an entity bean to keep track of the batch information.
In a real application, this stateful bean would interface with entities that would save the actual test score data persistently. However, in this lab, for simplicity, the test score records will not be saved in a database.
Here is a UML diagram:

The AddScores interface represents the client's view of the stateful session bean. It defines methods to let the user add a score to the batch, retrieve the count of batched scores, retrieve the average score for the batch and set and retrieve the test name.
The data for each test score consists of the student's name and the test score.
In the same fashion as in earlier labs, create a Dynamic Web Project named Lab05Web. Be sure to generate the Web deployment descriptor.
Right-click on the project, then choose New - Other - EJB - Session Bean (EJB 3.x) and press Next to start the wizard.
On the first wizard page, for the Java package, enter scores.
For the Class name, enter AddScoresBean.
For the State type, select Stateful.
Uncheck the No-interface View box, then put a checkmark next to the Remote box, then, for the remote interface name, change the name to scores.AddScores and press Next.
On the next wizard page, uncheck the Inherited abstract method and Constructors from superclass checkboxes, then press Finish.
In the Project Explorer, expand Java Resources/src/scores -- you should see two entries:
Double-click AddScores to open the business interface into the Java editor. Note how the wizard inserted the @Remote annotation, then within the interface, write the business method definitions as described in the UML diagam in Figure 1.
Press Ctrl+S to save.
Edit AddScoresBean. From the Eclipse menu, choose Source - Override/Implement Methods and select all of the methods from the AddScores interface.
Eclipse writes method stub implementations. For methods that return a value, the stubs return a "placeholder" value of either zero or null.
Now it's time to complete the EJB implementation. Follow these steps:
To save the test scores, you should define a HashMap as a private field:
private HashMap<String, Integer> scores =
new HashMap<String, Integer>();
Use Source - Organize Imports to import java.util.HashMap.
In the addScore method, to add a student name (key) and score, use the HashMaps's put method, for example:
scores.put(name, score);
In the getAverageScore method, to calculate the average score, use the HashMap's keys method to retrieve a list of student names and then use a for loop. Your code might look something like:
double total = 0;
Set<String> keys = scores.keySet();
for(String key : keys)
{
int score = scores.get(key);
total += score;
}
return total/scores.size();
In the getCount method, to determine the count of scores, use the HashMap's size method.
For the test name, define a private String field. Your getTestName method can simply return the String and the setTestName can accept a String and assign it to the field.
For the flushBatch method, first annotate this method with @Remove so that the EJB container knows it's OK to end the session and garbage collect the stateful session EJB.
If you were writing a real-world program, at this point you would write the accumulated scores to a database, but for now, complete the method by simply calling the HashMap's clear method.
Use Source - Organize Imports so that Eclipse imports the required type for the @Remove annotation.
In this part, you will write a servlet that acts as a client to the AddScores stateful session EJB.
Import two fully completed JSPs via the File System from the {Lab Installation directory}/starters/lab05:
In the Project Explorer, right-click on the new project's WebContent folder and choose Import... to start the import wizard.
On the first wizard page, choose General - File system, then press Next.
On the next wizard page, for the From directory, press the Browse button and navigate to the {Lab Installation Directory}/starters/lab05 folder, then press OK. If your computer has the standard lab setup, the proper directory is:
c:\jeeclass\starters\lab05
In the left pane, click on the lab05 to highlight it, then put a checkmark next to index.jsp and addScore.jsp.
Press Finish to complete the import. You should see the imported files in the project's WebContent folder.
Open index.jsp into the editor and note how it defines an HTML form into which the user can enter a "test name". When submitted, the form invokes a servlet named CreateBatchServlet that you will write in a moment.
Open addScore.jsp into the editor and note how it defines an HTML form into which the user can enter a "student name" and a "test score". This form invokes a servlet named AddScoresServlet that you will write in a moment.
Note also how the form has three "submit" buttons:
Next, create the Java class for the CreateBatchServlet. Follow these steps:
In the Project Explorer, right-click on the project and choose New - Servlet to start the wizard.
On the first wizard page, for the Java package enter servlets.
For the Class name, enter CreateBatchServlet, then press Next.
On the next page, note the URL Mapping, which assigns a URL to the servlet, then press Next.
On the next wizard page, uncheck the doPost checbox, then press Finish. Eclipse opens the servlet class into the editor.
Your next job is to complete the CreateBatchServlet.
This servlet will create an instance of the AddScores stateful session EJB you wrote in the last part. Unfortunately, we cannot use dependency injection to retrieve the reference, since the application needs a new AddScores instance every time the user navigates to the index.jsp home page.
So instead of using dependency injection, the servlet will perform a JNDI lookup. The servlet will then store the EJB's reference in the HTTP session, and transfer control to the "Add Scores" page. Follow these steps to complete the servlet:
In the servlet's doGet method, write code to create an initial JNDI context and retrieve a reference to the stateful EJB, thus creating an instance:
Context ctx = new InitialContext();
AddScores batch = (AddScores)ctx.lookup(
"java:global/Lab05Web/AddScoresBean");
Use Source - Organize Imports to import the proper types from the javax.naming package.
Note: Ignore errors regarding unhandled exceptions for the time being.
Retrieve the test name that the user entered into the HTML form and set it into the EJB:
String testName = request.getParameter("testName");
batch.setTestName(testName);
Create an HTTP session, store the EJB reference in it, then transfer to the addScores.jsp:
HttpSession session = request.getSession();
session.setAttribute("batch", batch);
response.sendRedirect("addScore.jsp");
Use Source - Organize Imports to import the proper types.
Highlight all of the lines within the doGet method and use Source - Surround With - Try/catch Block so that Eclipse writes simple exception handling.
Save to compile - you should have no errors.
In the same fashion as in an earlier step, create a new servlet named AddScoreServlet in the servlets package. The new servlet should override only doGet.
This new servlet has several jobs. To get started, write code to respond to the "Add Score" button:
In the servlet's doGet method, first attempt to retrieve the EJB reference from the HTTP session. If it's not there, perhaps because the user skipped the home page, send them back to the home page:
HttpSession session = request.getSession();
AddScores batch = (AddScores)session.getAttribute("batch");
if (batch != null)
{
}
else
response.sendRedirect("index.jsp");
Inside the "if" statement, write a nested "if" to determine which button the user pressed:
String action = request.getParameter("action");
if (action.equals("Add Score"))
{
}
Within the "if", retrieve the data that the user entered and set it into the stateful EJB. Then send the user back to the HTML form so they can enter another score:
String studentName = request.getParameter("studentName");
String score = request.getParameter("score");
batch.addScore(studentName, Integer.parseInt(score));
response.sendRedirect("addScore.jsp");
After the closing brace of the nested "if", write an "else if" to determine if the user pressed the "New Batch" button:
else if (action.equals("New Batch"))
{
}
Within the "else if", retrieve the current EJB's name, then call its flushBatch method. Recall that you annotated flushBatch with @Remove -- when you call this method, the container gets rid of the EJB.
String testName = batch.getTestName();
batch.flushBatch();
Then use JNDI to retrieve another EJB reference, which creates a new stateful EJB. Note that you can copy and paste from the CreateBatchServlet to save typing:
Context ctx = new InitialContext();
batch = (AddScores)ctx.lookup(
"java:global/Lab05Web/AddScoresBean");
Set the new EJB's name to the test name, then store its reference in the HTTP session and send the user back to the addScores.jsp:
batch.setTestName(testName);
session.setAttribute("batch", batch);
response.sendRedirect("addScore.jsp");
Highlight all of the lines within the "else if" block and use Source - Surround With - Try/catch Block.
After the closing brace of the "else if", determine if the user pressed the "Done" button. If so, flush the batch and send the user back to the home page:
else if (action.equals("Done"))
{
batch.flushBatch();
response.sendRedirect("index.jsp");
}
Use Source - Organize Imports as necessary and save to compile. Ensure that you have no errors.
To test your program, right-click on index.jsp and choose Run As - Run on Server. You should be able to create a batch, add scores, flush the batch and return back to the home page.
Remove the project from the server and close all Eclipse windows.