390 likes | 509 Views
Raghu Kodali Consulting Product Manager & SOA Evangelist Oracle Application Server. Can EJB 3.0 make developers more productive ?. What we all heard about EJB 3 ?. Simplify development EJB = Plain Old Java Object (POJO) Use metadata annotations Reduce number of artifacts
E N D
Raghu KodaliConsulting Product Manager & SOA Evangelist Oracle Application Server
What we all heard about EJB 3 ? • Simplify development • EJB = Plain Old Java Object (POJO) • Use metadata annotations • Reduce number of artifacts • Attract broad range of developers • Standardize persistence API • O-R mapping similar to TopLink, Hibernate, .. • EntityManager API for CRUD operations
What is this talk all about ? • I wanted to check the truth behind EJB 3 simplicity hype • What did I learn ? • What are my findings/results ? • Conclusion(s)
Approach taken • Find a sample EJB 2.1 application that is available in public domain • Selected RosterApp application from J2EE 1.4 tutorial(s)(http://java.sun.com/j2ee/1.4/docs/tutorial/doc/CMP2.html#wp79745) • Migrated the application to EJB 3.0 architecture
What is RosterApp Application? • Maintains the team rosters for players in sports leagues
Approach taken for EJB 3 RosterApp • Bottom-up approach to migrate EJB 2.1 RosterApp • Entity Beans • Data Transfer Objects (DTO’s) • Session bean/façade • Utility and client classes
EJB 3.0 - POJO Entities • Concrete classes (no longer abstract) • No required interfaces • Support new() • getter/setter methods • can contain logic (validation, etc.) • No exposure of instance variables outside bean class • Collection interfaces used for relationships • Usable outside the EJB container
RosterApp - Entities • Roster App has three entities • LeagueBean • TeamBean • PlayerBean • Reverse engineered the Roster App database schema as EJB 3 POJO’s, instead of migrating EJB 2.1 entity beans
Results of Reverse Engineering • POJO’s with default set of EJB 3 annotations • Many-to-Many annotation had to added manually @ManyToMany(cascade=PERSIST,fetch=LAZY) @AssociationTable(table=@Table(name="TEAM_PLAYER"), joinColumns=@JoinColumn(name="TEAM_ID", referencedColumnName="ID"), inverseJoinColumns=@JoinColumn(name="PLAYER_ID", referencedColumnName="ID") )
Example: EJB 3.0 LeagueBean @Entity @Table(name="LEAGUE", schema="CMPROSTER") public class League implements Serializable { public League(String id, String name, String sport) { setId(id); setName(name); setSport(sport); } @Id @Column(name = "ID", primaryKey = true, nullable = false) public String getId() { return id; } ...
D E M O N S T R A T I O N EJB 3.0 Entities
EJB 3.0 - EntityManager • EntityManager serves as untyped “home” • Factory for Query objects • Utilize EJBQL, Expressions, SQL • Queries defined dynamically or stored within an Entity
Next Step – Migrate EJBQL from finder methods in EJB 2.1 • Defined @NamedQueries annotations on PlayerBean • Remaining migration was for ejbSelect() methods in EJB 2.1 – migrated them as dynamic queries in façade • This pretty much covered much of O-R part
Next Step – Migrate EJBQL from finder methods in EJB 2.1 @NamedQueries ({ @NamedQuery(name="findAll",queryString="SELECT OBJECT (p)FROM Player p"), @NamedQuery(name="findByCity",queryString="SELECT DISTINCT OBJECT(p) FROM Player p, in (p.teams) as t where t.city = :city"), @NamedQuery(name="findByHigherSalary",queryString="SELECT DISTINCT OBJECT(p1)FROM Player p1, Player p2 WHERE p1.salary > p2.salary AND p2.name = :name "), …. })
Next Step – Migrating Team POJO add and remove methods public void dropPlayer(Player player) { Debug.print("TeamBean dropPlayer"); try { Collection players = getPlayers(); players.remove(player); } catch (Exception ex) { throw new EJBException(ex.getMessage()); } } public void dropPlayer(Player player) { Debug.print("TeamBean dropPlayer"); getPlayers().remove(player); }
EJB 3.0 - EntityManager • EntityManager serves as untyped “home” • Provides lifecycle operations • persist() • remove() • merge() • flush(), refresh(), etc. • Attach and Detach objects • Merge back the changes
Next Step – Migration DTO’s • DTO’s are lightweight objects used in EJB 2.1 for transferring data to clients • EJB 3 architecture is based POJO’s, which are lightweight objects • We can transfer these POJO’s directly without having to use DTO’s
Next Step – Migration DTO’s • For EJB 3 version of RosterApp, there are no DTO’s • I had to make sure that Session Façade, is receiving the right POJO classes • Make sure POJO’s are serialiazable • Get rid of extra methods that were doing copy of data to DTO’s and viceversa.
Next Step – Migrating Session Bean/facade • Remove/Delete home interface • Change remote interface to make it a business interface (POJI) • In EJB 3.0, you no longer require to use EJBObject or EJBLocalObject • Add @Remote for business interface • Add @Stateless for the bean class
Next Step – Migrating Session Bean/facade @Stateless public class RosterBean implements Roster { public void createPlayer(Player details) { Debug.print("RosterBean createPlayer"); em.persist(details); } } @Remote public interface Roster { public void createPlayer(Player details) throws RemoteException; }
Next Step – Migrating Session Bean/facade • Big chunk of migration exercise is making use of EntityManager API’s for POJO interaction • Creating NamedQueries for ejbSelect methods • Make sure the business methods are interacting with POJO’s directly instead of DTO’s
Next Step – Migrating Session Bean/facade public List getTeamsOfLeague(String leagueId) { Debug.print("RosterBean getTeamsOfLeague"); ArrayList detailsList = new ArrayList(); Collection teams = null; try { LocalLeague league = leagueHome.findByPrimaryKey(leagueId); teams = league.getTeams(); } catch (Exception ex) { throw new EJBException(ex.getMessage()); } Iterator i = teams.iterator(); while (i.hasNext()) { LocalTeam team = (LocalTeam) i.next(); TeamDetails details = new TeamDetails(team.getTeamId(), team.getName(), team.getCity()); detailsList.add(details); } return detailsList;
Next Step – Migrating Session Bean/facade public List getTeamsOfLeague(String leagueId) { Debug.print("RosterBean getTeamsOfLeague"); League l = (League)getEntityManager(). find("League", leagueId); return l.getTeamList(); }
EJB 3 – Client View • Client view • Dependency Injection • Lookup mechanism
Next Step – Client Migration • Main difference is the lookup code • Use POJO’s instead of DTO’s
Next Step – Client Migration Context initial = new InitialContext(); Object objref = initial.lookup("java:comp/env/ejb/SimpleRoster"); RosterHome home = RosterHome) PortableRemoteObject.narrow(objref,RosterHome.class);Roster myRoster = home.create();insertInfo(myRoster); Context initial = getInitialContext(); Roster myRoster = (Roster)initial.lookup("java:comp/env/ejb/SimpleRoster");insertInfo(myRoster);
D E M O N S T R A T I O N Run RosterApp
So what are the end results ? • Compare # of lines of Java Code • Compare # of lines of XML in deployment descriptors • Compare # of Java files • Compare # of XML files
Conclusion(s) • Big thumbs up on ease of use • POJO architecture is the right way to go, as it has been proven by frameworks like TopLink, Hibernate etc… • EntityManager API big plus • Ease of use to develop CRUD operations • Query with @NamedQuery/@NamedQueries annotations
Conclusion(s) • Testability outside container is big plus
Conclusion(s) • Other neat features like sequence generators with @SequenceGenerator annotation • No longer we need to write our own PK generators • Can make use of database sequences • Those who don’t want database portability, go for it !
Conclusion(s) • Missing support for native SQL Queries • Not enough tooling support • O-R annotations need more tooling around • Immediate feedback on syntax problems and invalid queries – should not have to wait until deployment time
Q & Q U E S T I O N S A N S W E R S A