EJB3
EJB3 Examples für Glassfish 2.x. Für Classpathsettings der Clients siehe Glassfish.
Contents
Stateless Session Bean
Bemerkungen:
- Standalone Clients können die @EJB Annotation nicht verwenden.
- Der Defaultname fürs Remote Interface im JNDI ist full qualified class name of remote interface. In dem Fall also learningejb.SimpleSessionBeanRemote.
- Siehe http://wiki.netbeans.org/CreatingEJB3UsingNetbeansAndGlassfish
- Der Port für ORB kann in der Adminkonsole nachgeschaut werden. IIOP Zielgeräte.
Bean
package learningejb;
import javax.ejb.Stateless;
@Stateless
public class SimpleSessionBeanBean implements SimpleSessionBeanRemote, SimpleSessionBeanLocal {
public void helloWorld(final String inputtext) {
System.out.printf("Hello World");
}
}
Remote
package learningejb;
import javax.ejb.Remote;
@Remote
public interface SimpleSessionBeanRemote {
void helloWorld(final String inputtext);
}
Local
package learningejb;
import javax.ejb.Local;
@Local
public interface SimpleSessionBeanLocal {
}
Client
package learningejb3;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import learningejb.SimpleSessionBeanRemote;
public class Main {
public static void main(String[] args) {
System.out.println("Starting application");
try {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3712");
InitialContext ctx = new InitialContext(props);
SimpleSessionBeanRemote testEJB = (SimpleSessionBeanRemote) ctx.lookup("learningejb.SimpleSessionBeanRemote");
testEJB.helloWorld("hello");
} catch (NamingException nex) {
nex.printStackTrace();
}
}
}
Message Driven Bean
message driven bean
package learningejb;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(mappedName = "mydestination", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class MyMessageConsumerBean implements MessageListener {
public MyMessageConsumerBean() {
}
public void onMessage(Message message) {
System.out.println("Hello from message");
if(message instanceof TextMessage){
TextMessage tm = (TextMessage) message;
try {
System.out.println(tm.getText());
} catch (JMSException ex) {
ex.printStackTrace();
}
}
}
}
standalone client, message producer
Folgende Klasse verschickt eine Message an eine Queue. Es ist eine standalone Applikation, resource injection ist daher nicht möglich:
package scbcdjmsclient;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Main {
public static void main(String[] args) {
System.out.println("Starting application");
try {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3712");
InitialContext ctx = new InitialContext(props);
QueueConnectionFactory connectionFactory = (QueueConnectionFactory) ctx.lookup("myconnectionfactory");
Queue queue = (Queue) ctx.lookup("mydestination");
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer procucer = session.createProducer(queue);
TextMessage message = session.createTextMessage("a text message hello world");
procucer.send(message);
}
catch(JMSException jmsex){
jmsex.printStackTrace();
}
catch (NamingException nex) {
nex.printStackTrace();
}
}
}
ejb3 message procucer
Anbei ein EJB3, welches Messages verschickt.
package learningejb;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.jms.TextMessage;
@Stateless
public class SimpleSessionBeanBean implements SimpleSessionBeanRemote {
@Resource(mappedName = "mydestination")
Queue queue;
@Resource(mappedName = "myconnectionfactory")
QueueConnectionFactory connectionFactory;
public void helloWorld(String inputtext) {
try {
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer procucer = session.createProducer(queue);
TextMessage message = session.createTextMessage("a text message hello world");
procucer.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Annotationless example
bean
package learningejb;
import javax.jms.Message;
import javax.jms.MessageListener;
public class MessageDriven2 implements MessageListener {
public void onMessage(Message message) {
System.out.println("message received !!!!!");
}
}
ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<message-driven>
<ejb-name>mymessagedrivenbean2</ejb-name>
<mapped-name>mydestination</mapped-name>
<ejb-class>learningejb.MessageDriven2</ejb-class>
<!-- message-destination-link>mydestname</message-destination-link -->
<message-destination-type>javax.jms.Queue</message-destination-type>
<activation-config>
<activation-config-property>
<activation-config-property-name>acknowledgeMode</activation-config-property-name>
<activation-config-property-value>Auto-acknowledge</activation-config-property-value>
</activation-config-property>
</activation-config>
</message-driven>
</enterprise-beans>
<assembly-descriptor>
<!-- nicht benutzt bei diesem Beispiel, nur zum Zeigen
<message-destination>
<message-destination-name>mydestname</message-destination-name>
<mapped-name>mydestination</mapped-name>
</message-destination>
-->
</assembly-descriptor>
</ejb-jar>
activation-config-properties
In diesem Abschnitt werden die Activation-Config-Properties beschrieben.
messageSelector
Mit dem Selector können Messages ausgewählt werden, welche von diesem Bean verarbeitet werden. Beispiel:
JMSType = 'car' AND color = 'blue' AND weight > 2500
destinationType
Mögiche Werte sind javax.jms.Topic und javax.jms.Queue.
subscriptionDurability
Mögliche Werte sind Durable und NonDurable
acknowledgeMode
Mögliche Werte sind AUTO_ACKNOWLEDGE und DUPS_OK_ACKNOWLEDGE.
Timer Services
remote
package learningejb;
import javax.ejb.Remote;
@Remote
public interface TimerExampleRemote {
public void startTimer();
}
beanclass
Dieses Beispiel kreiert einen Intervall-Timer.
package learningejb;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
@Stateless
public class TimerExampleBean implements TimerExampleRemote {
@Resource
TimerService timerService;
@Timeout
public void timeOut(Timer timer)
{
System.out.println("Hello from timer");
}
//remote method impl
public void startTimer(){
this.timerService.createTimer(2000, 3000, "some info");
}
}
Security
Standalone EJB3 Client mit Authentication
Main Klasse mit Login:
package learningejb3;
import com.sun.appserv.security.ProgrammaticLogin;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import learningejb.SecuredRemote;
public class Main {
public static void main(String[] args) {
System.out.println("Starting application");
try {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3712");
ProgrammaticLogin programmaticLogin = new ProgrammaticLogin();
if(programmaticLogin.login("claude","claude") == false){
System.out.println("login failed");
}
InitialContext ctx = new InitialContext(props);
SecuredRemote testEJB = (SecuredRemote) ctx.lookup("learningejb.SecuredRemote");
testEJB.sayHello();
} catch (NamingException nex) {
nex.printStackTrace();
}
}
}
appclientlogin.conf:
default { com.sun.enterprise.security.auth.login.ClientPasswordLoginModule required debug=true; }; certificate { com.sun.enterprise.security.auth.login.ClientCertificateLoginModule required debug=true; };
Startupargumente:
-Djava.security.auth.login.config=appclientlogin.conf
secured bean mit annotationen
package learningejb;
import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
@Stateless
@DeclareRoles("role1")
@RolesAllowed("role1")
public class SecuredBean implements SecuredRemote {
@Resource
EJBContext context;
public void sayHello() {
System.out.println("Say hello from secured bean!");
System.out.println("principal:" + context.getCallerPrincipal().getName());
}
}
Zuordnung von Rollennamen im Code zu Security-Roles
package learningejb;
import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
@Stateless(name="SecuredBeanName", mappedName="SecuredBeanNameJNDI")
@DeclareRoles({"role1"})
public class SecuredBean implements SecuredRemote {
@Resource
EJBContext context;
@EJB
InnerLocal innerlocal;
@RolesAllowed("role1")
public void sayHello() {
System.out.println("role1: " + context.isCallerInRole("role1")); //true if caller is assigned role1
System.out.println("localrole: " + context.isCallerInRole("localrole")); //true if caller is assigned role1
}
}
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<session>
<ejb-name>SecuredBeanName</ejb-name>
<security-role-ref>
<role-name>localrole</role-name>
<role-link>role1</role-link>
</security-role-ref>
</session>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>role1</role-name>
</security-role>
</assembly-descriptor>
</ejb-jar>
Annotationless
Beispiel ohne Annotationen.
Bean
package learningejb;
import javax.interceptor.InvocationContext;
public class DescriptorBean implements DescriptionBeanRemote {
public void sayHello(String astring){
System.out.println("Say hello:" + astring);
}
public Object myaroundInvoke(InvocationContext invocationContext) throws Exception {
System.out.println("In aroundInvoke");
return invocationContext.proceed();
}
}
Remote
package learningejb;
public interface DescriptionBeanRemote {
public void sayHello(String astring);
}
ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<session>
<description>a sample</description>
<display-name>a displayed name</display-name>
<ejb-name>ASimpleSessionBean</ejb-name>
<business-remote>learningejb.DescriptionBeanRemote</business-remote>
<ejb-class>learningejb.DescriptorBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<around-invoke>
<method-name>myaroundInvoke</method-name>
</around-invoke>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<description>Transaction for requires new</description>
<method>
<ejb-name>ASimpleSessionBean</ejb-name>
<method-intf>Remote</method-intf>
<method-name>sayHello</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
Interceptors
Interceptor
package learningejb;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class MyInterceptor {
@AroundInvoke
public Object myaroundInvoke(InvocationContext invocationContext) throws Exception {
System.out.println("In aroundInvoke");
return invocationContext.proceed();
}
}
Bean
package learningejb;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
@Stateless
@Interceptors(MyInterceptor.class)
public class SimpleSessionBeanBean implements SimpleSessionBeanRemote, SimpleSessionBeanLocal {
public void helloWorld(final String inputtext) {
System.out.printf("Hello World");
}
}
Annotationless sample
Will man auf Annotationen verzichten, dann ejb-jar.xml verwenden. Beispiel erstellt einen default interceptor.
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<session>
<description>a sample</description>
<display-name>a displayed name</display-name>
<ejb-name>ASimpleSessionBean</ejb-name>
<business-remote>learningejb.DescriptionBeanRemote</business-remote>
<ejb-class>learningejb.DescriptorBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<around-invoke>
<method-name>myaroundInvoke</method-name>
</around-invoke>
</session>
</enterprise-beans>
<interceptors>
<interceptor>
<interceptor-class>learningejb.DefaultInterceptor</interceptor-class>
<around-invoke>
<method-name>myaroundInvoke</method-name>
</around-invoke>
</interceptor>
</interceptors>
<assembly-descriptor>
<container-transaction>
<description>Transaction for requires new</description>
<method>
<ejb-name>ASimpleSessionBean</ejb-name>
<method-intf>Remote</method-intf>
<method-name>sayHello</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>learningejb.DefaultInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>
simple environment entries
injection with annotations
bean
package learningejb;
import javax.annotation.Resource;
import javax.ejb.Stateless;
@Stateless
public class SimpleSessionBeanBean implements SimpleSessionBeanRemote {
@Resource
private int myvalue1;
public void helloWorld(String inputtext) {
System.out.println("myvalue1:" + myvalue1);
}
}
descirptor
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<session>
<ejb-name>SimpleSessionBeanBean</ejb-name>
<env-entry>
<env-entry-name>learningejb.SimpleSessionBeanBean/myvalue1</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>888</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
</ejb-jar>
injection with descriptor
bean
package learningejb;
import javax.ejb.Stateless;
@Stateless
public class SimpleSessionBeanBean implements SimpleSessionBeanRemote {
private int myvalue1;
public void helloWorld(String inputtext) {
System.out.println("myvalue1:" + myvalue1);
}
}
descriptor
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<session>
<ejb-name>SimpleSessionBeanBean</ejb-name>
<env-entry>
<env-entry-name>learningejb.SimpleSessionBeanBean/myvalue1</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>888</env-entry-value>
<injection-target>
<injection-target-class>learningejb.SimpleSessionBeanBean</injection-target-class>
<injection-target-name>myvalue1</injection-target-name>
</injection-target>
</env-entry>
</session>
</enterprise-beans>
</ejb-jar>
ejb ref
ejb-ref in descriptor
Bean
package learningejb;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
@Stateless
public class SimpleSessionBeanBean implements SimpleSessionBeanRemote {
private int myvalue1;
private SecuredLocal reftoother;
@RolesAllowed("role1")
public void helloWorld(String inputtext) {
System.out.println("myvalue1:" + myvalue1);
reftoother.sayHello();
}
}
descriptor
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns = "http://java.sun.com/xml/ns/javaee"
version = "3.0"
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">
<enterprise-beans>
<session>
<ejb-name>SimpleSessionBeanBean</ejb-name>
<env-entry>
<env-entry-name>learningejb.SimpleSessionBeanBean/myvalue1</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>888</env-entry-value>
<injection-target>
<injection-target-class>learningejb.SimpleSessionBeanBean</injection-target-class>
<injection-target-name>myvalue1</injection-target-name>
</injection-target>
</env-entry>
<ejb-local-ref>
<ejb-ref-name>refbean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>learningejb.SecuredLocal</local>
<ejb-link>SecuredBeanName</ejb-link>
<injection-target>
<injection-target-class>learningejb.SimpleSessionBeanBean</injection-target-class>
<injection-target-name>reftoother</injection-target-name>
</injection-target>
</ejb-local-ref>
</session>
<session>
<ejb-name>SecuredBeanName</ejb-name>
<env-entry>
<env-entry-name>learningejb.SecuredBean/myvalue1</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>888</env-entry-value>
</env-entry>
<security-role-ref>
<role-name>localrole</role-name>
<role-link>role1</role-link>
</security-role-ref>
</session>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>role1</role-name>
</security-role>
</assembly-descriptor>
</ejb-jar>
exceptions
Applicationexception Example. JEE unterscheidet zwischen System und Application-Exceptions.
package learningejb;
import javax.ejb.ApplicationException;
@ApplicationException(rollback=true)
public class MyAppEx extends RuntimeException {
}
Webservice Endpoint, JAX-WS
Die WSDL URL kann in der Amdministratorkonsole von Glassfish nachgeschaut werden.
Beispiel 1, simple
package learningejb;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;
@WebService
@Stateless
public class SimpleSessionBeanBean {
@Resource
WebServiceContext webserviceContext;
@WebMethod
public void aWebMethod(final String hello)
{
System.out.println("Hello from webmethod");
}
}
Transactions
Transactionattributes
Requires
If the client is running within a transaction and invokes the enterprise bean’s method, the method executes within the client’s transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method. The Required attribute is the implicit transaction attribute for all enterprise bean methods running with container-managed transaction demarcation. You typically do not set the Required attribute unless you need to override another transaction attribute. Because transaction attributes are declarative, you can easily change them later.
RequiresNew
If the client is running within a transaction and invokes the enterprise bean’s method, the container takes the following steps: 1. Suspends the client’s transaction 2. Starts a new transaction 3. Delegates the call to the method 4. Resumes the client’s transaction after the method completes
Mandatory
If the client is running within a transaction and invokes the enterprise bean’s method, the method executes within the client’s transaction. If the client is not associated with a transaction, the container throws the TransactionRequiredException.
Not supported
If the client is running within a transaction and invokes the enterprise bean’s method, the container suspends the client’s transaction before invoking the method. After the method has completed, the container resumes the client’s transaction. If the client is not associated with a transaction, the container does not start a new transaction before running the method. Use the NotSupported attribute for methods that don’t need transactions. Because transactions involve overhead, this attribute may improve performance.
Supports
If the client is running within a transaction and invokes the enterprise bean’s method, the method executes within the client’s transaction. If the client is not associated with a transaction, the container does not start a new transaction before running the method. Because the transactional behavior of the method may vary, you should use the Supports attribute with caution.
Never
If the client is running within a transaction and invokes the enterprise bean’s method, the container throws a RemoteException. If the client is not associated with a transaction, the container does not start a new transaction before running the method.