740 likes | 887 Views
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
E N D
EJB: Session Beans EJB: Session Beans
EJB: Session Beans Needs and JavaSE/EE Implementation Options
EJB: Session Beans 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
EJB: Session Beans Objectives • Rationale • Stateless Session Bean • Stateless • Stateful • Singleton • Enterprise Archives (EARs) • Example Session Bean • Interface Design Issues • Lazy Load • Pure POJOs • DTO Classes
EJB: Session Beans Overview • 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) • …
EJB: Session Beans Associated Design Patterns • Session Façade (covered in Business Logic) • Remote Façade • Data Transfer Objects
EJB: Session Beans 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
EJB: Session Beans Remote Facade Encapsulates Local Objects
EJB: Session Beans Remote Facade Encapsulates Local Logic
EJB: Session Beans 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
EJB: Session Beans 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
EJB: Session Beans 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
EJB: Session Beans 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
EJB: Session Beans 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()
EJB: Session Beans 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)
EJB: Session Beans 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)
EJB: Session Beans 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
EJB: Session Beans 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
EJB: Session Beans Singleton Session Bean • Stateful session bean with only one instance shared across all clients • Good for tracking transient state in-memory
EJB: Session Beans 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()
EJB: Session Beans 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
EJB: Session Beans Stateless Session Bean Lifecycle
EJB: Session Beans Stateful Session Bean Lifecycle
EJB: Session Beans Singleton Session Bean Lifecycle
EJB: Session Beans JavaEE 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)
EJB: Session Beans 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
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 EJB: Session Beans Application Server Class Loader EJB App Class Loader Web App Class Loader Web App Class Loader
EJB: Session Beans J2EE Enterprise Application Deployment Application Server Class Loader EAR Class Loader EJB interfaces and dependent classes identified by EJB manifests loaded by EAR’s classloader EAR Class Loader 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 App Class Loader Web App 2 Class Loader Web App 1 Class Loader Servlets/JSPs and lib.jars loaded by isolated classloaders
EJB: Session Beans Enterprise Application Archive (EAR) EAR WAR EJB WAR EJB WAR EJB Utility Classes Utility Classes Utility Classes Resource Adapter Client App Client App Resource Adapter Client App Resource Adapter META-INF/application.xml • 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
EJB: Session Beans 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
EJB: Session Beans application.xml application icon display-name description? module+ security-role* small-icon large-icon description? ejb|connector|java|web alt-dd role-name web-uri context-root
EJB: Session Beans 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
EJB: Session Beans 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>
EJB: Session Beans Example: Core Implementation ejbsessionBankImpl/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
EJB: Session Beans Example Session Bean: Business Interface package 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; }
EJB: Session Beans Example: EJB ejbsessionBankEJB/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
EJB: Session Beans Example Session Bean: Local and Remote Interfaces package ejava.examples.ejbsessionbank.ejb; import ejava.examples.ejbsessionbank.bl.Teller; @javax.ejb.Local public interface TellerLocal extends Teller { } package ejava.examples.ejbsessionbank.ejb; import ejava.examples.ejbsessionbank.bl.Teller; @javax.ejb.Remote public interface TellerRemote extends Teller { } * Warning – although business interfaces can be used for both local and remote interfaces, this only works for simple data models – more later
EJB: Session Beans Example Session Bean: Bean Class package ejava.examples.ejbsessionbank.ejb; import javax.annotation.*; import javax.ejb.*; import javax.persistence.*; ... @Stateless public 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
EJB: Session Beans 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() { ... }
EJB: Session Beans 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
EJB: Session Beans 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>!!!
EJB: Session Beans 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>
EJB: Session Beans Example Singleton Session Bean: Local and Remote Interfaces package ejava.examples.ejbsessionbank.ejb; public interface Stats { void open(); void close(); int getTotal(); int getDelta(); void reset(); } package ejava.examples.ejbsessionbank.ejb; @javax.ejb.Local public interface StatsLocal extends Stats { } package ejava.examples.ejbsessionbank.ejb; @javax.ejb.Remote public interface StatsRemote extends Stats { }
EJB: Session Beans Example Singleton Session Bean: Bean Class Setup package ejava.examples.ejbsessionbank.ejb; @javax.ejb.Singleton @javax.ejb.Startup @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.PostConstruct log.info("*** StatsEJB ***"); } (Stateful)
EJB: Session Beans Example Singleton Session Bean: Write/Read Methods @Override @javax.ejb.Lock( 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; }
EJB: Session Beans 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
EJB: Session Beans • Generic naming mechanism • Works identical with non-EJB resources • Ignorant of EJB details • Less Efficient • Being deprecated by JBoss in favor of EJB Client Remoting • 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.properties java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory java.naming.factory.url.pkgs= java.naming.provider.url=remote://127.0.0.1:4447 java.naming.security.principal=known java.naming.security.credentials=password jboss.naming.client.ejb.context=true • External JNDI Name ejbsessionBankEAR/ejbsessionBankEJB/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
EJB: Session Beans JUnit 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); } JNDI Properties being supplied through jndi.properties file -or- through a Properties object
EJB: Session Beans • EJB-specific naming mechanism • Does not work with non-EJB resources • Aware of EJB details • More efficient than Remoting • Non-standard EJBClient • jndi.properties java.naming.factory.initial= java.naming.factory.url.pkgs=org.jboss.ejb.client.naming java.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 here remote.connections=default #here we define the properties for the server we have called "default" remote.connection.default.host=127.0.0.1 remote.connection.default.port=4447 remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false • External JNDI Name ejb:(ear)/(module)/(distinctName)/(ejbClass)!(remoteInterface)[?stateful] ejb:ejbsessionBankEAR/ejbsessionBankEJB/””/TellerEJB!ejava.examples.ejbsessionbank.ejb.TellerRemote
EJB: Session Beans 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 ... } } • Error org.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)