CS6320 - EJB L. Grewe Enterprise JavaBeans Components Enterprise applications are modeled as a collection of components (or enterprise beans) in which each component is a reusable software unit that implements a specific part of the business functionality and has a well-specified interface. Used in Business/Data layers Scalable • container can create pool of servable EJBs Transactional • EJBs can manage transactions Concurrency safe. • EJBs can have state protection from concurrent access • EJBs can be tied with database entries A Java Architecture Java Technologies External Application EJB lives in a container Deployed on EJB servers and are hosted within containers. EJB depend on the container for certain services that can be declaratively customized at deployment time. Example J2EE server Types of EJBs There are three types of EJBs: • Session beans – Model task or process oriented aspects of a business application • Entity beans – Model persistent enterprise data** (note: Entity beans being replaced by Java Persistence API) • Message beans – Model asynchronous consuming of messages EJB more…. An EJB is a Java object defining a part of an application. Each EJB object implements a remote interface that it advertises. The EJB system generates proxy objects (stubs and skeletons) between the client and the EJB. Clients use the RMI-IIOP protocol for communication. Presence of the proxy objects is transparent to the clients. N-Tier Architecture Using EJB Presentation Layer Presentation Logic Tier Boundary EJB object EJB object EJB object EJB object Business Logic Layer (Application Server) JDBC Tier Boundary Database Data Layer 7 How a Client Accesses an EJB 1. 2. 3. Client locates the EJB container through the JNDI service. (or you know where it is) Client finds a reference to the EJB's interface. Now with the interface object, the client invokes methods on the EJB interface which the container in turn delegates to the bean itself. Acquiring a Bean 3: Create Interface New EJB object Client Object 5: Return EJB Object Reference 6: Invoke Remote Interface Business method 1: retrieve Home Object Reference 2: Return Home Reference 4: Create EJB Object EJB Object Enterprise Beans 7: Delegate request to object JNDI EJB Server Naming Service 9 The EJB RMI-IIOP Common Object Request Broker Architecture (CORBA) • Specifications governed by the Object Management Group (OMG) • CORBA is language neutral, using interfaces written in Interface Definition Language (IDL). • CORBA uses Object Request Brokers (ORBs) for networking and data marshalling. EJBs borrow heavily from this technology and from RMI • RMI-IIOP CORBA services incorporated into EJBs: • Naming, Lifecycle management, Security • Persistence, Distributed structures Session EJBs Encapsulate business logic best practice: use when only one client has access to a bean instance and the state does not need to be persistent. Think of a session bean as a grouping of related business operations • BankTeller session bean does withdrawl, checkaccount, deposit • LoanManager session bean does loan_application, loan_approval Session EJBs: 2 kinds Stateless created with no regard for the maintenance of any state between subsequent calls by a client. Statefull maintain state for a particular client between alss before some amount of time has expiered. EJB 3.0 – life made easier MAJOR changes from 2.* to make writing EJBs easier Ease of Use: • Have replaced 2 interfaces and 1 class with now only a business interface and a bean that implements this interface (note for local access only need class) Get rid of / simplify deployment XML files • Uses 'annotations' rather than the complex 'deployment descriptors' used in version 2.x. EJB 3.* : The interface class This class defines the business logic as an interface package helloworld; /** * Interface of the HelloWorld example. * @author You */ public interface HelloWorldInterface { /** * Hello world. */ void helloWorld(); } EJB 3.* : The bean class…implementing the interface This bean will be a stateless session bean, thus the class will be annotated with @Stateless annotation. package helloword; import javax.ejb.Remote; import javax.ejb.Stateless; /** the interface must be a * Business code for the HelloWorld interface. remote interface to be * @author Florent Benoit available for remote */ clients. This is done @Stateless by using the @Remote @Remote(HelloWorldInterface.class) annotation. public class HelloWorldBean implements HelloWorldInterface { /** * Hello world implementation. */ public void helloWorld() { System.out.println("Hello world !"); } } EJB 3.*: next step of hello world Compile HelloWorldInterface and HelloWorldBean Now you can JAR these files and deploy (see your container for details) EJB 3.*: HelloWorld Client Code package helloworld; import javax.naming.Context; import javax.naming.InitialContext; /** * Client of the helloworld bean. * @author You */ public final class Client { /** * JNDI name of the bean. */ private static final String JNDI_NAME = "helloworld.HelloWorldBean" + "_" + HelloWorldInterface.class.getName() + "@Remote“; /** * Utility class. No public constructor */ private Client() { } You need a client Could be a servlet or any kind of Java program to communicate with the EJB. Here we make a standalone Console application Class named Client //hardcoding location of EJB //that is in same source package // as this client HelloWorld Client Code…continued You need a client /** * Main method. * @param args the arguments (not required) * @throws Exception if exception is found. */ public static void main(final String[] args) throws Exception { //grab content of container Context initialContext = new InitialContext(); Could be a servlet or any kind of Java program to communicate with the EJB. Here we make a standalone Console application Class named Client. //look up EJB in this container and grab interface object HelloWorldInterface businessItf = (HelloWorldInterface) initialContext.lookup(JNDI_NAME); System.out.println("Calling helloWorld method..."); //call method of bean remotely through client’s interface object. businessItf.helloWorld(); } } Remote and Local Interfaces EJB can have remote or local interface Remote • Used for accessing beans outside the JVM managing the bean class • Restricts access to pass by value, and parameters must be Serializable Local • • • • Used by clients that share a JVM with the bean Do not involve networking Use pass by reference semantics Allow association with other EJBs (in the local JVM, thus reduce communication overheads) • Do not need interface class – can do only with bean class. @Remote – an annotation The @Remote line is an annotation • It can occur on the previous line, or you can use it like a modifier (e.g. @Remote public …) • Annotations specify meta-data • In this case, @Remote says that the interface can be used remotely • Alternatively, a local interface could be used when clients and EJBs are co-located. @Local – an annotation the @Local annotation would declare it as a local interface, which can only be accessed from the same machine EJB 3.* - Another Example Calculator – add and subtract import javax.ejb.Remote; import javax.ejb.Stateless; @Remote public interface Calculator { public int add(int x, int y); public int subtract(int x, int y); } @Stateless public class CalculatorBean implements Calculator { public int add(int x, int y) { return x + y; } public int subtract(int x, int y) { Return x – y; } } EJB 3.* - Shopping cart - stateful Still homeless • Created as they are looked up @Remove replaces EJBObject.remove in EJB 2.* when the EJB is to go away. Stateful bean is removed after method called import javax.ejb.Remote; import javax.ejb.Statefull; @Remote public interface ShoppingCart { public void addItem(int prodId, int quantity); public void checkout(); } @Stateful public class ShoppingCartBean implements ShoppingCart { @Remove public void checkout() { … } } It is called @Remove annotation – lifecycle end declares a method to represent the deletion of the bean • The method itself does not implement the deletion of the bean • The method is called first, then the container deletes the bean • This annotation is available to both types of session bean, as well as message-driven beans public ShopperImpl implements Shopper { //… other methods … @Remove public void remove() { System.out.println(“Removing Shopper”); } } EJB – transaction and security Example Shopping cart –need in check out @Stateful public class ShoppingCartBean implements ShoppingCart { @Remove @TransactionAttribute(REQUIRED) @MethodPermission({“valid_customer”}) public void checkout() { … // your code goes here. } } EJB 3.0: Dependency Injection Bean class specifies dependencies instead of lookup The @EJB annotation Facilitates Test Driven Development marks the converter Possible to test EJBs outside of container field as a dependency injected field @Stateful public class ShoppingCartBean implements ShoppingCart { Dependency injection is a technical term that basically means @Resource private SessionContext ctx; that dependencies (such as an EJB to its client) are made @EJB externally private CreditCardProcessor processor; //specifies EJB that this bean uses. private DataSource jdbc; @Resource(mappedName=“java:/DefaultDS”) public void setDataSource(DataSource db) { this.jdbc = db; } } In EJB 3.0, you can declare which EJBs should be used by a particular when you deploy that client @EJB – dependency injection You can use the dependency injection method of obtaining a session bean instance • This is the preferred method, since: It involves less code in the client It saves the client from dealing with JNDI directly The javax.ejb.EJB annotation is added to the declaration of the private member variable shopper, which is of type ShopperBean. ShopperBean exposes a local, no-interface view, so the enterprise bean implementation class is the variable type. import javax.ejb.EJB; public class SFSBClient { @EJB ShopperBean shopper; } public void cartTest() { CartItem item1 = new CartItem(“Briefcase 14x8”, 1); CartItem item2 = new CartItem(“Ball Point Pen”, 12); shopper.addToShoppingCart(item1); shopper.addToShoppingCart(item2); … code omitted … } Lifecycle Annotations / callbacks PUT THESE METHODS in YOUR BEAN @PrePassivate //called before put to “sleep” public void passivateHandler() { // free up resources before going into passive mode // whatever code you want } @PostActivate //called after activated public void activateHandler(InvocationContext context) { // re-acquire resources // whatever code you want } NOTE: an alternative to having code in the bean itself is to create an Inceptor Class ---see later in lecture Passivate / Activate – Lifecycle modes As stateful session bean becomes passive, it goes into an available pool • The state is serialized and stored to disk When the bean’s client invokes one of the bean’s methods, the bean is activated again • However, if the bean remains unused for too long, it may be deleted • In these cases, the container may create a new instance, and load the state into the new bean for the client EJB 3.* Deployment Descriptor.....they can be optional (but see container for details) Some people like XML deployment descriptors Externalize configuration Externalize system architecture Replace annotations with XML (this is how must do in EJB 2.*) Recall Shopping Cart Example w/ annotations @Remote public interface ShoppingCart { public void addItem(int prodId, int quantity); public void checkout(); } @Stateful public class ShoppingCartBean implements ShoppingCart { @Remove @TransactionAttribute(REQUIRED) @MethodPermission({“valid_customer”}) public void checkout() { … } Shopping cart with no annotations but mandatory deployment XML file public interface ShoppingCart { public void addItem(int prodId, int quantity); public void checkout(); } public class ShoppingCartBean implements ShoppingCart { public void checkout() { … } } XML Descriptors Partial deployment descriptors supported • Start off with annotations, configure as needed <ejb-jar> <enterprise-beans> <session> <ejb-name>ShoppingCartBean</ejb-name> <ejb-local-ref> <ejb-ref-name>processor</ejb-ref-name> <local>CreditCardProcessor</local> </ejb-local-ref> </session> </enterprise-beans> </ejb-jar> Interceptors Interceptors cart.buy(product) interceptor @Stateless public class CartBean { public void buy(…) {} } Interceptors intercept calls Interceptors sit between caller and a session bean Analogous to servlet filters Can only be used with session and message driven beans Precursor to full aspect-oriented programming Interceptors Interceptor is a plain Java class A method can be designated as the interceptor method @AroundInvoke That method must return Object and throw Throwable That method must also accept an InvocationContext InvocationContext hold information about the request Request can be aborted with an exception Exceptions can be caught from the bean class and suppressed Return objects can be changed Arguments can be modified Interceptors public class RuleBasedSecurityInterceptor { boolean checkRule(…) { …} @AroundInvoke //this is the method acting as inceptor public Object customSecurity(InvocationContext ctx) throws Exception { if (checkRule(…) == false) { throw new SecurityException(“Custom check failed”); } return ctx.proceed(); } } Interceptors @Stateful All methods in class @Interceptors(RuleBasedSecurityInterceptor.class) public class ShoppingCartBean implements ShoppingCart { void buy(…) { …} @Interceptors(RuleBasedSecurityInterceptor.class) public void checkout() {…} } Per method Default Interceptors <ejb-jar> <assembly-descriptor> <interceptor-binding> <ejb-name>*</ejb-name> Every bean in deployment <interceptor-class>org.jboss.RuleBasedSecurity</interceptorclass> </interceptor-binding> </assembly-descriptor> </ejb-jar> Intercepting callbacks POST CONSTRUCT EVENT Interceptor @Stateful public class CartBean { @PostConstruct public void initialize(…) {} } Callback events can be intercepted Work same as @AroundInvokes Intercepting Callbacks @Stateless @Interceptor(JndiInjector.class) public class JndiInjector { @JndiInject(“java:/TransactionManager”) TransactionManager tm; } Custom injection annotation Intercepting Callbacks public class JndiInjector { @PostConstruct public void injector(InvocationContext ctx) { injectIntoAllFieldsWithJndiInjectAnnotation(ctx.getTarget()); } } EJB 2.* ---for historical purposes Need 2 interfaces and 1 class EJB 2.*: Back to Classes: Home Interface Implements EJBHome Lists methods available for creating, removing and finding EJBs in the container. container creates a home object from this interface at deployment time. at runtime home object used by client in conjunction with a naming service to find the component and establish a connection to its component interface public interface EnrollmentCartHome extends EJBHome { EnrollmentCart create () throws CreateException,RemoteException; } EJB 2.*: Back to Classes: Component Interface defines the methods offered by the bean class. container provides implementation of this interface by creating an object client through the home object (see above) is given this component object and uses it to invoke methods on the bean. component interface can be remote OR local.... remote when EJB client on different machine (typical) otherwise local (sometimes). public interface EnrollmentCart extends EJBObject { public void addCourses(String[] courseIDs) throws RemoteException; public Collection getCourses() throws RemoteException; public void empty() throws RemoteException; } EJB 2.*Back to Classes: Bean Class has methods that implements business logic,etc. accessed by client through component object (see above) not directly. public class EnrollmentCartEJB implements javax.ejb.SessionBean { private SessionContext ctx; private HashSet cart; /* callback methods */ public void setSessionContext(SessionContext ctx) { this.ctx = ctx; } pubic void ejbCreate() throws CreateException { cart = new HasSet(); } public void ejbActivate() {} public void ejbPassivate() {} public void ejbRemove() {} /* implement all business methods as defined in the component interface*/ public void addCourses(String[] courseIds) { if(couseIds == null) return; for(int i=0; i<courseIDs.length; i++) cart.add(courseIds[i]); } public Collection getCourses() { return cart; } public void empty() { cart.clear(); } } Development Steps (similar for EJB2.* and EJB3.*) Implement EJB Standard Interfaces Interfaces required by standard EJB component model to enable container-based management of EJB Implement EJB Business-Specific Interfaces (bean class) • Any business-specific interfaces (usually in session beans) and any supporting helper and utility classes. Development Steps Create Client Remote Interfaces • (component interface) • remote interface for your EJBs that define all of the business-specific interfaces (usually session beans) Create Client Home Interfaces • (home interface) • Home interface for your EJB that defines application-specific methods for creating your EJB as well as for finding your entinty EJBs. Development Steps Compile EJB Code • Compile: EJB implementation, home interface, remote interface. Deployment Descriptor • create for deployment of your EJBs • specifies: • EJB type, transaction attributes, security attributes. • ejb-jar.xml Development Steps Application Deployment Descriptor • May be Optional, but, if grouped into modules will need (i.e. sun-ejb-jar.xml) Development Steps Package EJBs into EJB Jar module • * May be Optional but, a good idea. Application Deployment Descriptor • May be Optional, but, if grouped into modules will need (i.e. sun-ejb-jar.xml) Development Steps Package EJB Modules into one J2EE EAR Application • May be Optional but, good idea when have multiple modules Deploy the Application • Deploy to container using descriptor(s). Alternative Deployment Can Deploy as part of a Web Application – with other items like Servlets, etc. Enterprise beans often provide the business logic of a web application….hence packaging them within the web application's WAR (web application archive) module simplifies deployment and application organization. Enterprise beans may be packaged within a WAR module as Java programming language class files or within a JAR file that is bundled within the WAR module. To include enterprise bean class files in a WAR module, the class files should be in the WEB-INF/classes directory. To include a JAR file that contains enterprise beans in a WAR module, add the JAR to the WEB-INF/lib directory of the WAR module. Glashfish Server and EJB and other code Deployment Descriptor Container Specific Descriptor EAR files option Tools to Deploy Use container provided Tools Sometimes can deploy from IDEs and other tools Example for Glashfish: Administration Console (container) The asadmin Utility (container) Ant Utility (container) NetBeans IDE Eclipse IDE (In addition to the bundled NetBeans IDE, a plug-in for the Eclipse IDE extends GlassFish to the Eclipse community. To download, see https://glassfishplugins.dev.java.net/.) JSR 88 Client Client Code – using an EJB 1. Grab Context object that acts as a "handle" to the EJB Container (use JNDI service) see here for details Using JNDI to lookup EJB on same J2EE app the initial context factory used is ApplicationClientInitialContextFactory. References to the remote objects that are part of the application are specified in application-client.xml and orion-application-client.xml files located in Meta-Inf directory of the application ear file. The context factory reads these files when accessing the remote object. The reference to the EJB object in application-client.xml file is specified like this Using the ApplicationClientInitialContextFactory to construct JNDI initial contexts allows the client to look up local objects (objects contained in the immediate application, or in its parent application) using the java:comp/env mechanism. Remote objects can be looked up using ORMI. Using JNDI to lookup EJB on same J2EE app //Code to look up an EJB object is part of the same J2EE application import java.sql.Connection; import javax.naming.InitialContext; import javax.naming.Context; import javax.sql.DataSource; //Note :This code assumes EJBHomeInterface and EJBRemoteInterface already exist public class Code1{ public Code1(){ Hashtable env = new Hashtable(); // set the environment properties.. Yours will be different env.put(Context.INITIAL_CONTEXT_FACTORY,"com.evermind.server.ApplicationClientInitialContextFactory"); env.put(Context.PROVIDER_URL, "ormi:///ejbsample"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); try { // create an initial context using the above environment properties Context context = new InitialContext(env); EJBRemoteInterface ejbObject; // Perform look up using JNDI name of ejb object Object boundObject = context.lookup("ObjectName"); //this should be name of EJB object // Narrow the reference of the object returned by lookup() method EJBHomeInterface homeInterface = (EJBHomeInterface)PortableRemoteObject.narrow( boundObject, EJBHomeInterface.class); // create an EJB instance ejbObject =homeInterface.create(); } catch (NamingException e) { System.out.println(e.toString()); } }} Client Code – usng JNDI to lookup EJB not in same application Sometimes the application might need to use an object that is part of another J2EE application. It is also possible that the EJB object is a part of current application but the reference to the resource objects cannot be specified or is not specified in the current application's applicationclient.xml file. In such cases, RMIInitialContextFactory is used for creating the initial context . Here is the code to use RMIInitialContextFactory and obtain EJB instance. Client Code – using JNDI to bind import java.util.*; import java.rmi.*; import java.io.*; import javax.naming.* import.javax.ejb.*; //this client demonstrates use of JNDI public class Client{ public static InitialContext ctx; public static void main(String[] argv) { try{ print("Conneting to a JNDI service ...."); ctx = new InitialContext(); System.out.print("connected successfully"); //add binding String name = "mary"; String email="mary@fun.com"; ctx.bind(name, email); //lookup binding String s = (String) ctx.lookup("mary"); print(s); //delete binding ctx.unbind("mary"); //close ctx.close(); }catch(CommunicationException e) { //failed to connect} Client Code – using an EJB 1. Grab Context object that acts as a "handle" to the EJB Container (use JNDI service) 2. Use the Context Object to create an instance of the EJB Home Interface (A) by looking up the EJB Component you are looking for. see here for details see here for details EJBHomeInterface A = ctx.lookup(".../EJBHomeInterface"); 3. Create instance of Component Message Driven Beans.. Message-driven Beans A message-driven bean (MDB) is • An asynchronous message consumer • A MessageListener object on a JMS destination • Invoked by the container as a result of the arrival of JMS message A message-driven bean has no conversational state A message-driven bean is anonymous EJB 3.* : Message Driven Beans (MDBs) Just implements MessageListener Annotation declares as MDB @MessageDriven( activationConfig={ActivationConfigProperty(name=“destination”, value=“queue/email”)}) public class EmailBean implements MessageListener { void onMessage(Message msg) { //whatever code you want } } Read online for more about Message Driven Beans Message Driven Beans – another example import javax.ejb.*; import javax.jms.*; @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName=“destinationType”, propertyValue=“javax.jms.Topic”) }) public class NewsletterMailer implements MessageListener { // This method is declared in MessageListener (a JMS interface) public void onMessage(Message msg) { try { if (msg instance of ObjectMessage) { ObjectMessage objMessage = (ObjectMessage)msg; NewsLetter newsletter = (NewsLetter)msg.getObject() String content = newsletter.getContent(); // send ‘content’ via E-Mail to the newsletter’s subscribers } } catch (Exception e) { e.printStackTrace(); } } } The @MessageDriven annotation marks this class as a MDB In this case, the MDB will receive events from a topic (i.e. publish/subscribe type), as opposed to javax.jms.Queue (i.e. point-to-point message type) Here, an ObjectMessage is sent, which contains a Java object MDB: The Client (JMS) import javax.jms.*; public class NewsletterClient { @Resource(mappedName="jms/NewMessageFactory") private ConnectionFactory connectionFactory; @Resource(mappedName="jms/NewMessage") private Queue queue; public void sendNewsLetter(String content) { NewsLetter newsletter = new NewsLetter(content); try { Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(queue); ObjectMessage objMessage = session.createObjectMessage(); objMessage.setObject(newsletter); messageProducer.send(objMessage); messageProducer.close(); } catch (Exception e) { e.printStackTrace(); } } } The client merely constructs an ObjectMessage, passing it the Newsletter object, and sends (publishes) it to the message topic This code is entirely JMS (not EJB at all) • It is also possible to send the message using another JMS-compatible messaging system (e.g. IBM WebSphere MQ), using their own API Entity Beans.. Entity Beans Used to encapsulate some data contained in the enterprise system. Such data may be created, removed or found by clients. Have special primary key classes defined for them that relate to primary keys of an associated entity stored in a database. Typically do not directly interface between clients to Entity beans but through middleware of a session bean. best practice: use if multiple clients can access bean and state needs to be persistent. An Entity Bean represents a part of an application. • A customer name, checking account, etc. Entity Beans model real-world objects that are persistent. It is useful to think of an Entity Bean as a representation of a row in a database. Entity Bean Features Entity Beans are transactional. • Changes to their persistent scope occurs inside a transactional scope. • The deployer can specifically turn this off. • Transactions are distributed. Entity Beans can be accessed by multiple users at the same time. Entity Beans are persistent. • They survive server crashes transparently to the client. Entity EJBs: 2 kinds Container Managed container provides code to deal with insert, delete, query, update of database. Rely on deployment descriptor to map EBJ class fields to columns (keys) of database table. It then generates the SQL as necessary. Bean Managed the bean itself has code to deal with the insert, deletion, querying and update of data to the relation data source. The details See class materials, reading and api for details on how to create EJBs Is a form of distributed computing and sits on Java’s RMI framework. More Annotations @Resource • Connection factories, env entries, • UserTransaction, EJBContext, etc. @EJB • EJB business (and home) interfaces @PersistenceContext, @PersistenceUnit • EntityManager and EntityManagerFactory @WebServiceRef • Web service references @Resource annotation @Stateless public class AccountProcessorBean implements AccountProcessor { @Resource protected SessionContext ctx; public Boolean withdraw(int accountId,Float amount) { if (!ctx.getCallerPrincipal().getName() .equals("MikeKeith")) throw new WithdrawalException( “All your money has been donated to Mike"); ... } ... } @PersistenceContext @Stateless public class AccountProcessorBean implements AccountProcessor { protected EntityManager em; public EntityManager getEntityManager() { return this.em; } @PersistenceContext(unitName="Accounts") public void setEntityManager(EntityManager em) { this.em = em; } public Boolean withdraw(int accountId,Float amount) { Account acct = em.find(Account.class, accountId); ... } ... }