Hi,

Until “JBoss AS7.1.0 CR1b” We saw a very combersome way of looking up an EJB from a remote client. But based on the demand of the community guys Now the “JBoss AS 7.1.0.Final” provides a very easy way of invoking the EJBs remotely from the client side.

We discussed the previous option of looking up EJB remotely till “JBoss AS7.1.0 CR1b” as described in the following link: “Minimum Jars Required for Client app to remotely Invoke EJBs in JBoss AS7”

.
.

What’s New in JBoss AS7.1.0.Final?

In this article we are going to see an Easiest way to lookup the EJBs remotely in >”JBoss AS7.1.0.Final”

Point-1). JBoss AS7.1.0.Final provides a new Jar file for the Client side in order to perform remote lookup’s of JMS and EJB components “jboss-as-7.1.0.Final/bin/client/jboss-client-7.1.0.Final.jar”. This jar should be used with standalone clients only, not with deployments are that deployed to an AS7 instance.

Point-2). What will be the syntax of the JNDI name while invoking a Stateless SessionBean?
For Stateless EJBs Beans JNDI Naming will be in following format:

                 .
<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>
                 .

Example: “TestRemoteEJBEAR/remoteEJB//CallerBean!remote.CallerRemote”

Point-3). On the client side we will need to use a new Protocul “remote://” as following:

.

  String JBOSS_CONTEXT="org.jboss.naming.remote.client.InitialContextFactory";;
  Properties props = new Properties();
  props.put(Context.INITIAL_CONTEXT_FACTORY, JBOSS_CONTEXT);
  props.put(Context.PROVIDER_URL, "remote://localhost:4447"); 
  props.put(Context.SECURITY_PRINCIPAL, "testuser");
  props.put(Context.SECURITY_CREDENTIALS, "testpassword");
  context = new InitialContext(props);	
.

Point-4). A properties file need to be placed in the Clients CLASSPATH with name “jboss-ejb-client.properties”

Point-5): [ IMPORTANT ] Security is the main focus now so before running “JBoss AS7.1.0.Final” we will need to create a new Application User by running “${JBOSS_HOME}/bin/add-user.sh” script as following :

[userone@localhost bin]$ ./add-user.sh 

What type of user do you wish to add? 
 a) Management User (mgmt-users.properties) 
 b) Application User (application-users.properties)
(a): b

Enter the details of the new user to add.
Realm (ApplicationRealm) :  ApplicationRealm
Username : testuser
Password : testpassword
Re-enter Password : testpassword

What roles do you want this user to belong to? (Please enter a comma separated list, or leave blank for none) : testrole
About to add user 'testuser' for realm 'ApplicationRealm'

Is this correct yes/no? yes

Added user 'testuser' to file '/home/userone/jboss-as-7.1.0.Final/standalone/configuration/application-users.properties'
Added user 'testuser' to file '/home/userone/jboss-as-7.1.0.Final/domain/configuration/application-users.properties'
Added user 'testuser' with roles testrole to file '/home/userone/jboss-as-7.1.0.Final/standalone/configuration/application-roles.properties'
Added user 'testuser' with roles testrole to file '/home/userone/jboss-as-7.1.0.Final/domain/configuration/application-roles.properties'
.
.

.
.

Source Code (Git Repo) Source Code for this Demo Can be downloaded from GIT Repository:
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/New_EJB3_Remote_Lookup

Once you have gone through the above mentioned 4- Points we can now begin writing our EJB Based application.

Developing Simple EJB3 Application

Step-1). Create a directory somewhere in your file system like “/home/userone/New_EJB3_Remote_Lookup” and then create another directory with name “src” inside the “/home/userone/New_EJB3_Remote_Lookup” directory.

Step-2). Write the EJB Stateless Bean class “CallerBean.java” as following inside the directory “/home/userone/New_EJB3_Remote_Lookup/src”:

package remote;
import javax.ejb.*;
import javax.naming.*;
import java.util.*;

@Stateless  
@Remote(CallerRemote.class)
public class CallerBean implements CallerRemote
 {
     public String testMethod(String name)
	    {
		   System.out.println("nnt Bean's testMethod(String name) called....");
		   return "[CallerBean] returned Hello "+name;
	    }
 }

Step-3). Write the EJB Remote Interface “CallerRemote.java” as following inside the directory “/home/userone/New_EJB3_Remote_Lookup/src”:

package remote;
public interface CallerRemote
{
     public String testMethod(String name);
}

Step-4). As we are going to create an EAR file containing the above Stateless Session Bean so We will write the “application.xml” as following inside the directory “/home/userone/New_EJB3_Remote_Lookup/src”:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" id="Application_ID" version="5">
  <module>
    <ejb>remoteEJB.jar</ejb>
  </module>
</application>

Developing EJB3 Remote Client

Step-5). Now we will write the Client side code to access the Above mentioned EJB Remotely so create a class “TestRemoteClientA.java” as following inside the directory “/home/userone/New_EJB3_Remote_Lookup/src”:

package client;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;
import remote.CallerRemote;
public class TestRemoteClientA
  {
      public static void main(String ar[]) throws Exception 
       {
          Context context=null;
       try
         {
                Properties props = new Properties();
                props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
                props.put(Context.PROVIDER_URL, "remote://localhost:4447"); 
                props.put(Context.SECURITY_PRINCIPAL, "testuser");
                props.put(Context.SECURITY_CREDENTIALS, "testpassword");
                context = new InitialContext(props);	
	        System.out.println("ntGot initial Context: "+context);		
         }
       catch (Exception e)
         {
                e.printStackTrace();
          }

         // Lookup Format will be 
         // <app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>
   
         CallerRemote remote=(CallerRemote)context.lookup("TestRemoteEJBEAR/remoteEJB//CallerBean!remote.CallerRemote");
         System.out.println("nt remote.testMethod("MiddlewareMagic") = "+remote.testMethod("MiddlewareMagic"));
       }
  }

Step-6). Now we will need to create a properties file “jboss-ejb-client.properties” as following inside the directory “/home/userone/New_EJB3_Remote_Lookup/src”:


remote.connections=default
endpoint.name=client-endpoint
remote.connection.default.port = 4447
remote.connection.default.host=localhost
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

NOTE: The above properties file need to be present inside the client’s classpath. In our case we are going to put this file inside a JAR file “remoteEJBClient.jar” and then we will add this JAR inside the client’s classpath.

Step-7). Now Start your JBoss Profile as following from inside the directory “/home/userone/jboss-as-7.1.0.Final/bin”:

.
 ./standalone.sh -c standalone-full.xml
.

Step-8). Now the most important part of building / deploying and running the application so in order to achieve that we will create a simple ant build script, So Create a “build.xml” file inside the “/home/userone/New_EJB3_Remote_Lookup” directory as following:

<project name="SingletonStartupService" default="all">
<property name="jboss.home" value="/home/userone/jboss-as-7.1.0.Final" />
<property name="jboss.module.dir" value="${jboss.home}/modules" />
<property name="basedir" value="." />
<property name="tmp.dir" value="tmp" />
<property name="src.dir" value="src" />
<property name="output.dir" value="build" />
<property name="ear.name" value="TestRemoteEJBEAR.ear" />
<property name="ejb.jar" value="remoteEJB.jar" />
<property name="client.jar.name" value="remoteEJBClient.jar" />

        <path id="jboss.classpath">
           <fileset dir="${jboss.module.dir}">
               <include name="**/*.jar"/>
           </fileset>  
        </path>

        <!-- Client Needs the following Jar to be present in the CLASSPATH including -->
        <path id="jboss.new.client.classpath">
           <fileset dir="${jboss.home}/bin/client">
               <include name="jboss-client-7.1.0.Final.jar" />
           </fileset>  
        </path>
	 
        <target name="all" depends="deploy" />

        <target name="build_ear">
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}" />
           <javac srcdir="${src.dir}" destdir="${tmp.dir}"  includes="*.java" classpathref="jboss.classpath"/>

           <jar jarfile="${tmp.dir}/${ejb.jar}" basedir="${tmp.dir}" compress="true" />

           <delete includeEmptyDirs="true">
              <fileset dir="${tmp.dir}/remote"/>
           </delete> 
           <mkdir dir="${tmp.dir}/META-INF"/>
           <copy todir="${tmp.dir}/META-INF">
                <fileset dir="${src.dir}/">
                  <include name="application.xml"/> 
                </fileset>
           </copy>           
           <jar jarfile="${tmp.dir}/${ear.name}" basedir="${tmp.dir}" compress="true" />
           <delete includeEmptyDirs="true">
              <fileset dir="${tmp.dir}/META-INF"/>
           </delete> 
           <delete file="${tmp.dir}/${ejb.jar}"/>

           <copy file="${tmp.dir}/${ear.name}" tofile="${output.dir}/${ear.name}"/>
           <delete file="${tmp.dir}/${ear.name}"/>
        </target>


        <target name="deploy" depends="build_ear">
            <echo message="*******************  Deploying the EAR file ${ear.name} *********************" />  
            <echo message="********** ${output.dir}/${ear.name} to ${jboss.home}/standalone/deployments **********" />  
            <copy todir="${jboss.home}/standalone/deployments/">
                <fileset dir="${output.dir}/">
                  <include name="${ear.name}"/> 
                </fileset>
            </copy>
            <echo message="*******************  Deployed Successfully   *********************" />  
        </target>


        <target name="run">
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}" />
           <copy file="${src.dir}/jboss-ejb-client.properties" toDir="${tmp.dir}"/> 

           <javac srcdir="${src.dir}" destdir="${tmp.dir}"  includes="CallerRemote.java,TestRemoteClientA.java" classpathref="jboss.classpath"/>          
           <jar jarfile="${output.dir}/${client.jar.name}" basedir="${tmp.dir}" compress="true" />
           <delete dir="${tmp.dir}"/>

           <java classname="client.TestRemoteClientA" fork="true">
               <classpath>
                  <pathelement location="${output.dir}/${client.jar.name}"/>
                  <path refid="jboss.new.client.classpath"/>
               </classpath>
           </java>
        </target>        
    
</project>

NOTE: The only change in the above file you need to do is to change the “jboss.home” directory path in the second line of the above script to point to your own JBoss AS7 directory.

Step-9). Now before running your ANT script to build and deploy the above webapplication you should have the ANT as well as JAVA set in the $PATH variable of the Shell / command prompt as following:

For Unix Based OS:
export PATH=/home/userone/jdk1.6.0_21/bin:/home/userone/org.apache.ant_1.6.5/bin:$PATH

For Windows Based OS:
set PATH=C:/jdk1.6.0_21/bin;C:/org.apache.ant_1.6.5/bin;%PATH%

Step-10). Now once the PATH is set In the command/Shell prompt you can move inside the directory “/home/userone/New_EJB3_Remote_Lookup” and then run the ant to build and deploy the EJB based EAR applicationon your JBoss Standalone full profile, by running the command “ant deploy”

[userone@localhost New_EJB3_Remote_Lookup]$ ant deploy
ant deploy
Buildfile: build.xml

build_ear:
    [mkdir] Created dir: /home/userone/New_EJB3_Remote_Lookup/tmp
    [javac] Compiling 3 source files to /home/userone/New_EJB3_Remote_Lookup/tmp
      [jar] Building jar: /home/userone/New_EJB3_Remote_Lookup/tmp/remoteEJB.jar
    [mkdir] Created dir: /home/userone/New_EJB3_Remote_Lookup/tmp/META-INF
     [copy] Copying 1 file to /home/userone/New_EJB3_Remote_Lookup/tmp/META-INF
      [jar] Building jar: /home/userone/New_EJB3_Remote_Lookup/tmp/TestRemoteEJBEAR.ear
   [delete] Deleting: /home/userone/New_EJB3_Remote_Lookup/tmp/remoteEJB.jar
     [copy] Copying 1 file to /home/userone/New_EJB3_Remote_Lookup/build
   [delete] Deleting: /home/userone/New_EJB3_Remote_Lookup/tmp/TestRemoteEJBEAR.ear

deploy:
     [echo] *******************  Deploying the EAR file TestRemoteEJBEAR.ear *********************
     [echo] ********** build/TestRemoteEJBEAR.ear to /home/userone/jboss-as-7.1.0.Final/standalone/deployments **********
     [copy] Copying 1 file to /home/userone/jboss-as-7.1.0.Final/standalone/deployments
     [echo] *******************  Deployed Successfully   *********************

BUILD SUCCESSFUL
Total time: 1 second

As soon as the EJB will be deployed on the JBoss AS7.1.0.Final you will see the following kind of output on your JBoss Console (STDOUT):

22:44:32,587 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-7) JBAS015876: Starting deployment of "TestRemoteEJBEAR.ear"
22:44:32,595 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-7) JBAS015876: Starting deployment of "remoteEJB.jar"
22:44:32,626 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named CallerBean in deployment unit subdeployment "remoteEJB.jar" of deployment "TestRemoteEJBEAR.ear" are as follows:

	java:global/TestRemoteEJBEAR/remoteEJB/CallerBean!remote.CallerRemote
	java:app/remoteEJB/CallerBean!remote.CallerRemote
	java:module/CallerBean!remote.CallerRemote
	java:jboss/exported/TestRemoteEJBEAR/remoteEJB/CallerBean!remote.CallerRemote
	java:global/TestRemoteEJBEAR/remoteEJB/CallerBean
	java:app/remoteEJB/CallerBean
	java:module/CallerBean

22:44:32,654 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 2) JBAS018565: Replaced deployment "TestRemoteEJBEAR.ear" with deployment "TestRemoteEJBEAR.ear"

Step-11). Now we will try to compile and run the EJB3 remote Client application by running the command “ant run”

[userone@localhost New_EJB3_Remote_Lookup]$ ant run
Buildfile: build.xml

run:
   [delete] Deleting directory /home/userone/New_EJB3_Remote_Lookup/tmp
    [mkdir] Created dir: /home/userone/New_EJB3_Remote_Lookup/tmp
     [copy] Copying 1 file to /home/userone/New_EJB3_Remote_Lookup/tmp
    [javac] Compiling 2 source files to /home/userone/New_EJB3_Remote_Lookup/tmp
      [jar] Building jar: /home/userone/New_EJB3_Remote_Lookup/build/remoteEJBClient.jar
   [delete] Deleting directory /home/userone/New_EJB3_Remote_Lookup/tmp
      Feb 18, 2012 10:45:52 PM org.xnio.Xnio <clinit>
      INFO: XNIO Version 3.0.3.GA
      Feb 18, 2012 10:45:52 PM org.xnio.nio.NioXnio <clinit>
      INFO: XNIO NIO Implementation Version 3.0.3.GA
      Feb 18, 2012 10:45:52 PM org.jboss.remoting3.EndpointImpl <clinit>
      INFO: JBoss Remoting version 3.2.2.GA
      
      	Got initial Context: javax.naming.InitialContext@1ebcda2d
      Feb 18, 2012 10:45:53 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
      INFO: Received server version 1 and marshalling strategies [river]
      Feb 18, 2012 10:45:53 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
      INFO: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@1309de5b, receiver=Remoting connection EJB receiver [connection=Remoting connection <30ff94b1>,channel=jboss.ejb,nodename=localhost]} on channel Channel ID 8359e77c (outbound) of Remoting connection 1fe903d5 to localhost/127.0.0.1:4447
      Feb 18, 2012 10:45:53 PM org.jboss.ejb.client.remoting.ChannelAssociation$ResponseReceiver handleMessage
      WARN: Unsupported message received with header 0xffffffff
      
      	 remote.testMethod("MiddlewareMagic") = [CallerBean] returned Hello MiddlewareMagic

BUILD SUCCESSFUL
Total time: 2 seconds

References

[1] EJB invocations from a remote client using JNDI.
[2] Remote EJB invocations via JNDI – EJB client API or remote-naming project.
[3] EJB invocations from a remote server instance.
.
.
Thanks 🙂
Middleware Magic Team

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.