Top Banner
Enterprise Java v131013 EJB: Session Beans 1 EJB: Session Beans
74

EJB: Session Beans

Jan 18, 2016

Download

Documents

cadee

EJB: Session Beans. Needs and JavaSE/EE Implementation Options. Goals. Be able to deploy business logic to the EJB tier hosted by the container resource management threading security transactions remote interfaces async capabilities - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 1

EJB: Session Beans

Page 2: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 2

Needs and JavaSE/EE Implementation Options

Page 3: EJB: Session Beans

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

Page 4: EJB: Session Beans

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

Page 5: EJB: Session Beans

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

Page 6: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 6

Associated Design Patterns• Session Façade (covered in Business Logic)• Remote Façade• Data Transfer Objects

Page 7: EJB: Session Beans

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

Page 8: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 8

Remote Facade Encapsulates Local Objects

Page 9: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 9

Remote Facade Encapsulates Local Logic

Page 10: EJB: Session Beans

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

Page 11: EJB: Session Beans

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

Page 12: EJB: Session Beans

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

Page 13: EJB: Session Beans

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

Page 14: EJB: Session Beans

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()

Page 15: EJB: Session Beans

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)

Page 16: EJB: Session Beans

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)

Page 17: EJB: Session Beans

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

Page 18: EJB: Session Beans

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

Page 19: EJB: Session Beans

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

Page 20: EJB: Session Beans

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()

Page 21: EJB: Session Beans

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

Page 22: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 22

Stateless Session Bean Lifecycle

Page 23: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 23

Stateful Session Bean Lifecycle

Page 24: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 24

Singleton Session Bean Lifecycle

Page 25: EJB: Session Beans

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

Page 26: EJB: Session Beans

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

Page 27: EJB: Session Beans

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

Page 28: 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

Page 29: EJB: Session Beans

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

Page 30: EJB: Session Beans

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

Page 31: EJB: Session Beans

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

Page 32: EJB: Session Beans

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

Page 33: EJB: Session Beans

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>

Page 34: EJB: Session Beans

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

Page 35: EJB: Session Beans

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;}

Page 36: EJB: Session Beans

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

Page 37: EJB: Session Beans

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

Page 38: EJB: Session Beans

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

Page 39: EJB: Session Beans

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() { ... }

Page 40: EJB: Session Beans

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

Page 41: EJB: Session Beans

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>!!!

Page 42: EJB: Session Beans

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>

Page 43: EJB: Session Beans

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

Page 44: EJB: Session Beans

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)

Page 45: EJB: Session Beans

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

Page 46: EJB: Session Beans

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

Page 47: EJB: Session Beans

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

Page 48: EJB: Session Beans

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

Page 49: EJB: Session Beans

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

Page 50: EJB: Session Beans

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)

Page 51: EJB: Session Beans

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

Page 52: EJB: Session Beans

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

Page 53: EJB: Session Beans

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

Page 54: EJB: Session Beans

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>();

...

Page 55: EJB: Session Beans

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);

Page 56: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 56

Building EJBswith Maven

Page 57: EJB: Session Beans

EnterpriseJava

v131013 EJB: Session Beans 57

Parent Project|-- ejbsessionBankBLImpl|-- ejbsessionBankEAR|-- ejbsessionBankEJB|-- ejbsessionBankTest`-- pom.xml

Page 58: EJB: Session Beans

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>

Page 59: EJB: Session Beans

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)

Page 60: EJB: Session Beans

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>

Page 61: EJB: Session Beans

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>

Page 62: EJB: Session Beans

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>

Page 63: EJB: Session Beans

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>

Page 64: EJB: Session Beans

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"/>

Page 65: EJB: Session Beans

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>

Page 66: EJB: Session Beans

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

Page 67: 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>

Page 68: EJB: Session Beans

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>

Page 69: EJB: Session Beans

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

Page 70: EJB: Session Beans

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>

Page 71: EJB: Session Beans

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>...

Page 72: EJB: Session Beans

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>

Page 73: EJB: Session Beans

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

Page 74: EJB: Session Beans

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