session beans ejb3.0
DESCRIPTION
Session Beans EJB3.0. February 2010 – August 2010 [email protected] www.ericgerlofsma.nl. Basic Architecture of EJB3.0. Implementation Server and Client Stateless versus Stateful Remote versus Local The JNDI binding Life Cycle Interceptors Context The Annotations Deployment. - PowerPoint PPT PresentationTRANSCRIPT
Session Beans EJB3.0
February 2010 – August [email protected] www.ericgerlofsma.nl
Basic Architecture of EJB3.0• Implementation Server and Client• Stateless versus Stateful• Remote versus Local• The JNDI binding• Life Cycle• Interceptors• Context• The Annotations• Deployment
A Remote Stateless SessionBean and his interface
package efg.ejb;import javax.ejb.Stateless;
@Statelesspublic class HelloWorldBeanimplements HelloWorld{ public String sayHello() { return "HelloWorld!"; }}
package efg.ejb;import javax.ejb.Remote;
@Remotepublic interface HelloWorld{ String sayHello();}
implements
This is the Remote Interface
This is the Remote EJB
Directory Structure
HelloWorld├─jar│ └─efg│ └─ejb│ ├─HelloWorld.class│ └─HelloWorldBean.class├─src│ ├─HelloWorld.java│ └─HelloWorldBean.java└─build.xml
Deployment build.xml<project name="efg_ejb3_stateless_helloworld" basedir="." default="jar" >
<property environment="env"/> <property name="jboss.home" value="${env.JBOSS_HOME}"/> <property name="jboss.server" value="${jboss.home}/server/default"/> <property name="jboss.deploy" value="${jboss.server}/deploy"/> <property name="app" value="${ant.project.name}.jar"/>
<path id="j2ee"> <fileset dir="${jboss.home}/client"> <include name="**/*.jar"/> </fileset> </path>
<target name="compile"> <javac srcdir="src" destdir="jar" deprecation="on"> <include name="**/*.java" /> <classpath refid="j2ee"/> </javac> </target>
<target name="jar" depends="compile"> <jar destfile="${app}" basedir="jar"/> <move file="${app}" todir="${jboss.deploy}"/> </target>
</project>
JNDI binding1. startup browser2. http://Localhost:8080 3. JMX Console4. jboss service=JNDIView5. invoke list() and see:
Global JNDI Namespace with:+- HelloWorldBean (class: org.jnp.interfaces.NamingContext) +- remote (class: Proxy for: efg.ejb.HelloWorld) +- remote-efg.ejb.HelloWorld (class: Proxy for: efg.ejb.HelloWorld)
java:comp namespace of the component jboss.j2ee:jar=efg_ejb3_stateless_helloworld.jar ,name=HelloWorldBean ,service=EJB3 :
+- EJBContext (class: javax.ejb.EJBContext) +- TransactionSynchronizationRegistry[link -> java:TransactionSynchronizationRegistry] (class: javax.naming.LinkRef) +- UserTransaction (class: org.jboss.ejb3.tx.UserTransactionImpl) +- env (class: org.jnp.interfaces.NamingContext) +- ORB[link -> java:/JBossCorbaORB] (class: javax.naming.LinkRef)
Client, lookup, cast, callpackage efg.ejb;import javax.naming.InitialContext;
public class Main{ public static void main(String[] args) throws Exception { InitialContext ctx = new InitialContext(); HelloWorld helloWorld = (HelloWorld)ctx.lookup("HelloWorldBean/remote"); System.out.println(helloWorld.sayHello()); }}
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactoryjava.naming.provider.url=jnp://localhost:1099
jndi.properties
Client Directory Structure
client├─efg│ └─efg│ └─ejb│ ├─HelloWorld.class│ └─Main.class├─src│ ├─HelloWorld.java│ └─Main.java├─log4j.xml├─jndi.properties└─build.xml
Deployment build.xml(only for TextPad not for Eclips)
<project name="HelloWorldClient" basedir="." default="exec" >
<property environment="env"/> <property name="jboss.home" value="${env.JBOSS_HOME}"/> <property name="jboss.server" value="${jboss.home}/server/default"/>
<path id="j2ee"> <pathelement path="."/> <fileset dir="${jboss.home}/client"> <include name="**/*.jar"/> </fileset> <fileset dir="${jboss.home}/lib"> <include name="**/*.jar"/> </fileset> </path>
<target name="compile"> <javac srcdir="src" destdir="."> <include name="**/*.java" /> <classpath refid="j2ee"/> </javac> </target>
<target name="exec" depends="compile"> <java classname="efg.ejb.Main" fork="false"> <classpath refid="j2ee"/> </java> </target>
</project>
Client, lookup, no interfacepackage efg.ejb;import java.lang.reflect.Method;import javax.naming.InitialContext;
public class Main{ public static void main(String[] args) throws Exception { String sayHello = "sayHello"; InitialContext ctx = new InitialContext(); Object helloWorld = ctx.lookup("HelloWorldBean/remote"); Class[] param = {}; Method method = helloWorld.getClass().getMethod(sayHello, param); Object[] arg = {}; System.out.println(method.invoke(helloWorld, arg)); }}
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactoryjava.naming.provider.url=jnp://localhost:1099
jndi.properties
Changing the JNDI-Name@Stateless(mappedName="ejb/HelloWorld/mappedName", name="ejb/HelloWorld/name")
+- ejb (class: org.jnp.interfaces.NamingContext) | +- HelloWorld (class: org.jnp.interfaces.NamingContext) | | +- name (class: org.jnp.interfaces.NamingContext) | | | +- remote-efg.ejb.HelloWorld (class: Proxy for: efg.ejb.HelloWorld)| | +- mappedName (class: Proxy for: efg.ejb.HelloWorld)
Life cycle Stateless SessionBean?
Does Not Exist
Method Ready Pool
Class.newinstance()injections@PostConstruct
@PreDestroy
business methods
Showing the Life cycle
/*****************************************************************\ Life Cycle Methods \*****************************************************************/ @PostConstruct public void postConstruct() { System.out.println("("+id+")HelloWorldBean.postConstruct()"); }
@PreDestroy public void preDestroy() { System.out.println("("+id+")HelloWorldBean.preDestroy()"); }
Interceptors for special jobs(1)package efg.ejb;
import javax.ejb.Stateless;import javax.interceptor.Interceptors;
@Stateless@Interceptors(MyInterceptor.class)public class HelloWorldBeanimplements HelloWorld{ . . .}
Class-declared-Interceptors are invoked, instead of calling a business method.
An Interceptor gets the responsibility ofcalling the next entry in the interceptor chain.Finally the business method is called.
Before and after the call special action,like logging, checking authentication andtiming can be done.
Interceptors for special jobs(2)package efg.ejb;
import javax.interceptor.InvocationContext;import javax.interceptor.AroundInvoke;
public class MyInterceptor{ @AroundInvoke public Object test(InvocationContext invocationContext) throws Exception { . . . Object ret = invocationContext.proceed(); . . . return ret; }}
Interceptors for special jobs(3)javax.interceptor.InvocationContext
Map<String, Object> getContextData()Method getMethod()Object[] getParameters()Object getTarget()Object proceed()void setParameters(Object[] params)
Interceptors for special jobs(2)15:46:14,775 INFO [STDOUT] (0)HelloWorldBean()15:46:14,775 INFO [STDOUT] MyInterceptor()15:46:14,775 INFO [STDOUT] MyInterceptor.test([ target=efg.ejb.HelloWorldBean@1bce9a , method=public java.lang.String efg.ejb.HelloWorldBean.sayHello() , parameters=[] , contextData={} ])15:46:14,775 INFO [STDOUT] Method=public java.lang.String efg.ejb.HelloWorldBean.sayHello()15:46:14,775 INFO [STDOUT] (0)HelloWorldBean.sayHello()15:46:14,775 INFO [STDOUT] return=HelloWorld!
Injected SessionContext
@Resource private SessionContext sessionContext;
EJBContextPrincipal getCallerPrincipal()boolean isCallerInRole(String rolename)Object lookup(String name)TimerService getTimerService()boolean getRollbackOnly()void setRollbackOnly()
SessionContext
No Annotations ejb-jar.xml(1)<?xml version="1.0" encoding="UTF-8"?>
<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_0.xsd" version="3.0"> <enterprise-beans> <session> <ejb-name>HelloWorldSessionBean</ejb-name> <mapped-name>HelloWorldMappedName</mapped-name> <business-remote>efg.ejb.HelloWorld</business-remote> <ejb-class>efg.ejb.HelloWorldBean</ejb-class> <session-type>Stateless</session-type> <remove-method> <bean-method> <method-name>sayHello</method-name> </bean-method> </remove-method> <post-construct> <lifecycle-callback-method>postConstruct</lifecycle-callback-method> </post-construct> <pre-destroy> <lifecycle-callback-method>preDestroy</lifecycle-callback-method> </pre-destroy> </session> </enterprise-beans>
No Annotations ejb-jar.xml(2) <interceptors> <interceptor> <interceptor-class>efg.ejb.MyInterceptor</interceptor-class> <around-invoke> <method-name>test</method-name> </around-invoke> </interceptor> </interceptors> <assembly-descriptor> <security-role> <role-name>beheerder</role-name> </security-role> <security-role> <role-name>klant</role-name> </security-role> <method> <ejb-name>HelloWorldSessionBean</ejb-name> <method-name>sayHello</method-name> </method> </method-permission> <interceptor-binding> <ejb-name>HelloWorldSessionBean</ejb-name> <interceptor-class>efg.ejb.MyInterceptor</interceptor-class> <method> <method-name>sayHello</method-name> </method> </interceptor-binding> </assembly-descriptor></ejb-jar>
Stateless or Stateful SessionBean?
A SLSB has no state: they don’t have properties(global variables).A SLSB is thread safe: multiple clients can share the same SSB.The container instantiates a SLSB only once.The container can hold 100 SLSB’s. see server/default/conf/standardjboss.xml
A SFSB has state.A SFSB is connected to one client only.A SFSB must be destroyed if the client timed out. A SFSB needs a complex management model.Don’t use a SFSB if it is not necessary.
Life cycle Stateful SessionBean?
Does Not Exist
Method Ready Pool
Class.newinstance()injections@PostConstruct
@PreDestroy
business methods
Passive
@PrePassivate @PostActivate
timeout
Exception
Annotations• @Stateless• @Stateful• @Remote• @Local• @RemoteBinding
• @SecurityDomain• @DeclareRoles• @RolesAllowed
• @PostConstruct• @PreDestroy• @PrePassivate• @PostActivate
• @EJB• @Resource
Stateless / Stateful
package javax.ejb;
@Target(TYPE)@Retention(RUNTIME)public @interface Stateless{ String description() default ""; String mappedName() default ""; String name() default <ejb-name>;}
package javax.ejb;
@Target(TYPE)@Retention(RUNTIME)public @interface Stateful{ String description() default ""; String mappedName() default ""; String name() default <ejb-name>;}
Remote / Local
package javax.ejb;
@Target(TYPE)@Retention(RUNTIME)public @interface Remote{ Class[] value default {};}
package javax.ejb;
@Target(TYPE)@Retention(RUNTIME)public @interface Local{ Class[] value default {};}
If the SessionBean has no Remote or Local annotations and the SessionBean implements a business interface, that interface is by default a Local business interface.
A default global JNDI binding is created. <ejb-name>/remote<ejb-name>/local
Life Cycle
package javax.annotation;
@Documented@Target(METHOD)@Retention(RUNTIME)public @interface PostConstruct
package javax.annotation;
@Documented@Target(METHOD)@Retention(RUNTIME)public @interface PreDestroy
package javax.ejb;
@Target(METHOD)@Retention(RUNTIME)public @interface PostActivate
package javax.ejb;
@Target(METHOD)@Retention(RUNTIME)public @interface PrePassivate
Security
package javax.annotation.security;
@Documented@Target(TYPE)@Retention(RUNTIME)public @interface DeclareRoles
package javax.annotation.security;
@Documented@Target(TYPE, METHOD)@Retention(RUNTIME)public @interface RolesAllowed
EJB reference
package javax.ejb;
@Target(TYPE, METHOD, FIELD)@Retention(RUNTIME)public @interface EJB{ String description default ””; Class beanInterface default Object.class; String beanName default ””; String mappedName default ””; String name default ””;}
If mappedName is used: it is the global JNDI name of the EJB you are referencing, and all other attributes are ignored.
If beanName is used: the container searches for the beanName as <ejb-link> , and all other attributes are ignored.
If no attributes are used: the container searches for the declarated bean interface, and throws an Exception if duplicates are found.
Resource reference
package javax.annotation;
@Target(TYPE, METHOD, FIELD)@Retention(RUNTIME)public @interface Resource{ String description default ””; Class type default Object.class; String name default ””; String mappedName default ””; boolean sharable default true; Resource.AuthenticationType authentication default CONTAINER;}
Questions
1. The interface HelloWorld in the client is a copy of the HelloWorld interface in the Server. Is it still the same interface if the packages are different? Is it still the same interface if the classnames are different?
2. A session bean has a local interface. Why is this session bean unreachable from the outside?