Upload
august-west
View
217
Download
0
Embed Size (px)
Citation preview
EnterpriseJava
v131013 EJB: Session Beans 1
EJB: Session Beans
EnterpriseJava
v131013 EJB: Session Beans 2
Needs and JavaSE/EE Implementation Options
EnterpriseJava
v131013 EJB: Session Beans 3
Goals
• Be able to deploy business logic to the EJB tier– hosted by the container
• resource management• threading• security• transactions• remote interfaces• async capabilities
– accessed by other local business logic and local web tier– accessed by remote clients
EnterpriseJava
v131013 EJB: Session Beans 4
Objectives• Rationale• Stateless Session Bean
– Stateless– Stateful– Singleton
• Enterprise Archives (EARs)• Example Session Bean• Interface Design Issues
– Lazy Load– Pure POJOs– DTO Classes
EnterpriseJavaOverview
• Entity Beans – model business data in system
• Session Beans– model interactions between other beans– Taskflow
• Enterprise Archive (EAR)– Deployment artifact with a specific structure containing
• EJB component(s)• WAR component(s)• Utility jar(s)• …
v131013 EJB: Session Beans 5
EnterpriseJava
v131013 EJB: Session Beans 6
Associated Design Patterns• Session Façade (covered in Business Logic)• Remote Façade• Data Transfer Objects
EnterpriseJava
v131013 EJB: Session Beans 7
Remote Facade• Forces
– core service layer (business logic and its business objects) contains fine grain methods and objects
– a significant number of fine-grain remote calls will not work
• Solution– add a Remote Facade
• a course-grain facade over a service layer • contains no business logic; it calls it• translates course-grain methods and objects into fine-grain
method calls and objects to/from service layer• bulk accessors wrap fine-grain access methods
– service layer does not have a remote interface• fine grain business objects used might not be Serializable
EnterpriseJava
v131013 EJB: Session Beans 8
Remote Facade Encapsulates Local Objects
EnterpriseJava
v131013 EJB: Session Beans 9
Remote Facade Encapsulates Local Logic
EnterpriseJava
v131013 EJB: Session Beans 10
DTO Pattern
• Context– Business Objects represent too much information or
behavior to transfer to remote client• Problem
– Client may get information they don't need– Client may get information they can't handle– Client may get information they are not authorized to use– Client may get too much information/behavior to be
useful (e.g., entire database serialized to client)• Forces
– Some clients are local and can share object references with business logic
– Handling specifics of remote clients outside of core scope of business logic
EnterpriseJava
v131013 EJB: Session Beans 11
DTO/Remote Facade Solution
• Layer a Remote Facade over Business Logic• Remote Facade constructs Data Transfer Objects
(DTOs) from Business Objects that are appropriate for remote client view
• Remote Facade uses DTOs to construct or locate Business Objects to communicate with Business Logic
EnterpriseJava
v131013 EJB: Session Beans 12
DTO Pattern Roles
• Data Transfer Object– represent a subset of the state of the application at a point
in time– not dependent on Business Objects or server-side
technologies• doing so would require sending Business Objects to client• XML and Web services provide the “ultimate isolation” in
DTO implementation• Remote Facade
– uses Business Logic to perform core business logic– layered on to of Business Logic to translate between
Business Objects and DTOs• Business Logic
– continues to perform core duties as described in DAO Pattern
EnterpriseJava
v131013 EJB: Session Beans 13
DTO Pattern Consequences• Clients only get what they need• Clients only get what they understand• Clients only get what they are authorized to use• Remote and Local interfaces to services are different
– makes it harder to provide location transparency
• Lightweight Business Objects can be used as DTOs– Remote Facade must make sure they are “pruned” of
excess related items before transferring to client– Remote Facade must make sure they are “cleaned” of
DAO persistence classes before transferring to client
EnterpriseJava
v131013 EJB: Session Beans 14
Use Cases and Session Beans• Session Bean per Use Case too fine grain
– CreateAccountEJB
– DepositEJB
– WithdrawEJB
– TransferEJB
• Group cohesive Use Cases into a larger-grain Session Bean
– TellerEJB• createAccount(), deposit(), withdraw(), transfer()
EnterpriseJava
v131013 EJB: Session Beans 15
Use of Session versus Entity Beans• Session Beans
– implementation of a task– interaction between other beans– direct database access
• bulk operations– examples
• TaxDistrict.calcTax(double cost)• Teller.transfer(long fromAccount, long toAccount,
double amount)• Registrar.listStudents(String course)
EnterpriseJava
v131013 EJB: Session Beans 16
Use of Session versus Entity Beans (cont.)
• Entity Beans– represent shared data in the database– provide a type-safe, complete view of shared
information– interacts with data generally at the individual
object/row level– examples
• Account, Student• Account.setOwner(String taxId), Account.getOwner()• Account.withdraw(double amount),
Account.deposit(double amount)
EnterpriseJava
v131013 EJB: Session Beans 17
Stateless Session Bean• maintains no conversational state
– each method is ignorant of what went before it and what will happen after it
• maintains implementation state– sharable between separate client invocations
• a set of procedures or batch commands that take in a set of parameters and return a result
EnterpriseJava
v131013 EJB: Session Beans 18
Stateful Session Bean• maintains conversational state
– object can cache values between calls• ex. iterator
– idle timeout period or client command ends lifetime• maintains implementation state
– not sharable between separate clients/objects• all resources are allocated to perform the work of one
Stateful Session bean instance. That instance is tied to the state of the client
• able to react to transaction states– ex. Publish error message on transaction rollback
EnterpriseJavaSingleton Session Bean
• Stateful session bean with only one instance shared across all clients
• Good for tracking transient state in-memory
v131013 EJB: Session Beans 19
EnterpriseJava
v131013 EJB: Session Beans 20
Stateless/Stateful/Singleton• Stateless
– can contain cached implementations• JDBC DataSources• JMS Publishers• cached EAI state• all non-visible to calling client
• Stateful– may contain all of the above and add client
conversational state • Singleton
– May contain all of the above except client conversation state would be shared across clients
• e.g., getNextTask()
EnterpriseJava
v131013 EJB: Session Beans 21
Stateless/Stateful/Singleton• Stateless
– Cheapest to implement, deploy, scale• Stateful
– should only be used within the scope of a single HttpRequest
– should not be used at HttpSession Scope• multiple threads would access same instance
• Singleton– Newest bean type– More overhead than stateless because of concurrency
management– Extremely efficient when managing in-memory state
EnterpriseJava
v131013 EJB: Session Beans 22
Stateless Session Bean Lifecycle
EnterpriseJava
v131013 EJB: Session Beans 23
Stateful Session Bean Lifecycle
EnterpriseJava
v131013 EJB: Session Beans 24
Singleton Session Bean Lifecycle
EnterpriseJavaJavaEE EARs
• Used for compound deployments– Multiple EJBs
– Multiple WARs
– EJB + WAR
• Optional with new JavaEE 6 “flexible deployment” and the first and last case above
– WAR• EJB(s)
v131013 EJB: Session Beans 25
EnterpriseJava
v131013 EJB: Session Beans 26
Class Loaders
• Arranged in a parent/child relationship• Requests for a class are first delegated to the parent
class loader• May access classes/resources loaded by local and
parent class loader• Do not have access to classes/resources loaded by
sibling class loaders
Parent Class Loader
Child Class Loader Child Class Loader
EnterpriseJava
27
Application Server Class Loader
EJB AppClass Loader
Web App Class Loader
Web App Class Loader
Separate EJB/WAR Deployment
• Classes loaded by EJB Application Class Loader not seen by Web Application
• Shared implementations must be placed in both applications
– WEB-INF/lib– causes difficulty when passing object between applications
that have loaded the same class
v131013 EJB: Session Beans
EnterpriseJava
v131013 EJB: Session Beans 28
J2EE Enterprise Application Deployment
Application Server Class Loader
EAR Class Loader
EJB App Class Loader
EAR Class Loader
Web App 2 Class LoaderWeb App 1 Class Loader Servlets/JSPs and lib.jars
loaded by isolated classloaders
All EJBs are loaded by a single class loader•may also include web dependent classes identified through manifest entries to promote singleton loading of classes across web applications
EJB interfaces and dependent classes identified by EJB manifests loaded by EAR’s classloader
EnterpriseJava
v131013 EJB: Session Beans 29
Enterprise Application Archive (EAR)
• WAR(s)
– directory or archive
• EJB(s)
– directory or archive
• Client JAR(s)
– client applications
• Utility Classes(s)
– directory or archive
– supplies external source utility classes
– referenced through MANIFESTs
• Resource Adapters(s)
– custom resource drivers
WARWARWAR
EJBEJBEJB
EAR
META-INF/application.xml
UtilityClasses
Resource AdapterResource
AdapterResource Adapter
ClientApp
ClientAppClient
App
UtilityClasses
UtilityClasses
EnterpriseJava
v131013 EJB: Session Beans 30
Directory and Archive Forms
• Exploded Directory Form– ability to modify static files (html/jsp) without
redeploying
– separate server serves up content in exploded form
– simpler build environment • consistent with build environment of free versions of
IDEs (Forte, JBuilder, etc.)
• Archive File Format– easy form of distribution
EnterpriseJava
v131013 EJB: Session Beans 31
application
icon
small-icon large-icon
display-name description? module+ security-role*
ejb|connector|java|web alt-dd
web-uri context-root
description?
role-name
application.xml
EnterpriseJava
v131013 EJB: Session Beans 32
Key Element Definitions
• Modules– ejb – EJBs (Ex. EJB1.jar)– web – web applications– java - client applications– connector – JCA resource adapters
• Web applications– web-uri (ex. webapp1.war)– context-root
• Name of web app’s context• May be empty if only one webapp in the application
EnterpriseJava
v131013 EJB: Session Beans 33
application.xml Example
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC
"-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN"
"http://java.sun.com/dtd/application_1_3.dtd">
<application>
<display-name>ejbsessionBankEAR</display-name>
<description>Example Session Bean Bank Application</description>
<module>
<web>
<web-uri>ejbsessionBankWAR.war</web-uri>
<context-root>/ejbsessionBankWAR</context-root>
</web>
</module>
<module>
<ejb>ejbsessionBankEJB-1.0.2007.2-SNAPSHOT.jar</ejb>
</module>
EnterpriseJava
v131013 EJB: Session Beans 34
Example: Core ImplementationejbsessionBankImpl/target/classes|-- META-INF| `-- orm.xml`-- ejava `-- examples `-- ejbsessionbank |-- bl | |-- BankException.class | `-- Teller.class |-- blimpl | `-- TellerImpl.class |-- bo | |-- Account.class | |-- Ledger.class | `-- Owner.class |-- dao | |-- AccountDAO.class | |-- DAOException.class | `-- OwnerDAO.class `-- jpa |-- JPAAccountDAO.class `-- JPAOwnerDAO.class
* Note: we are not including a JavaSE persistence.xml in Impl
EnterpriseJava
v131013 EJB: Session Beans 35
Example Session Bean: Business Interfacepackage ejava.examples.ejbsessionbank.bl;
import java.util.List;import ejava.examples.ejbsessionbank.bo.Account;import ejava.examples.ejbsessionbank.bo.Ledger;
public interface Teller { Account createAccount(String accNum) throws BankException; Account getAccount(String acctNum) throws BankException; Account closeAccount(String acctNum) throws BankException; void updateAccount(Account account) throws BankException; List<Account> getOverdrawnAccounts(int index, int count) throws BankException; List<Account> getAccounts(int index, int count) throws BankException; Ledger getLedger() throws BankException;}
EnterpriseJava
v131013 EJB: Session Beans 36
Example: EJBejbsessionBankEJB/target/classes|-- ejava| `-- examples| `-- ejbsessionbank| |-- dto| | `-- OwnerDTO.class| `-- ejb| |-- Stats.class| |-- StatsEJB.class| |-- StatsLocal.class| |-- StatsRemote.class| |-- TellerEJB.class| |-- TellerLocal.class| `-- TellerRemote.class`-- META-INF |-- ejb-jar.xml `-- persistence.xml
* Note: We are providing a JavaEE persistence.xml in the EJB
EnterpriseJava
v131013 EJB: Session Beans 37
Example Session Bean: Local and Remote Interfaces
package ejava.examples.ejbsessionbank.ejb;
import ejava.examples.ejbsessionbank.bl.Teller;
@javax.ejb.Localpublic interface TellerLocal extends Teller {}
package ejava.examples.ejbsessionbank.ejb;
import ejava.examples.ejbsessionbank.bl.Teller;
@javax.ejb.Remotepublic interface TellerRemote extends Teller {} * Warning – although business interfaces can be used
for both local and remote interfaces, this only worksfor simple data models – more later
EnterpriseJava
v131013 EJB: Session Beans 38
Example Session Bean: Bean Classpackage ejava.examples.ejbsessionbank.ejb;
import javax.annotation.*;import javax.ejb.*;import javax.persistence.*;...
@Statelesspublic class TellerEJB implements TellerLocal, TellerRemote { private static final Log log = ... @Resource protected SessionContext ctx; @PersistenceContext(unitName="ejbsessionbank") protected EntityManager em; @Resource(name="daoClass") protected String daoClassName; protected Teller teller;
Stateless
EnterpriseJava
v131013 EJB: Session Beans 39
Example Session Bean: Bean Class@PostConstruct
public void init() {
log.debug("init(), daoClass=" + daoClassName);
teller = new TellerImpl();
try {
AccountDAO dao = (AccountDAO)Thread.currentThread() //just a partial example of resolving
.getContextClassLoader() //a property supplied
.loadClass(daoClassName) //by the container
.newInstance();
((JPAAccountDAO)dao).setEntityManager(em);
((TellerImpl)teller).setAcctDAO(dao);
OwnerDAO ownerDAO = new JPAOwnerDAO();
((JPAOwnerDAO)ownerDAO).setEntityManager(em);
((TellerImpl)teller).setOwnerDAO(ownerDAO); }
catch (Exception ex) {
log.fatal("error loading dao class:" + daoClassName, ex);
throw new EJBException("error loading dao class:" +
daoClassName + ", " + ex);
}
@PreDestroy
public void close() { ... }
EnterpriseJava
v131013 EJB: Session Beans 40
Example Session Bean: Bean Class
public Account createAccount(String accountNumber) throws BankException{ try { return teller.createAccount(accountNumber); } catch (AccountDAOException ex) { ctx.setRollbackOnly(); log.fatal("internal error creating account", ex); throw new BankException("internal error creating account:"+ ex); }}
Log details of exception locally on server-side
Provide de-serializable message to client
EnterpriseJava
v131013 EJB: Session Beans 41
Example Session Bean: ejb-jar.xml<?xml version="1.0"?><ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1">
<enterprise-beans>
<session>
<ejb-name>TellerEJB</ejb-name>
<env-entry>
<env-entry-name>daoClass</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>ejava.examples.ejbsessionbank.jpa.JPAAccountDAO
</env-entry-value>
</env-entry>
...
</session>
</enterprise-beans>
</ejb-jar>Watch out for <CR>!!!
EnterpriseJava
v131013 EJB: Session Beans 42
Example Session Bean: persistence.xml<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="ejbsessionbank"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <jar-file>lib/ejbsessionBankImpl-${project.version}.jar</jar-file> <properties> <property name="hibernate.dialect" value="${hibernate.dialect}"/> </properties> </persistence-unit> </persistence>
EnterpriseJavaExample Singleton Session Bean:
Local and Remote Interfacespackage ejava.examples.ejbsessionbank.ejb;public interface Stats {
void open();void close();int getTotal();int getDelta();void reset();
}
package ejava.examples.ejbsessionbank.ejb;@javax.ejb.Localpublic interface StatsLocal extends Stats {}
package ejava.examples.ejbsessionbank.ejb;@javax.ejb.Remotepublic interface StatsRemote extends Stats {}
v131013 EJB: Session Beans 43
EnterpriseJavaExample Singleton Session Bean:
Bean Class Setuppackage ejava.examples.ejbsessionbank.ejb;
@[email protected]@javax.ejb.ConcurrencyManagement( javax.ejb.ConcurrencyManagementType.CONTAINER)@javax.ejb.AccessTimeout(value=3000)public class StatsEJB implements StatsLocal, StatsRemote { private static final Log log = ...
private int delta;private int total;
@javax.annotation.PostConstructlog.info("*** StatsEJB ***");
}
v131013 EJB: Session Beans 44
(Stateful)
EnterpriseJavaExample Singleton Session Bean:
Write/Read Methods@[email protected](
javax.ejb.LockType.WRITE)public void open() {
this.delta += 1;this.total += 1;
}
@Override@Lock(LockType.WRITE)public void close() {
this.delta -= 1;this.total += 1;
}
@Override@Lock(LockType.WRITE)public void reset() {
delta=0;total=0;
}
@Override@Lock(LockType.READ)public int getTotal() {
return total;}
@Override@Lock(LockType.READ)public int getDelta() {
return delta;}
v131013 EJB: Session Beans 45
EnterpriseJava
v131013 EJB: Session Beans 46
Example: RMI Test
ejbsessionBankTest/target/test-classes|-- ejava| `-- examples| `-- ejbsessionbank| `-- ejbclient… …| |-- TellerEJBClientIT.class| |-- TellerRemotingIT.class| |-- TellerOwnerEJBClientIT.class| `-- TellerOwnerRemotingIT.class|-- jboss-ejb-client.properties|-- jndi.properties`-- log4j.xml
JUnit Test Types*Test = unit tests run by surefire plugin*IT = integration tests run by failsafe plugin
EnterpriseJavaRemoting
• JNDI Tree (Internally Accessible)java:global/ejbsessionBankEAR/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerLocal
java:app/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerLocal
java:module/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerLocal
java:global/ejbsessionBankEAR/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
java:app/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
java:module/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
• JNDI Tree (externally Accessible)java:jboss/exported/ejbsessionBankEAR/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
• jndi.propertiesjava.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactoryjava.naming.factory.url.pkgs=java.naming.provider.url=remote://127.0.0.1:4447java.naming.security.principal=knownjava.naming.security.credentials=passwordjboss.naming.client.ejb.context=true
• External JNDI NameejbsessionBankEAR/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
v131013 EJB: Session Beans 47
• Generic naming mechanism• Works identical with non-EJB resources• Ignorant of EJB details• Less Efficient• Being deprecated by JBoss in favor of
EJB Client
EnterpriseJavaJUnit Integration Test (IT)
public class TellerRemotingIT { private static final Log log = ... protected Teller teller; @Before public void setUp() throws Exception { InitialContext jndi = new InitialContext(); teller = (TellerRemote)jndi.lookup(jndiName); }
@Test public void testCreateAccount() throws Exception { log.info("*** testCreateAccount ***"); Account account=null; //try with what should be a unique number try { account = teller.createAccount("1234"); log.debug("account created:" + account); } catch (Exception ex) { log.fatal("error creating account:" + ex, ex); fail("error creating account:" + ex); }
v131013 EJB: Session Beans 48
JNDI Properties being supplied through jndi.properties file -or-through a Propertiesobject
EnterpriseJavaEJBClient
• jndi.propertiesjava.naming.factory.initial=java.naming.factory.url.pkgs=org.jboss.ejb.client.namingjava.naming.provider.url=java.naming.security.principal=java.naming.security.credentials=
• jboss-ejb-client.properties#top level property listing the names of the connections. There will be a set #of properties for each name listed hereremote.connections=default
#here we define the properties for the server we have called "default"remote.connection.default.host=127.0.0.1remote.connection.default.port=4447remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
• External JNDI Nameejb:(ear)/(module)/(distinctName)/(ejbClass)!(remoteInterface)[?stateful]
ejb:ejbsessionBankEAR/ejbsessionBankEJB/””/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
v131013 EJB: Session Beans 49
• EJB-specific naming mechanism• Does not work with non-EJB resources• Aware of EJB details• More efficient than Remoting• Non-standard
EnterpriseJava
v131013 EJB: Session Beans 50
Lazy Load Issues• EJB
public List<Owner> getOwners(int index, int count) {
return teller.getOwners(index, count);
• RMI Test List<Owner> owners = teller.getOwners(0, 100); assertEquals("unexpected number of owners", 2, owners.size()); for(Owner o : owners) { for (Account a: o.getAccounts()) { //LINE 87 ... } }
• Errororg.hibernate.LazyInitializationException: failed to lazily initialize a
collection of role: ejava.examples.ejbsessionbank.bo.Owner.accounts, no session or session was closed
... org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:249)
at ejava.examples.ejbsessionbank.ejbclient.TellerOwnerRemoteTest.testLazy(TellerOwnerRemoteTest.java:87)
EnterpriseJava
v131013 EJB: Session Beans 51
Lazy Load Correction• EJB Remote
@Remotepublic interface TellerRemote extends Teller { List<Owner> getOwnersLoaded(int index, int count) throws BankException;}
• EJB public List<Owner> getOwnersLoaded(int index, int count) throws BankException { List<Owner> owners = getOwners(index, count); for(Owner owner : owners) { for (Account account : owner.getAccounts()) { account.getBalance(); //call a method to get loaded } } return owners; }
• RMI Test List<Owner> owners = teller.getOwnersLoaded(0, 100);
SELECT o FROM Owner o LEFT JOIN FETCH o.accounts
Alt: DAO JPAQL Querypublic class Owner { @OneToMany(fetch=EAGER) private List<Account> accounts;
Alt: relation fetch mode
EnterpriseJava
v131013 EJB: Session Beans 52
Non-POJO Class Issues• EJB
public List<Owner> getOwnersLoaded(int index, int count) throws BankException { List<Owner> owners = getOwners(index, count); for(Owner owner : owners) { for (Account account : owner.getAccounts()) { account.getBalance(); //call a method to get loaded } } return owners; }
• RMI Test List<Owner> owners = teller.getOwnersLoaded(0, 100); for(Owner o : owners) { for (Account a: o.getAccounts()) { log.info("account=" + a); } log.debug("addresses=" + o.getAccounts().getClass().getName()); assertTrue("unexpected collection class", o.getAccounts().getClass().getName().contains("hibernate")); }
• Output -account=id=2, acctnum=111, bal=$0.0
-addresses=org.hibernate.collection.PersistentBag
EnterpriseJava
v131013 EJB: Session Beans 53
Non-POJO Class Correction• EJB
public List<Owner> getOwnersPOJO(int index, int count) ... List<Owner> ownersPOJO = new ArrayList<Owner>(); for(Owner owner : getOwners(index, count)) { Owner ownerPOJO = new Owner(owner.getId()); ownerPOJO.setFirstName(owner.getFirstName()); ownerPOJO.setLastName(owner.getLastName()); ownerPOJO.setSsn(owner.getSsn()); for (Account account : owner.getAccounts()) { Account accountPOJO = new Account(account.getId()); accountPOJO.setAccountNumber(account.getAccountNumber()); accountPOJO.deposit(account.getBalance()); ownerPOJO.getAccounts().add(accountPOJO); } ownersPOJO.add(ownerPOJO); } return ownersPOJO; }
• RMI Test owners = teller.getOwnersPOJO(0, 100);... log.debug("addresses=" + o.getAccounts().getClass().getName()); assertFalse("unexpected collection class", o.getAccounts().getClass().getName().contains("hibernate"));• Output -account=id=2, acctnum=111, bal=$0.0 -addresses=java.util.ArrayList
EnterpriseJava
v131013 EJB: Session Beans 54
BO Complexity Class Issues
• Business Objectpublic class Owner implements Serializable {
private long id;
private String firstName;
private String lastName;
private String ssn;
private Collection<Account> accounts = new ArrayList<Account>();
...
EnterpriseJava
v131013 EJB: Session Beans 55
BO Complexity Correction• DTO Class
public class OwnerDTO implements Serializable { private static final long serialVersionUID = 1L; private long id; private String firstName; private String lastName; private int accounts;...
• EJB public List<OwnerDTO> getOwnersDTO(int index, int count) throws BankException { List<OwnerDTO> ownersDTO = new ArrayList<OwnerDTO>(); for(Owner owner : getOwners(index, count)) { OwnerDTO ownerDTO = new OwnerDTO(owner.getId()); ownerDTO.setFirstName(owner.getFirstName()); ownerDTO.setLastName(owner.getLastName()); ownerDTO.setAccounts(owner.getAccounts().size()); ownersDTO.add(ownerDTO); } return ownersDTO; }
• RMI Test List<OwnerDTO> owners = teller.getOwnersDTO(0, 100);
EnterpriseJava
v131013 EJB: Session Beans 56
Building EJBswith Maven
EnterpriseJava
v131013 EJB: Session Beans 57
Parent Project|-- ejbsessionBankBLImpl|-- ejbsessionBankEAR|-- ejbsessionBankEJB|-- ejbsessionBankTest`-- pom.xml
EnterpriseJava
v131013 EJB: Session Beans 58
Parent Project<?xml version="1.0" encoding="UTF-8"?><project> <parent> <groupId>ejava</groupId> <artifactId>ejava-root</artifactId> <version>3.0.2012.2-SNAPSHOT</version> <relativePath/> </parent> <modelVersion>4.0.0</modelVersion>
<groupId>ejava.javaee.ejb</groupId> <artifactId>ejbsessionBank</artifactId> <packaging>pom</packaging>
<name>EJB Session Bean Bank</name> <description> This project is the root project for the core session bean example. </description> <modules> <module>ejbsessionBankImpl</module> <module>ejbsessionBankEJB</module> <module>ejbsessionBankWAR</module> <module>ejbsessionBankEAR</module> <module>ejbsessionBankTest</module> </modules></project>
EnterpriseJava
v131013 EJB: Session Beans 59
EJB Project
ejbsessionBankEJB/src/`-- main |-- java | `-- ejava | `-- examples | `-- ejbsessionbank | |-- dto | | `-- OwnerDTO.java | `-- ejb | |-- StatsEJB.java | |-- Stats.java | |-- StatsLocal.java | |-- StatsRemote.java | |-- TellerEJB.java | |-- TellerLocal.java | `-- TellerRemote.java `-- resources `-- META-INF |-- ejb-jar.xml |-- persistence.xml `-- (jboss-ejb3.xml)
EnterpriseJava
v131013 EJB: Session Beans 60
EJB Project pom.xml: ejb Packaging<project> <parent> <artifactId>ejbsessionBank</artifactId> <groupId>ejava.javaee.ejb</groupId> <version>3.0.2012.2-SNAPSHOT</version> <relativePath>..</relativePath> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>ejbsessionBankEJB</artifactId> <packaging>ejb</packaging> <name>Session Bank EJB</name> <description> This project provides an example of the core properties of a session bean. </description>
<dependencies> </dependencies>
<build> </build>
<profiles> </profiles></project>
EnterpriseJava
v131013 EJB: Session Beans 61
EJB Project: dependencies<dependencies> <!-- core dependencies --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankImpl</artifactId> <version>${project.version}</version> <scope>provided</scope> </dependency></dependencies>
EnterpriseJava
v131013 EJB: Session Beans 62
EJB Project: plugins <build> <!--tell the resource plugin to perform filtering on resources to fill in dialect, etc. --> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources>
<plugins> <!-- tell the EJB plugin we are using EJB3 and configure client-jar --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <configuration> <generateClient>true</generateClient> <clientExcludes> <clientExclude>**/ejb/*Local.class</clientExclude> <clientExclude>**/ejb/*EJB.class</clientExclude> </clientExcludes> </configuration> </plugin> </plugins> </build>
EnterpriseJava
v131013 EJB: Session Beans 63
EJB Project: profiles <profiles> <profile> <!-- H2 embedded/file-based DB --> <id>h2db</id> <properties> <jdbc.driver>org.h2.Driver</jdbc.driver> <jdbc.url>jdbc:h2:${basedir}/target/h2db/ejava</jdbc.url> <jdbc.user>sa</jdbc.user> <jdbc.password/>
<hibernate.dialect> org.hibernate.dialect.H2Dialect </hibernate.dialect>
</properties>... </profile> </profiles>
EnterpriseJava
v131013 EJB: Session Beans 64
EJB Project: persistence.xml<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="ejbsessionbank"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties>
<property name="hibernate.dialect" value="${hibernate.dialect}"/>
<property name="hibernate.show_sql" value="false"/> </properties> </persistence-unit>
•After filtering <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
EnterpriseJava
v131013 EJB: Session Beans 65
EAR ProjectejbsessionBankEAR/`-- pom.xml
• pom.xml<project> <parent> <artifactId>ejbsessionBank</artifactId> <groupId>ejava.javaee.ejb</groupId> <version>3.0.2012.2-SNAPSHOT</version> <relativePath>..</relativePath> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>ejbsessionBankEAR</artifactId> <packaging>ear</packaging>
<name>Session Bank EAR</name>
<dependencies> </dependencies>
<build> </build>
</project>
EnterpriseJava
66
EAR Project (cont.): dependencies <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankEJB</artifactId> <version>${project.version}</version> <type>ejb</type> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankWAR</artifactId> <version>${project.version}</version> <type>war</type> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankImpl</artifactId> <version>${project.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
v131013 EJB: Session Beans
EnterpriseJava
v131013 EJB: Session Beans 67
EAR Project (cont.): plugins <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ear-plugin</artifactId> <configuration> <description> Example Session Bean Bank Application </description> <defaultLibBundleDir>lib</defaultLibBundleDir> <!-- eliminates use of version in EAR JNDI name portion --> <applicationName>${project.artifactId}</applicationName> <modules> <webModule> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankWAR</artifactId> <contextRoot>ejbsessionBank</contextRoot> </webModule> <!-- eliminates use of the version in the EJB JNDI name --> <ejbModule> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankEJB</artifactId> <bundleFileName>ejbsessionBankEJB.jar</bundleFileName> </ejbModule> </modules> </configuration> </plugin> </plugins> </build>
EnterpriseJava
v131013 EJB: Session Beans 68
EAR Project (cont.)• Use cargo plugin to undeploy built and deployed EARs <profile> <id>undeploy</id> <build> <plugins> <plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <executions> <execution> <id>undeploy-ear</id> <phase>pre-clean</phase> <goals> <goal>undeploy</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile>
EnterpriseJava
v131013 EJB: Session Beans 69
EAR Project (cont.)
ejbsessionBankEAR/target/ejbsessionBankEAR-3.0.2012.2-SNAPSHOT|-- ejbsessionBankEJB.jar|-- ejbsessionBankWAR-3.0.2012.2-SNAPSHOT.war|-- lib| |-- ejava-util-3.0.2012.2-SNAPSHOT.jar| `-- ejbsessionBankImpl-3.0.2012.2-SNAPSHOT.jar`-- META-INF `-- application.xml
EnterpriseJava
v131013 EJB: Session Beans 70
RMI Test ProjectejbsessionBankTest/|-- pom.xml`-- src |-- main `-- test |-- java | `-- ejava | `-- examples | `-- ejbsessionbank | `-- ejbclient | |-- TellerOwnerRemoteTest.java | `-- TellerRemoteTest.java `-- resources |-- jndi.properties `-- log4j.xml
• pom.xml<project> <parent> <artifactId>ejbsessionBank</artifactId> <groupId>ejava.javaee.ejb</groupId> <version>3.0.2012.2-SNAPSHOT</version> <relativePath>..</relativePath> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>ejbsessionBankTest</artifactId> <packaging>jar</packaging> <name>Session Bank Test</name>
EnterpriseJava
v131013 EJB: Session Beans 71
RMI Test Project (cont.) <dependencies>... <!-- component to test within deployment--> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankEJB</artifactId> <version>${project.version}</version> <type>ejb-client</type> <scope>test</scope> </dependency>
<!-- package being deployed must be a dependency --> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankEAR</artifactId> <version>${project.version}</version> <type>ear</type> <scope>compile</scope> </dependency>
<dependency> <groupId>ejava.common</groupId> <artifactId>jboss-rmi-client</artifactId> <version>${project.version}</version> <type>pom</type> <scope>test</scope> </dependency>...
EnterpriseJava
v131013 EJB: Session Beans 72
RMI Test Project (cont.): plugins <build> <plugins> <!-- artifacts to deploy to server --> <plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <configuration> <deployables> <deployable> <groupId>${project.groupId}</groupId> <artifactId>ejbsessionBankEAR</artifactId> <type>ear</type> </deployable> </deployables> </configuration> </plugin>
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <configuration> <systemPropertyVariables> <foo>${foovar}</foo> </systemPropertyVariables> </configuration> </plugin> </plugins> </build>
EnterpriseJava
v131013 EJB: Session Beans 73
Summary• Integrates Bean activity (“task script”)• Server-side code for client
– Stateless and Stateful• Server-side cache for client
– Stateful• POJO with minor amount of class metadata
EnterpriseJava
v131013 EJB: Session Beans 74
References
• “Enterprise JavaBeans 3.0, 5th Edition”; Burke & Monsen-Haefel; ISBN 0-596-00978-X; O'Reilly
• “Mobile Design Patterns and Architectures”, http://www.titu.jyu.fi/modpa/ (MODPA)
– Remote Facade• http://www.titu.jyu.fi/modpa/Patterns/pattern-RemoteFaca
de.html• “Patterns of Enterprise Archecture, Chapter 15: Remote
Facade”; Martin Fowler– http://www.theserverside.com/tt/articles/content/
FowlerPatterns/Fowler_ch15.pdf