The goal of this new thread is not to explain all the EJB 2 mechanisms but to share what I really missed during the migration, that is a working example of EJB2 sessions and EJB2 entities on JBoss 7.1. Since JEE 6, it is possible to package the EJB directly in a war archive, so this example will be based on that.
The source code is available here.
EJB 2 session java code
I will create an EJB 2 session called HelloWorld with a simple method returning a String object. Three classes must be created to do that :- The EJB interface
package com.jsebfranck.jboss.ejb2.session;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface HelloWorldEJB extends EJBObject {
public String helloWorld() throws RemoteException;
}
- The implementation
package com.jsebfranck.jboss.ejb2.session;
import java.rmi.RemoteException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloWorldEJBBean implements SessionBean {
private static final long serialVersionUID = 1L;
public String helloWorld() throws RemoteException {
return "Hello world, I am an EJB2 session";
}
public void ejbActivate() throws EJBException, RemoteException {}
public void ejbPassivate() throws EJBException, RemoteException {}
public void ejbRemove() throws EJBException, RemoteException {}
public void setSessionContext(SessionContext arg0) throws EJBException, RemoteException {}
}
- And the EJB Home
package com.jsebfranck.jboss.ejb2.session;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface HelloWorldEJBHome extends EJBHome {
public HelloWorldEJB create() throws RemoteException, CreateException;
}
EJB 2 entity java code
For the EJB 2 entity example, I will create an object called Member with two fields : an id and a login. Three java objects are also needed to do that :
- The EJBLocalObject
package com.jsebfranck.jboss.ejb2.entity;
import javax.ejb.EJBLocalObject;
public interface Member extends EJBLocalObject {
public Long getId();
public String getLogin();
}
- The EntityBean
package com.jsebfranck.jboss.ejb2.entity;
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
public abstract class MemberBean implements EntityBean {
private static final long serialVersionUID = 1L;
private transient EntityContext ctx;
public MemberBean() {
}
public Long ejbCreate(Long id, String login) throws CreateException {
setId(id);
setLogin(login);
return id;
}
public void ejbPostCreate(Long id, String login) {
}
public abstract Long getId();
public abstract void setId(Long id);
public abstract String getLogin();
public abstract void setLogin(String login);
public void setEntityContext(EntityContext ctx) {
this.ctx = ctx;
}
public void unsetEntityContext() {
this.ctx = null;
}
public void ejbActivate() {}
public void ejbPassivate() {}
public void ejbLoad() {}
public void ejbStore() {}
public void ejbRemove() {}
}
- And the EJBHome
package com.jsebfranck.jboss.ejb2.session;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface HelloWorldEJBHome extends EJBHome {
public HelloWorldEJB create() throws RemoteException, CreateException;
}
XML configuration
Now we have to declare the EJB entity and the EJB session in the xml configuration. A first file is needed for that, ejb-jar.xml. This file must be put in the /WEB-INF folder of the war archive.
<ejb-jar version="3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
<enterprise-beans>
<session>
<ejb-name>HelloWorldEJB</ejb-name>
<home>com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome</home>
<remote>com.jsebfranck.jboss.ejb2.session.HelloWorldEJB</remote>
<ejb-class>com.jsebfranck.jboss.ejb2.session.HelloWorldEJBBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
<entity>
<ejb-name>MemberEJB</ejb-name>
<local-home>com.jsebfranck.jboss.ejb2.entity.MemberHome</local-home>
<local>com.jsebfranck.jboss.ejb2.entity.Member</local>
<ejb-class>com.jsebfranck.jboss.ejb2.entity.MemberBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Long</prim-key-class>
<reentrant>false</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>member</abstract-schema-name>
<cmp-field>
<field-name>id</field-name>
</cmp-field>
<cmp-field>
<field-name>login</field-name>
</cmp-field>
<primkey-field>id</primkey-field>
</entity>
</enterprise-beans>
</ejb-jar>
Now let's configure the mapping of the EJB entity. This is done in the jbosscmp-jdbc.xml file which must be put in the META-INF folder of the war archive.
<jbosscmp-jdbc>
<defaults>
<datasource>java:jboss/datasources/hsqldbDS</datasource>
</defaults>
<enterprise-beans>
<entity>
<ejb-name>MemberEJB</ejb-name>
<row-locking>false</row-locking>
<table-name>simple</table-name>
<cmp-field>
<field-name>id</field-name>
<column-name>id</column-name>
</cmp-field>
<cmp-field>
<field-name>login</field-name>
<column-name>login</column-name>
</cmp-field>
</entity>
</enterprise-beans>
</jbosscmp-jdbc>
JBoss configuration
As you noticed in the jbosscmp-jdbc.xml file, a datasource is required for the entity. This datasource is configured directly in the jboss configuration. As I launch JBoss 7.1 in a standalone mode, I put the following configuration in the $JBOSS_HOME/standalone/configuration/standalone-full.xml file.In this example, a use a hsql database :
<subsystem xmlns="urn:jboss:domain:datasources:1.0">
<datasources>
<datasource enabled="true" jndi-name="java:jboss/datasources/hsqldbDS" jta="true" pool-name="hsqldbDS" use-ccm="true" use-java-context="true">
<connection-url>jdbc:hsqldb:file:/Users/jsebfranck/Documents/database/standaloneHsqldb</connection-url>
<driver>hsqldb</driver>
<pool>
<prefill>false</prefill>
<use-strict-min>false</use-strict-min>
<flush-strategy>FailingConnectionOnly</flush-strategy>
</pool>
<security>
<user-name>sa</user-name>
</security>
</datasource>
Deployment in jboss
When you deploy the web application on jboss (standalone.sh --server-config=standalone-full.xml), you can see the JNDI names of both EJB in the logs. This will help us to do our lookups in the client.
19:07:56,689 INFO [org.jboss.as.server.deployment] (MSC service thread 1-2) JBAS015876: Starting deployment of "WarWithEJB2.war"
19:07:57,069 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-4) JNDI bindings for session bean named MemberEJB in deployment unit deployment "WarWithEJB2.war" are as follows:
java:global/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.Member
java:app/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.Member
java:module/MemberEJB!com.jsebfranck.jboss.ejb2.entity.Member
java:global/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome
java:app/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome
java:module/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome
19:07:57,073 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-4) JNDI bindings for session bean named HelloWorldEJB in deployment unit deployment "WarWithEJB2.war" are as follows:
java:global/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJB
java:app/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJB
java:module/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJB
java:jboss/exported/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJB
java:global/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome
java:app/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome
java:module/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome
java:jboss/exported/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome
Simple servlet client
We are now able to test our EJBs. The following code calls the helloWorld method of the EJB session, then it creates a new line in the Member table.package com.jsebfranck.jboss.servlet;
import java.io.IOException;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jsebfranck.jboss.ejb2.entity.Member;
import com.jsebfranck.jboss.ejb2.entity.MemberHome;
import com.jsebfranck.jboss.ejb2.session.HelloWorldEJB;
import com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome;
@WebServlet("/Ejb2Servlet")
public class Ejb2Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// EJB 2 session
HelloWorldEJBHome helloWorldEJBHome = (HelloWorldEJBHome) new InitialContext().lookup("java:global/WarWithEJB2/HelloWorldEJB!com.jsebfranck.jboss.ejb2.session.HelloWorldEJBHome");
HelloWorldEJB helloWorldEjb = helloWorldEJBHome.create();
response.getWriter().println("EJB session test : " + helloWorldEjb.helloWorld());
// EJB 2 entity
MemberHome memberHome = (MemberHome) new InitialContext().lookup("java:global/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome");
Member member = memberHome.create(25L, "jsebfranck");
response.getWriter().println("EJB entity test : " + member.getId() + " - " + member.getLogin());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
And we have the prove that this example is working :-)
Hi Jean,
RépondreSupprimerThank you for the article, I've the following doubts:
1. I would like to know the list of *.jar files you've used like jboss-j2ee.jar. Also, let me know, where you placed those jar files.
2. In ejb-jar.xml, you've used EJB3.1 version by using the following tag:
In my case, I've the following tag:
Please let me know how to migrate from ejb-jar_2_0.dtd to ejb-jar_3_1.xsd. Meanwhile, I'm reading both the dtd and xsd files.
3. Also let me know the meanings of following tags in standalone-full.xml while configuring datasource:
false
false
FailingConnectionOnly
Please let me know or post some links explaining them.
Literally, you have saved lot of hours of mine by providing the example.
Thanks again,
Diesel
The tags which I've used in 2 question are
RépondreSupprimerIn ejb-jar.xml, you've used EJB3.1 version by using the following tag:
ejb-jar version="3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
In my case, I've the following tag:
DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd"
Similarly, in question 3, the tags are
pool
prefill false prefill
use-strict-min false use-strict-min
flush-strategy FailingConnectionOnly flush-strategy
pool
Hi,
RépondreSupprimerI'm glad this example will help you.
1) In this example, the generated .war file don't contain any .jar, all the needed jar are directly in jboss 7 folders.
2) I remember I tried to do the deployment with EJB 2.0 tag but it didn't work so I just change the header of the ejb-jar.xml to use the 3.1 tag. That's all I changed.
3) Configuring a datasource in jboss 7 is a large topic because it is not obvious at all. I faces a lot of difficulties to configure an oracle datasource. In this example, I just took the parameters of another example with hsql. So you should refer to JBoss documentations of further details.
Nice example to start migration from JBoss4 to JBoss7.
RépondreSupprimerDo you have any experience with auto-increment primary keys? Works fine in JBoss4 and stopped working in JBoss7.
Thanks for any advice. Dusan.
Hi Dusan,
SupprimerHow do you increment your keys? Do you use a custom generator using a database sequence? Something else?
Please note that I have published the source code here : https://github.com/jsebfranck/jee-samples.
RépondreSupprimerI tried this example and for some reason my ejb is not detected as I don't see the information below and ultimately i get the error javax.naming.NameNotFoundException..
RépondreSupprimer19:07:56,689 INFO [org.jboss.as.server.deployment] (MSC service thread 1-2) JBAS015876: Starting deployment of "WarWithEJB2.war"
19:07:57,069 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-4) JNDI bindings for session bean named MemberEJB in deployment unit deployment "WarWithEJB2.war" are as follows:
java:global/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.Member
java:app/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.Member
java:module/MemberEJB!com.jsebfranck.jboss.ejb2.entity.Member
java:global/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome
java:app/WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome
java:module/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome
Are you sure to launch your jboss server with the standalone-full configuration? --> standalone.sh --server-config=standalone-full.xml
SupprimerThanks for your reply and I actually am using Eclipse and I am using the standalone-full.xml configuration. Remember the ejbs are inside the war as you have stated and only the war is deployed. Am I missing something. Can you share your deployed war? The other question I wanted to ask is does it use the jboss-ejb-client.properties internally as stated in the link below https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI
SupprimerHi, thanks a lot for your tutorial! I'm actually facing a similar challenge: migrate an ejb 2 application (swing client) from Jboss 4 to Jboss 7.
RépondreSupprimerI was able to run your code locally, but I tried to connect the session bean using a remote client instead of a Servlet.
This is how I did:
Hashtable properties = new Hashtable();
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
properties.put(Context.PROVIDER_URL, "remote://localhost:4447");
properties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
InitialContext ic = new InitialContext(properties);
Object o = ic.lookup("ejb:j7e2/j7e2-ejb-1.0.0//HelloWorldEJB!be.mil.ejb2.session.HelloWorldEJBHome");
HelloWorldEJBHome helloWorldEJBHome = (HelloWorldEJBHome) o;
HelloWorldEJB helloWorldEjb = helloWorldEJBHome.create();
... and here comes the error: java.lang.IllegalStateException: No EJB receiver available for handling [appName:j7e2,modulename:j7e2-ejb-1.0.0,distinctname:]
I'm nearly sure about my appName/modulename as my bean deployed like this in jboss:
java:global/j7e2/j7e2-ejb-1.0.0/HelloWorldEJB!be.mil.ejb2.session.HelloWorldEJBHome
Any Idea?
Hi,When i tried this example without Entity bean then it was running properly but when i implement Entity bean logic and tried to connect my developement database(Oracle 11g) that time i am getting error like
RépondreSupprimer12:58:09,660 INFO [org.jboss.ejb.client] (http--127.0.0.1-8080-1) JBoss EJB Client version 1.0.5.Final
12:58:09,687 ERROR [stderr] (http--127.0.0.1-8080-1) javax.naming.NameNotFoundException: WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome -- service jboss.naming.context.java.global.WarWithEJB2."MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome"
12:58:09,690 ERROR [stderr] (http--127.0.0.1-8080-1) at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:97)
12:58:09,691 ERROR [stderr] (http--127.0.0.1-8080-1) at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:178)
12:58:09,692 ERROR [stderr] (http--127.0.0.1-8080-1) at org.jboss.as.naming.InitialContext.lookup(InitialContext.java:123)
12:58:09,694 ERROR [stderr] (http--127.0.0.1-8080-1) at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:214)
12:58:09,695 ERROR [stderr] (http--127.0.0.1-8080-1) at javax.naming.InitialContext.lookup(InitialContext.java:392)
12:58:09,696 ERROR [stderr] (http--127.0.0.1-8080-1) at com.jsebfranck.jboss.servlet.Ejb2Servlet.doGet(Ejb2Servlet.java:29)
12:58:09,697 ERROR [stderr] (http--127.0.0.1-8080-1) at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
12:58:09,698 ERROR [stderr] (http--127.0.0.1-8080-1) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
12:58:09,699 ERROR [stderr] (http--127.0.0.1-8080-1) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
12:58:09,716 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/WarWithEJB2].[Ejb2Servlet]] (http--127.0.0.1-8080-1) Servlet.service() for servlet Ejb2Servlet threw exception: java.lang.RuntimeException: javax.naming.NameNotFoundException: WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome -- service jboss.naming.context.java.global.WarWithEJB2."MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome"
at com.jsebfranck.jboss.servlet.Ejb2Servlet.doGet(Ejb2Servlet.java:34) [classes:]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
Caused by: javax.naming.NameNotFoundException: WarWithEJB2/MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome -- service jboss.naming.context.java.global.WarWithEJB2."MemberEJB!com.jsebfranck.jboss.ejb2.entity.MemberHome"
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:97)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:178)
at org.jboss.as.naming.InitialContext.lookup(InitialContext.java:123)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:214)
at javax.naming.InitialContext.lookup(InitialContext.java:392) [rt.jar:1.6.0_06]
at com.jsebfranck.jboss.servlet.Ejb2Servlet.doGet(Ejb2Servlet.java:29) [classes:]
... 15 more
Please help me out...
Hi, I wonder if you might have advice for me, I'm getting the error JBAS014154: Failed to marshal EJB parameters. The problem is I have a CMR relationship. When I try and pass one EJB object to the create method of another EJB method to set the relationship, it can't marshal up remote objects. This code used to work for me with some older version of jboss, so the code itself is basically sound. I think I have to do something different to not get a remote object but rather a local object so it doesn't try and marshal it. As I understand it, whenever you do a lookup on "java:global...." it gets a remote object, but I can't find out how to do a lookup and get a local object.
RépondreSupprimerCongratulations guys, quality information you have given!!!..Its really useful blog. Thanks for sharing this useful information
RépondreSupprimerjava training institutes in chennai | java j2ee training institutes in velachery
Caesars Casino Bonus Code - Aprcasino.com
RépondreSupprimerWhen you sign up at the Caesars Casino in Las Vegas, you'll be able to 카지노 사이트 가입 play games like blackjack, roulette, and more at the top of the Caesars