Articles
Developer: J2EE
Using Oracle TopLink with the Spring Frameworkby Lonneke Dikmans, Oracle Fusion Middleware Regional Director
Build a sample application using Spring 2.0 and Oracle TopLink with Oracle JDeveloper 10g, step by step. Updated May 2007 Spring, a popular framework for developing lightweight J2EE applications, uses Aspect Oriented Programming (AOP) and dependency injection at its core. It supports various frameworks, including object-relational mapping (ORM) tools such as the open-source Oracle TopLink and JBoss Hibernate. In this article, you will learn how to use the Spring Framework's support for TopLink. ( Click here to visit the Oracle + Spring page on OTN.) Spring offers several benefits:
Using Spring doesn’t change the basics of the underlying ORM tool. This means that you can continue to design and code applications the way you’re used to. Here you'll build an application using Spring 2.0 and TopLink with Oracle JDeveloper 10.1.3.2. First, you’ll set up the workspace and then look at a sample application. After that, you’ll examine the data access code as well as the Spring configuration. After testing the code, you’ll deploy the application to the Oracle Containers for Java (OC4J) runtime. Set Up Your WorkspaceThe sample application uses JDeveloper 10.1.3 with Spring 2.0.When creating your own application, you’ll base it on the Web application template with TopLink, EJB, and JavaServer Faces (JSF). For this case, however, start by downloading and extracting the sample application and importing it into JDeveloper (see Figure 1):
Once you import the application, you must add libraries to use the Spring framework and to test the application. Because you used the Web application template, the libraries for TopLink and JSF have already been added to the Model and ViewController projects. Table 1 shows the libraries you need to add. Table 1. Libraries needed for each project.
Start by adding libraries for the Model project:
The Model project now looks like Figure 2.
Next, add libraries to the TestModel project:
The TestModel project now looks like Figure 3.
Finally, add the necessary libraries to the ViewController project:
The ViewController project should now look like Figure 4:
The Sample ApplicationNow that you’ve set up the workspace, you can focus on the HockeyCoachAssistant application. This simple program keeps track of teams in a field hockey competition; users can add, delete, or edit teams from the competition. The user interface is a Web application that consists of java server pages (jsp) with ADF Faces components. The Start page is teams.jsp (see Figure 5).
The application consists of four layers: model, data access (DAO), service, and view (see Figure 6). This article focuses on the DAO layer, which is where the Spring support for TopLink is used.
Installing the ApplicationTo show how TopLink support is used in the HockeyCoachAssistant application, you must create a connection to the database and create the schema and tables.
The Data Access LayerSpring support for data access includes two parts:
This is true for all of Spring’s data access support, including TopLink, Hibernate, JDBC, IBATIS, and JDO. There are two ways to use the TopLinkTemplate class: You can inject it in every DAO class in the application using the Application Context, or you can extend a support class. Our example extends the TopLinkDaoSupport class. This results in the following structure for the data access component (Figure 11):
The TopLinkCompetitionDao (see Figure 11) implements the CompetitionDao interface, which is exposed to the service layer. This way, the data access implementation details are hidden from the rest of the application.
Retrieving Data. To populate the first page, you must first retrieve all the teams in the database, using the findAllTeams method. If you implement this without Spring (for example, in a stateless session bean or a plain Java class), the code would look like the code in Listing 1: Listing 1. Retrieve data without Spring. Session management is in the code.
public List<Team> findAllTeams() {
List<Team> result = null;
Session session = getSessionFactory().acquireSession();
result = (List<Team>)session.executeQuery("findAllTeam", Team.class);
session.release();
return result;
}
Because the Spring template handles resource management, all you have to implement in the TopLinkCompetitionDao class is the call to executeQuery. Acquiring and releasing the session is taken care of. (See Listing 2) Listing 2. Retrieve data with Spring. Resources are managed by Spring.
public List<Team> findAllTeams() {
return (List<Team>)getTopLinkTemplate().execute(
new TopLinkCallback(){
public Object doInTopLink(Session session) {
return session.executeQuery("findAllTeam", Team.class);
}
});
}
Of course, you can add parameters or use another named query that’s defined in the TopLink map. Because you need to fetch all the teams, you can use the template’s convenience method (see Listing 3). Listing 3. Alternative with Spring using convenience methods.
public List<team> findAllTeams() {
return getTopLinkTemplate().readAll(Team.class);
}
The same logic applies to findAllClubs (see Listing 4): Listing 4. FindAllClubs() with Spring.
public List<Club> findAllClubs(){
return getTopLinkTemplate().readAll(Club.class);
}
Next,
Inserting Data. Because users can add new teams to a club, you must implement saveTeam(Team). Without Spring, your code would look like Listing 5: Listing 5. Save team without Spring.
public void saveTeam(Team entity) {
UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
uow.registerNewObject(entity);
uow.commit();
}
As you can see, the process of acquiring resources and managing transactions is embedded in the code. With Spring, transactions are declared in the application context using AOP. The method now looks like Listing 6: Listing 6. Save Team with Spring.
public void saveTeam(Team team) {
getTopLinkTemplate().merge(team);
}
You can use several variations: deepMerge, shallowMerge, and mergeWithReferences. Which one you use depends on what you want to happen with associated objects. These methods work the same as the corresponding methods on the UnitOfWork API. Updating Data. Users can update teams by adding or changing a remark. Without Spring, the code looks like Listing 7: Listing 7. Code to update the team without Spring.
public void updateTeam(Team entity) {
UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
Object workingCopy = uow.readObject(entity);
if (workingCopy == null){
throw new RuntimeException("Couldn?t find team to update");
}
uow.shallowMergeClone(entity)
uow.commit();
}
Using Spring, the implementation looks like Listing 8. Listing 8. Update team with Spring.
public void updateTeam(Team team) {
getTopLinkTemplate().shallowMerge(team);
}
It’s important that the entity that’s merged is registered with the session before you change it, otherwise the call to the method in Listing 8 will throw an exception. That’s why, when a user selects a team for editing, it’s read by calling the loadTeam(…) as is shown in Listing 9. Listing 9. Load the team to register it with the session.
public Team loadTeam(Long teamId) {
Team t = null;
try {
t = (Team)getTopLinkTemplate().readAndCopy(Team.class, teamId);
} catch (ObjectRetrievalFailureException e) {
if (logger.isDebugEnabled()) {
logger.debug("team with id: " + teamId + "is not found");
}
}
return t;
}
Deleting Data. Because teams can also be deleted, you must implement deleteTeam(Team). If we don’t use Spring, the code would look like Listing 10. Listing 10. Delete a team without Spring.
public void deleteTeam(Team entity) {
UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
Object workingCopy = uow.readObject(entity);
if (workingCopy == null){
throw new RuntimeException("Could not find team to delete");
}
uow.deleteObject(workingCopy);
uow.commit();
}
In Listing 11, you can see what the code looks like using the TopLinkTemplate: Listing 11. Delete the team with the TopLinkTemplate.
public void deleteTeam(Team team) {
getTopLinkTemplate().delete(team);
}
Since all the tests succeed, you’re done implementing the TopLinkCompetitionDao class. Now, let’s take a closer look at the implementation of the CompetitionDaoTopLinkTest class.
Configuring Resources and Transactions. Once you've removed all the resource management and transaction management code from the DAO class, you must configure it in the Spring configuration file. This is done in the file ApplicationContext.xml.
Testing the CodeNow it’s time to examine the test code. Figure 16 shows the class model of the tests. There’s a test method for every method in the TopLinkCompetitionDao class. The tests are run against an Oracle database. In this example, I used DbUnit to initialize the data from an XML file. JUnit is used to write test cases and assert the results. The class AbstractTransactionalDataSourceSpringContextTests makes sure the tests run in a transaction and are rolled back after they complete. In these tests, I used the jdbcTemplate to retrieve data and count rows.
For the tests, Spring is configured differently. AbstractDaoTest defines where the spring configuration is located in the getConfigLocations() method. It points to the file test-config.xml. The most important differences from the applicationContext are:
Using this approach, the test code becomes very simple. Listing 18 shows an example of the testGetAllTeams(): Listing 18. Example of a test method in CompetitionDaoTopLinkTest.
/**
* Tests the method that gets all teams that belong to a competition.
* Fields that are fetched include the club and the name
*/
public void testGetAllTeams(){
List<Team> teams = competitionDao.findAllTeams();
assertNotNull(teams);
assertEquals(2, teams.size());
Team teamOne = teams.get(0);
assertNotNull(teamOne.getClub());
assertEquals("Kampong", teamOne.getClub().getName());
assertNotNull(teamOne.getName());
}
Several convenience methods are available in the AbstractXXXSpringContextTests classes. These methods, which are used in several of the tests, are described in Table 2. Table 2. Methods used in the test class.
Play around with the code to see what happens if you comment out the setComplete() and the endTransaction() in the the testSaveTeam or testDeleteTeam method. The tests should fail because the jdbcTemplate doesn’t use the TopLink session and the transaction is still running. Deploying the ApplicationNow that you’ve tested the application, you can deploy it using deployment profiles, ant, or maven (See Figure 17). For this case, use deployment profiles.
What’s NextSpring Framework 2.0 supports TopLink, Hibernate, JDO and other data access frameworks as well as the new kid on the block: Java Persistence API (JPA). It offers comprehensive support for the Java Persistence API the same way it supports TopLink and Hibernate. It also includes the open-source TopLink Essentials, the reference implementation of JPA. ConclusionIn this article, you've learned how to use Spring and TopLink in JDeveloper. Setting up the workspace is easy and you’ll appreciate being able to design and code TopLink applications the way you’re used to. Resource and transaction management can be defined declaratively in the Spring configuration, making for a clean separation of concerns. Apart from making the code easier to maintain and test, this makes migrating to EJB 3.0 and JPA easier. Lonneke Dikmans, an Oracle Fusion Middleware Regional Director and Oracle ACE, is managing partner at Approach Alliance in The Netherlands. She is an architect, specializing in SOA and agile development. Lonneke has been using JDeveloper since 2000, and has experience designing, developing, and deploying Java applications. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||