The main purpose of this post is to deploy an ejb remote in JBoss and connect from a static main Test - from the 'outside'.
And a the secondary goal is to present the maven structure I use in my projects.
Steps 1..9 :
1. Define application user on JBoss
Use the add-user.sh utility : https://docs.jboss.org/author/display/AS71/add-user+utility2. Install a JBoss server plugin in your IDE
JBoss developer studio is not a bad thing : http://www.jboss.org/tools3. Start with a maven project / modules structure
I would recomand this design :A parent pom project hosting
- api module (interfaces)
- war module depending on api module.
NOTE :
You must add JEE6 api on parent level or on war level :
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0-4</version>
<scope>provided</scope>
</dependency>
and see here after point 7. note2 why you should NOT add the 'original' javax jee6 api dependency.
4. Define the remote interface within the api module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface IRecipeService{ | |
public RecipeRef findByPk(long pk); | |
public Recipe prepare(long pk, int count); | |
} | |
5. Implement the Stateless within the war module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Stateless | |
@Remote(IRecipeService.class) | |
public class RecipeServiceBean implements IRecipeService { | |
public RecipeRef findByPk(long pk) { | |
RecipeRef r = new RecipeRef(); | |
r.setPk(1); | |
r.setName("Georgetown Cupkcake recipe"); | |
return r; | |
} | |
public Recipe prepare(long pk, int count) { | |
Recipe recipe = new Recipe(findByPk(pk)); | |
recipe.setDirections("directions"); | |
return recipe; | |
} | |
} |
Just avoiding hello world pattern ;)
6. Start JBoss and check JNDI deployment log
java:global/cupcake-engine/RecipeServiceBean!ch.ectropy.cupcake.service.IRecipeService
java:app/cupcake-engine/RecipeServiceBean!ch.ectropy.cupcake.service.IRecipeService
java:module/RecipeServiceBean!ch.ectropy.cupcake.service.IRecipeService
java:jboss/exported/cupcake-engine/RecipeServiceBean!ch.ectropy.cupcake.service.IRecipeService
java:global/cupcake-engine/RecipeServiceBean
java:app/cupcake-engine/RecipeServiceBean
java:module/RecipeServiceBean
NOTE :
The java:jboss/exported prefix is our exported remote EJB.
7. Create test ejb client with correct module dependencies
You may add your test client directly within /test sources of the api module or somewhere else.This and only this dependency is necessary for a testing main class connecting to a JBoss 6.1EAP AS:
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-ejb-client-bom</artifactId>
<version>7.2.0.Final</version>
<type>pom</type>
<scope>test</scope>
</dependency>
NOTE 1 : For JBoss 7.1.1 "Brontes" - use
<version>7.1.0.Final</version>
NOTE 2 : KICK OUT any dependancy on
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
WHY : This will cause errors on client side like:
ClassFormatError: Absent Code attribute in method that is not native or abstract in class..
8. Create some static main Test class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void main(String[] args) throws Exception { | |
// lookup string : without java:jboss/exported/ | |
String ls = "/cupcake-engine/RecipeServiceBean!ch.ectropy.cupcake.service.IRecipeService"; | |
final Hashtable<Object, Object> jndiProperties = new Hashtable<Object, Object>(); | |
jndiProperties.put(InitialContext.INITIAL_CONTEXT_FACTORY, | |
"org.jboss.naming.remote.client.InitialContextFactory"); | |
jndiProperties.put(InitialContext.PROVIDER_URL, | |
"remote://localhost:4447"); | |
jndiProperties.put("jboss.naming.client.ejb.context", true); | |
jndiProperties.put(InitialContext.SECURITY_PRINCIPAL, | |
"user"); | |
jndiProperties.put(InitialContext.SECURITY_CREDENTIALS, | |
"password"); | |
final Context context = new InitialContext(jndiProperties); | |
IRecipeService ri = (IRecipeService) context | |
.lookup(ls); | |
RecipeRef rr=ri.findByPk(0); | |
System.out.println("name=" + rr.getName()); | |
} | |
NOTE
This was the 'hardest' step : look at the jndi name :a. The java:jboss/exported has been truncated.
b. The lookup string is formed as followed :
<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-
interface
>
<app-name> is the ear name - here empty as we are deploying directly from a war.
<module-name> is the war name.
The resulting string begins with /cupcake-engine
Documentation
https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project9. Enjoy
janv. 14, 2014 11:29:16 PM org.xnio.Xnio <clinit>
INFO: XNIO Version 3.0.7.GA
janv. 14, 2014 11:29:16 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.0.7.GA
janv. 14, 2014 11:29:16 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 3.2.14.GA
janv. 14, 2014 11:29:16 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
janv. 14, 2014 11:29:16 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@29fdf006, receiver=Remoting connection EJB receiver [connection=Remoting connection <2222537a>,channel=jboss.ejb,nodename=hp-envy]} on channel Channel ID a2134a0c (outbound) of Remoting connection 40e09d8b to localhost/127.0.0.1:4447
name=Georgetown Cupkcake recipe