In this lab, you will write a program that uses Java Persistence to persist a business object model.
In this part, you will write a POJO entity that can be used with Java Persistence and uses automatically generated primary keys.
Ensure that the H2 database and GUI are running. See the last lab for instructions on how to start them if they are not running.
As before, create a Dynamic Web project named Lab08Web. Be sure to create the Web deployment descriptor.
Next, configure the project to support JPA:
In the Project Explorer, right-click on the project and choose Properties, then click the Project Facets entry.
Put a checkmark in the JPA entry, then set the version to 2.0.
Near the bottom, click the Further configuration required/available link to start the wizard.
On the first wizard page, in the Platform section, select EclipseLink 2.4.x/2.5.x.
In the JPA Implementation section, select Disable Library Configuration, then press OK twice.
Look in the project's Java Resources folder. Note that it has a src folder with an embedded META-INF folder. You will edit the persistence.xml file in this folder in a later step.
Next, create an entity using an Eclipse wizard:
Right-click on the src folder and choose New - JPA Entity to start the wizard.
On the first wizard page, for the Java package, enter part1.
For the Class name, enter Auto and then press Next.
On the next page, in the Table Name section, uncheck the Use default box and for the Table Name, enter Autos.
In the Entry Fields section, press the Add button and for the Type, select int and for the Name, enter vin and press OK. Then put a checkmark in the Key column for this newly added field.
Repeat the Add to define three more fields, neither of which should be part of the Key:
Type Name
---- ----
double price
double dutyRate
java.lang.String model
Press Finish. Eclipse creates the entity class and opens it into the editor.
Note the following:
You need one more annotation to get this to work. Immediately before the vin field, write a @GeneratedValue annotation using the AUTO strategy.
You will need to write imports for the @GeneratedValue annotation and the GenerationType enumeration.
Next, you need to edit the persistence.xml file that configures Java Persistence (the create-JPA-project wizard created the file):
In the Project Explorer, expand the META-INF folder and double-click on persistence.xml to open it into the editor.
At the bottom of the editor, click the General tab, then in the General section at the top, change the Name to lab08.
At the bottom of the editor, click the Connection tab. For the Transaction Type, select JTA.
Then for the JTA data source, enter ExampleDS. This is the data source you configured to reference your H2 database.
Click the Properties tab at the bottom of the editor window.
Use the Add button to define the following properties:
Name
----
openjpa.jdbc.SynchronizeMappings
Value
------
buildSchema(schemaAction='dropDB,add')
This property tells the OpenJPA provider to recreate the database every time the program starts. Note that this is OK for development and testing, but NEVER use this in production, as you will lose all existing data.
Click the Source tab at the bottom of the window and examine the raw XML and ensure that you understand it.
Be sure to save the file before continuing.
As in earlier labs, create a stateless session EJB according to these specifications:
Java package name: session
Class name: AutoSessionBean
No-interface View: unchecked
Local interface name: session.ManageAutos
Complete the session/ManageAutos.java interface by writing the following method definitions:
public Auto insertAuto(String model, double price, double dutyRate);
public Auto queryAuto(int vin);
Complete the session EJB, AutoSessionBean.java:
Use dependency injection to obtain a reference to the persistence manager:
@PersistenceContext(unitName="lab08")
private EntityManager entityManager;
Recall that you wrote a persistence.xml file in the JPA project that configured the persistence unit name to be lab08.
Use Source - Override/Implement Methods menu so that Eclipse generates empty implementation methods for insertAuto and queryAuto.
Complete the insertAuto method:
Note that since this code is in a session EJB, the container, by default, runs each method invocation within a transaction. Thus, you don't need to begin and commit a transaction manually.
Complete the queryAuto method:
Query q = entityManager.createQuery(
"SELECT a FROM Auto a WHERE a.vin = :vin");
q.setParameter("vin", vin);
Auto a = (Auto)q.getSingleResult();
return a;
You will need to import javax.persistence.Query.
Save all files and ensure that you have no errors.
As in earlier labs, right-click on the Web project's Java Resources/src folder and create a new servlet named AutoServlet in the servlets package. The new servlet should override only doGet.
Complete the servlet:
Define a private field of type ManageAutos (the EJB interface) and use dependency injection to initialize it.
In the doGet method, set the content type and retrieve a PrintWriter:
response.setContentType("text/html");
PrintWriter out = response.getWriter();
Call the session EJB's insertAuto method, passing the following parameters:
model: "Ford"
price: 25000
dutyRate: 0
Store the returned Auto reference in a local variable named a1.
Call the session EJB's insertAuto method again, passing the following parameters:
model: "Chevrolet"
price: 28000
dutyRate: 0
Store the returned Auto reference in another local variable named a2.
Call the session EJB's queryAuto method twice, retrieving two Auto entities, storing their references in variables named a3 and a4. You will need to specify the vin numbers returned from the insertAuto method.
Then display each of the autos' properties to the Web page using code like:
out.println("<p>Vin: " +
a3.getVin() + "</p>");
out.println("<p>Price: " +
a3.getPrice() + "</p>");
out.println("<p>Model: " +
a3.getModel() + "</p>");
out.println("<p>Duty rate: " +
a3.getDutyRate() + "</p>");
In the Project Explorer, right-click on the servlet and choose Run As - Run on Server to run the servlet. You should see the automobile information in the resulting Web page.
Note how the vin values were assigned by the system as auto-generated values.
Note: If you find that you made a mistake with the entity, you should stop the server. Then restart it and test again. Since we are using a top-down approach, this will cause the server to drop and recreate the database tables.
In this part, you will demonstrate using inheritance in the object model with a persistent backing store. Your code will demonstrate both inheritance and polymorphism.
You will write three classes (two new ones) that implement a class hierarchy using inheritance. The application is for a business that purchases automobiles from domestic and foreign manufacturers. The business must pay a duty tax on each foreign car that is imported -- the duty calculation depends on the car's origin. Here is the UML class diagram for the system:

Here are the business rules:
Make the following changes to Auto:
Decorate the class with the @Inheritance annotation using the "Table per Subclass" strategy (i.e. JOINED).
Write a public payDuty method that accepts no arguments and returns a double. For generic Auto, the returned duty should be zero. The subclasses will override this method.
Next, create a subclass entity using an Eclipse wizard:
Right-click on the src folder and choose New - JPA Entity to start the wizard.
On the first wizard page, for the Java package, enter part3.
For the Class name, enter EuropeanAuto.
For the Superclass, press the Browse button and start typing Auto, then select Auto - part1 and press OK.
In the Inheritance section, put a checkmark next to the Inheritance box, then select JOINED from the list. Press Next.
On the next page, in the Entry Fields section, press the Add button and for the Type, select double and for the Name, enter euMembershipDiscount and press OK. Press Finish. Eclipse creates the entity class and opens it into the editor.
This class will inherit its primary key from the Auto superclass, so you should not specify a key field here.
Use the Source - Override/Implement Methods menu so that Eclipse writes a stubbed-out overriden payDuty method.
Implement this method using the business rule defined above at the beginning of this part. Note that to perform the duty calculation, you will need to call the getDutyRate and getPrice methods from the superclass:
double dutyRate = getDutyRate();
double price = getPrice();
Repeat the above step to create another entity subclass of Auto named JapaneseAuto.
This new entity should define a single field of type String named portOfDeparture
In the JapaneseAuto entity, override the payDuty method and implement the business rule described at the beginning of this part.
For the portOfDeparture portion of the calculation, you can use the String class's equals method on the portOfDeparture field to determine if the JapaneseAuto was shipped from Yokohama or not:
boolean f = portOfDeparture.equals("Yokohama");
Now it's time to update the session EJB to reflect the new entity classes:
Edit the ManageAutos.java interface and add the following new methods:
public EuropeanAuto insertEuropeanAuto(String model, double price,
double dutyRate, double euMembershipDiscount);
public JapaneseAuto insertJapaneseAuto(String model, double price,
double dutyRate, String portOfDeparture);
public double calculateTotalDuty();
Edit AutoSessionBean.java and use Source - Override/Implement Methods to write skeleton implementations for the three new methods.
Complete the insertEuropeanAuto method so that it creates a EuropeanAuto entity and intializes its properties using the values passed as parameters. Remember that you don't need to initialize the vin property since it's auto-generated.
Be sure to persist the new EuropeanAuto entity and return its generated reference.
Repeat the above step to complete the insertJapaneseAuto method so it creates, intializes and persists a JapaneseAuto and returns the object's reference.
Complete the calculateTotalDuty method so that it queries all Autos (generic) and then loops through the returned collection and calls the payDuty method on each Auto to accumulate the totalDuty for all of the Autos. We will cover queries in more detail later, but for now, your code might look something like:
public double calculateTotalDuty()
{
Query q = entityManager.createQuery(
"SELECT a FROM Auto a");
double totalDuty = 0;
List<Auto> inventory = q.getResultList();
for(Auto a : inventory)
totalDuty += a.payDuty();
return totalDuty;
}
You will need to import java.util.List.
This code uses polymorphism to treat all types of Auto the same. Note that if we were to later add another kind of auto, say an Australian model, the calculateTotalDuty method would still work as is.
Next, edit AutoServlet.java and update it to reflect the changes you just made:
In the doGet method, after the existing code, call the session EJB's insertEuropeanAuto and insertJapaneseAuto methods to create two more Autos:
Object Model Price Duty Rate
------ ----- ----- ---------
EuropeanAuto object BMW 35000 5%
JapaneseAuto object Honda 30000 7%
The EuropeanAuto object should have an euMembershipDiscount value of 2%.
The JapaneseAuto object was shipped from Yokohama.
Call the session EJB's calculateTotalDuty method and display the total duty to the Web page.
Run the AutoServlet on the server. You should see the total duty - if you used the values suggested earlier, the total should be 4050.
Now let's examine the database. Follow these steps:
Find the Web page containing the H2 administrative console GUI.
In the GUI's toolbar, click the icon for "refresh" - this icon is should be immediately to the left of the "Auto commit" checkbox.
In the left-hand navigation pane, you should see entries for your Autos, EuropeanAuto and JapaneseAuto tables, as well as a "sequence" table that OpenJPA created to hold generated primary keys.
In the GUI, there's a multi-line entry field into which you can enter SQL commands. Enter the following, the press the Run (Ctrl+Enter) toolbar button to display the Auto table:
SELECT * FROM autos
Note how the AUTOS table contains the common information for all superclass and subclass objects.
To display the EuropeanAuto data, press Clear, then enter the following and then press Run (Ctrl+Enter):
SELECT * FROM europeanauto
Note how this table contains the "delta" of information that makes a EuropeanAuto different from a generic Auto. That's a result of you choosing the JOINED inheritance strategy.
Note also that the VIN column acts as a foreign key into the AUTOS table so that the persistence manager can perform a JOIN to gather all of the information for a EuropeanAuto.
Run the following command to display the JapaneseAuto data:
SELECT * FROM japaneseauto
Note how this table contains the "delta" of information that makes a JapaneseAuto different from a generic Auto.
Remove all projects from the server to undeploy them, then stop the server.