In this lab, you will write a program that uses EJB declarative transactions.
In this part, you will import an Eclipse project that contains entities, EJBs and a Web application to save you typing.
Your first job is to import the completed Eclipse project. Follow these steps:
From the Eclipse menu, choose File - Import to start the wizard.
On the first wizard page, select General - Existing Projects into Workspace, then press Next.
On the next page, for the Select Archive file, press the Browse button and navigate to {Lab Installation Directory}/starters/lab11 and select the lab11.zip file. If your computer has the standard lab setup on Windows XP, the path to the file is:
C:\jeeclass\starters\lab11\lab11.zip
On Windows Vista or later:
C:\Users\username\jeeclass\starters\lab11\lab11.zip
Press Next.
On the next wizard page, press Finish.
Examine the project, looking in the Java Resources:src/com.oaktreeair.ffprogram, Java Resources:src/com.oaktreeair.ffprogram.session and servlets packages. Figure 1 summarizes the application:

We have provided you will all of the interfaces; you will write the implementation classes. In addition, we have provided you with the Flier.java and Award.java classes, but you will need to configure them as entities.
Before you can run the Web application, you need to create the database tables and populate them with sample data. We have provided you with an SQL script for this purpose; follow these steps to run the script:
Find the H2 administrative console's Web page. If you can't find it, restart H2 as you did in earlier labs.
In Eclipse, in the Lab11Web/WebContent/WEB-INF folder, open the createfliers.sql script and examine it and ensure that you understand it.
Press Ctrl+A to highlight the entire file, then press Ctrl+C to copy to the clipboard.
In the H2 admin console, click on the entry field, then press Ctrl+V to paste the script.
Press the Run (Ctrl+Enter) button to execute the script.
In this part, you will use JPA annotations to configure the Flier and Award entities.
Start by configuring the Flier entity:
Open Flier.java into the editor and familiarize yourself with it. Examining Figure 1 above, note that it has a bidrectional, one-to-many relationship with Award.
Start by adding the required @Entity and @Id annotations. You should also use an auto-generated key using the AUTO strategy.
Annotate the awards field as a OneToMany relationship. This entity, Flier, will act as the inverse, so be sure to use the mappedBy attribute. For now, you can ignore any error on the OneToMany annotation complaining about "invalid mapping type".
Edit persistence.xml, and in the Source view, immediately following the jta-data-source element, configure the entity class:
<class>com.oaktreeair.ffprogram.Flier</class>
Next, configure the Award entity:
Open Award.java into the editor and familiarize yourself with it. Examining Figure 1 above, note that it has a bidrectional, many-to-one relationship with Flier.
Start by adding the required @Entity and @Id annotations. You should also use an auto-generated key using the AUTO strategy.
Next, annotate the flier field as ManyToOne and specify the join-column that the database table uses:
@ManyToOne
@JoinColumn(name="flierID")
Add the class to persistence.xml. Save everything - you should have no errors.
In this part, you will write EJBs that will be accessed from the Web tier. We have provided you with the EJB interfaces: your job is to write the implementations.
Create a new class named FlierManagerBean in the com.oaktreeair.ffprogram.session package that implements the FlierManager local interface.
Complete the EJB:
Annotate the class so that it's a stateless session EJB.
Define a field of type EntityManager and inject a reference into it. Be sure to specify the unit name.
Annotate the findFlierById method so that it's transactional, using a propagation attribute of SUPPORTS. That way, if your program calls this method without a transaction, it will run with no transaction - that's appropriate for a method that doesn't modify any entities.
Annotate the updateFlier method so that it's transactional, using a propagation attribute of REQUIRED. That way, if your program calls this method without a transaction, the container will start a new transaction - that's appropriate for a method that modifies entities.
Implement the findFlierByID method. Issue a JPA query that retrieves the Flier with the given flierID and returns it.
Implement the updateFlier method. Call the EntityManager's merge method, passing the given Flier reference. The merge method ensures that the entity in memory and the database table are in sync.
Create a new class named AwardManagerBean in the com.oaktreeair.ffprogram.session package that implements the AwardManager interface.
Complete the EJB:
Annotate the class so that it's a stateless session EJB.
Define a field of type EntityManager and inject a reference into it. Be sure to specify the unit name.
Annotate the insertAward method so that it's transactional with a propagation attribute of MANDATORY. This method is designed to only be called from another EJB, FrequentFlierProgramBean, that starts a transaction (you will write that EJB in a moment). So if called from that EJB, it will propagate the transaction, but if called without any transaction in place, the container will throw an exception. This guarantees that this method is only called via the FrequentFlierProgramBean EJB.
Annotate the updateAward method so that it's transactional, using a propagation attribute of REQUIRED. That way, if your program calls this method without a transaction, the container will start a new transaction - that's appropriate for a method that modifies entities.
Implement the insertAward method (this code assumes you named your EntityManager field em:
award.setFlier(flier);
em.persist(award);
Collection<Award> awards = flier.getAwards();
awards.add(award);
em.merge(flier);
Implement the updateAward method:
em.merge(award);
Next, write the FrequentFlierProgramBean EJB class:
Create a new class named FrequentFlierProgramBean in the com.oaktreeair.ffprogram.session package that implements the FrequentFlierProgram interface.
Annotate the class so that it's a stateless session EJB.
Annotate the class so all of its methods are transactional with REQUIRED propagation.
Define fields for the AwardManager and the FlierManager EJBs and use @EJB to inject a reference to those EJBs.
Implement the redeemMiles method (assuming that you named your AwardManager reference am and your FlierManager reference fm):
boolean retVal = false;
Flier f = fm.findFlierByID((long)flierID);
int balance = f.getMileageBalance();
if (balance - miles >= 0)
{
// create a new award and add
// to flier's award collection
Award award = new Award();
award.setMilesRequired(miles);
award.setDescription(awardDescription);
am.insertAward(f, award);
balance -= miles;
f.setMileageBalance(balance);
retVal = true;
}
return retVal;
In this part, you will run a provided servlet that redeems miles for an Award on a Flier's account.
Open the Java Resources: src/servlets/AwardServlet.java servlet and ensure that you understand it. Note how it uses dependency injection for a reference to the FrequentFlierProgram bean, then attempts to redeem a mileage award, displaying the results to a simple Web page.
Test the program by right-clicking on AwardServlet.java and choosing Run As - Run on Server. After the server starts, you should see the "before" and "after" of the attempt to redeem miles.