Why Nashorn Java Scripting in Java8, Is it Poisonous for Java? (part-1)

Hi,

Until Java SE 7, JDKs shipped with a JavaScript scripting engine based on Mozilla Rhino. Java SE 8 instead ship with a new engine called Oracle Nashorn, which is based on JSR 292 and invoke dynamic.

JDK 1.8 provides us the “$JAVA_HOME/bin/jjs” command-line tool as well as using Oracle Nashorn as an embedded scripting engine inside Java applications.

Many people do not like why JDK 8 is focusing more on the Java Scripting and why so much effort is being put on the JavaScript engine like Nashorn. Will it kill java? Introducing such features will harm java? Is it poisonous for java?

Other parts of this article an be found at:

JDK8 Based Nashorn JavaScript & Java to interact with MySQL Database. (part-2)

Server Side Java Script Nashorn, WildFly10, Undertow with MySQL (part-3)

Different people may have different opinion about it however here we will talk about how to use it and how to take benefit from it.

Why Nashorn? Any benefits/advantages?

Many people have a question in mind that why Nashorn has been introduced and What is important in it? What are the advantages of using it ?

1. Nashorn fully supports ECMAScript 5.1 specification along with some extensions, to 100% pure Java implementation and 100% complied to bytecode and not the interpreted mode as with Rhino. Simply Nashorn scripts do not need to be compiled.

2. Nashorn provides much better performance than Rhino engine.

2. Nashorn will support the javax.script (JSR 223) API. The javax.script (JSR 223) API is for calling back into JavaScript from Java.

2. It directly compiles the JavaScript code in-memory and passes the Java bytecode to the JVM, and uses invokedynamic which provides backward compatibility to JDK7 – See more at: http://www.nagarro.com/de/de/blog/post/33/Java-8-Nashorn-Engine-for-JavaScript-Interoperability-and-Performance

3. Nashorn provides a flexibility to the users that they can either programmatically use it from Java programs or they can utilize it from the command line tool “jjs” which is located in “$JAVA_HOME/bin” directory.

4. Unlike Rhino, which has its own JavaScript debugger, The Nashorn does not provide it’s own JavaScript debugger but it provides an ability to remotely debug applications using an IDE like IntelliJ IDEA 13.

5. It provides much faster execution and multi-threading of JavaScript while running in Java’s JRE.

6. Nashorn can be very easily integrated and used with JavaFX. Users can very easily interpret a JavaFX script application with Nashorn using the jjs command with the -fx option. See: http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/javafx.html

7. Nashron can help in executing the OS level commands very easily like following:

    var lines = `ls -ls`.split("\n");
    for each (var line in lines) {
       print(line);
    } 

8. With Nashorn it will support in invoking Java code from JavaScript and for Java to invoke JavaScript code.

9. So far no security risk or exposure has been identified with Nashorm.

Some simple startup demos

Lets start writing very simple javascipts statements and then execute these statements using the Nashorn and the “jjs” jjs command-line tool.
As JDK8 is needed to be present in the PATH so lets setup the environment first. Following are the steps for setting the JDK8 installation in the PATH in order to use the “jjs” utility.

Unix Based OS

export JAVA_HOME=/PATH/TO/jdk1.8.0_60
export PATH=$JAVA_HOME/bin/jjs:$PATH

Windows Based OS

set JAVA_HOME=C:\jdk1.8.0_60
set PATH=%JAVA_HOME%\bin;%PATH%

Printing messages …

Once the environment is setup we can simply use the “print” function to display some messages on the jjs tool. Just type “jjs” in the command prompt to start this utility.

$ jjs
jjs> 
jjs> print ("What's New in MiddlewareMagic ? ");
What's New in MiddlewareMagic ? 
jjs> 

print(java.lang.System.currentTimeMillis());

Running jjs in “scripting” mode

“jjs” tool provides us an option “-scripting” using this we can run the OS specific commands as well as part of our scripts. For example listing the files or copy/moving a file or directory…etc.

$ jjs
jjs> var listing = `ls -l`
ECMAScript Exception: SyntaxError: <shell>:1:14 Expected an operand but found error
var listing = `ls -l`
              ^
jjs> 

As we did not start the jjs utility with the “-scripting” option hence it is not able to recognize those OS commands and failing as mentioned above. So not we will start it with this option.

$ jjs -scripting

jjs> 
jjs> var listing = `ls -l`
jjs> print(listing);
total 64

drwx------+ 27 jsensharma  XXXX\Domain Users   918 Nov 24 15:19 Desktop
drwx------+ 41 jsensharma  XXXX\Domain Users  1394 Nov 19 16:24 Documents
drwx------+ 31 jsensharma  XXXX\Domain Users  1054 Nov 26 17:01 Downloads
drwx------@ 57 jsensharma  XXXX\Domain Users  1938 Nov 26 16:36 Library
drwxr-xr-x   7 jsensharma  XXXX\Domain Users   238 Nov  3 18:38 MiddlewareMagicDemos

jjs>
jjs>
jjs> print(`date`);
Fri Nov 27 11:11:23 IST 2015
jjs>

Running a Nashorn script

It is also possible that we can combine the different functions as part of a java script file and then execute it by passing the file to the “jjs” command line tool as following:
Suppose we created a file with name “test.js” in the current directory as following:

//###### Simple JavaScript with some functions. ##
// Declaring a simple function.
function sayHello(a) { 
		return "Hello, "  + a; 
	}

//###### Invoking the function sayHelo()   ##
var result = sayHello('MiddlewareMagic');
print("\n\t\t sayHello returned: " + result + "\n"); 

Once the above file is saved then we can execute it simply by passing the file to the “jjs” utility as an argument:

$ jjs /PATH/TO/test.js 

		 sayHello returned: Hello, MiddlewareMagic

Using Java API inside the JavaScript

Now lets read a file using the script and display it’s content in the jjs terminal. Suppose we want to read a file “/PATH/TO/module.xml” and then we also want to print its content in the jjs terminal.

$ jjs

jjs> var moduleFile = "/PATH/TO/module.xml";

jjs> var fileData = new java.lang.String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(moduleFile)));

jjs> print(fileData)

Similarly we can also use some other Java APIs while using the above script like if we want to display the current date/time using the “java.util.Calendar” API then we can do the same as following:

jjs> print(java.util.Calendar.getInstance().getTime());

Fri Nov 27 11:08:32 IST 2015

Using JavaScript inside the Java code

In the above sample we have seen how to use the Java APIs inside the javascript , Now we will see how we can invoke a Java Script snippet or the java script functions inside a java code. The Java8 introduced us few new APIs which we need to use in order to achieve the same.
We will be using the “javax.script.ScriptEngineManager” and “javax.script.ScriptEngine” APIs here to invoke/execute javascript functions in java.

Lets create a simple Java Code “ExampleNashorn.java” in some directory as following:

import javax.script.*;
import java.io.*;

public class ExampleNashorn {
	public static void main(String ar[]) throws Exception {
		ScriptEngineManager enginManager = new ScriptEngineManager();
        // This method takes one String argument with the name of the script engine. 
        // To get an instance of the Nashorn engine, pass in "nashorn". 
        // Alternatively, you can use any of the following: 
        // "Nashorn", "javascript", "JavaScript", "js", "JS", "ecmascript", "ECMAScript".
        
        // Creating a Java Script Engine
		ScriptEngine engine = enginManager.getEngineByName("Nashorn");
		
		try {
            //// Directly executing JavaScript snippet: ////
		    final String rawJavaScript =  "print(java.lang.System.getProperty(\"java.home\"));" +
                                          "var Date = Java.type(\"java.util.Date\");" +
                                          "var dt = new Date(); " +
                                          "print('dt = ' + dt);";
			engine.eval(rawJavaScript);

		
		    //// Mixing Java and JavaScript  ////
			engine.put("a", new Integer(ar[0]));
			engine.put("b", new Integer(ar[1]));
			engine.eval("var c = (a+b);");
			System.out.println("Sum : " + ((Number)engine.get("c")).intValue());


			//// Executing a simple java script file ////
			FileReader javaScriptFileReader = new FileReader(new File("test.js"));
            engine.eval(javaScriptFileReader);

		} catch(final ScriptException se) {
			se.printStackTrace();
		}
	}
}

In the above sample java code we have seen the following things:
1. Directly executing JavaScript snippet form Java code.
2. Mixing Java and JavaScript
3. Executing a simple java script file using java “engine.eval” API.

Now lets run the above code simply by passing the two arguments so that it can add those numbers.

$ javac ExampleNashorn.java 

$ java ExampleNashorn 100 200

/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre

dt = Fri Nov 27 11:26:32 IST 2015

Sum : 300

		 sayHello returned: Hello, MiddlewareMagic

The Source code of this demo can be found in the following repository.
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/WildFly/Java_8/ServerSideJavaScript/Part-1
.
.
Enjoy MiddlewareMagic
Jay SenSharma


Why and How to use WildFly based EJB Client API for Client auto reconnect logic ?

Hi,

In JBossAS7 or in WildFly there are different approaches which we can use in order to access EJBs. Either using “EJB client API” or using “remote naming” approach. EJB Client API is a WildFly-specific API that allows invocation on remote EJBs. This client API isn’t based on JNDI. So remote clients need not rely on JNDI API to invoke on EJBs.

Using EJB Client API based approach for EJB lookup is the recommended approach. If the remote-naming is used there are some restrictions as there is no full support of the ejb-client features. Following are some points which encourages us to use the EJB Client API based approach over the remote-naming based approach for EJB invocations.

1. No load balancing, if the URL contains multiple “remote://” servers there is no load balancing, the first available server will be used and only in case it is not longer available there will be a failover to the next available one.

2. No cluster support. As a cluster needs to be defined in the “jboss-ejb-client.properties” this feature can not be used and there is no cluster node added

3. No client side interceptor. The EJBContext.getCurrent() can not be used and it is not possible to add a client interceptor

4. No UserTransaction support

5. All proxies become invalid if .close() for the related javax.naming.InitalContext is invoked, or the InitialContext is not longer referenced and gets garbage-collected. In this case the underlying EJBContext is destroyed and the connections are closed.

6. It is not possible to use remote-naming if the client is an application deployed on another JBoss instance

What this demo is about ?

This example demonstrates why to use the EJB Client API and not the remote naming based API. As part of this sample we will see how the EJB Client can automatically gets reconnected to WildFly automatically if the wildly instance goes down and rebooted again.

So lets start developing a very simple EJB3 application and then deploy it on WildFly 10 (WildFly 8/9 also can be used).

Developing and deploying EJB3 in WildFly

Step-1). Open a terminal and then move inside the WildFly 10 “bin” directory and then create “ejbuser” (with password “ejbuser@1”) in the ApplicationRealm as following:

   $ cd /PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/bin

   $ ./add-user.sh -a ejbuser ejbuser@1
      Updated user 'ejbuser' to file ‘/PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/standalone/configuration/application-users.properties'
      Updated user 'ejbuser' to file ‘/PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/domain/configuration/application-users.properties'

Step-2). Start the WildFly instance normally as following:

   $ cd /PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/bin
   $ ./standalone.sh 

Step-3). Lets now create a directory where we will place our EJB remote interface, EJB Bean and the clients.

   $ mkdir  WildFly_EJB_Client_Reconnect
   $ mkdir -p WildFly_EJB_Client_Reconnect/src
   $ cd /PATH/TO/WildFly_EJB_Client_Reconnect

Developing EJB Project

Step-4). First of all we will write EJB remote interface “CallerRemote.java” inside the “WildFly_EJB_Client_Reconnect/src” directory as following:

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

Step-5). Now we will write EJB Stateless Bean “CallerBean.java” inside the “WildFly_EJB_Client_Reconnect/src” directory as following:

package ejb3;
import javax.ejb.*;
import javax.naming.*;
import java.util.*;
@Stateless  
@Remote(CallerRemote.class)
public class CallerBean implements CallerRemote {
     public String testMethod(String name) {
          String result="";
		  System.out.println("\n\n\t[CallerBean] Bean's testMethod(String name) called...."); 
		  return "[CallerBean] returned Welcome, "+name;
	 }
 }

Step-6). As we want to package our above mentioned EJBs inside an EAR file so lets create an “application.xml” file which will be our EAR deployment descriptor. So lets create the following kind of application.xml file inside the “WildFly_EJB_Client_Reconnect/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>remoteEjbOne.jar</ejb>
  </module>
</application>

Writing EJB Client API approach based Client

Step-7). As we are going to use the EJB Client API based approach hence lets first create the “jboss-ejb-client.properties” as following inside the “WildFly_EJB_Client_Reconnect/src”, In this file we will define our WildFly server details where our EJB is deployed. While running this code we will need to make sure that this file is present in client CLASSPATH along with the “$JBOSS_HOME/bin.client/jboss-client.jar” file.

remote.connections=one
remote.connection.one.host=localhost
remote.connection.one.port=8080
remote.connection.one.username=ejbuser
remote.connection.one.password=ejbuser@1
remote.connection.one.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

Step-8). Now the most important of writing the EJB Client based code. So lets write the “Client.java” as following inside the “WildFly_EJB_Client_Reconnect/src”:

package client;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;
import ejb3.CallerRemote;
public class Client {
     public static void main(String ar[]) throws Exception {
          Context context=null;
          try {
                Properties props = new Properties();
                props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                context = new InitialContext(props);	
	            System.out.println("\n\tGot initial Context: "+context);		
          } catch (Exception e) {
                e.printStackTrace();
          }

          //   When the invocation starts you try stopping the WildFly and then restart it back to find out if client reconnection works or not.
          CallerRemote remote=(CallerRemote)context.lookup("ejb:TestEAR/remoteEjbOne/CallerBean!ejb3.CallerRemote");
          for (int i = 0; i <= 300; i++) {  
             try {
                   System.out.println("\n\t remote.testMethod(\"MiddlewareMagic!!!\") = "+remote.testMethod("MiddlewareMagic!!!"));
                   Thread.sleep(500);
              } catch(Exception e) {                    
                    System.out.println("\n\tEXCEPTION: " + e.getMessage());
                    e.printStackTrace();
                    try{ Thread.sleep(500); } catch(InterruptedException ee) {  ee.printStackTrace(); } 
              }  
          }  
     }
  }

Writing ANT script to build/deploy/run

Step-9). Now we will write the following kind of ANT build script which will build The EAR containing the EJBs, deploy it on WildFly as well as will run the client. So lets create the “build.xml” file inside the “WildFly_EJB_Client_Reconnect” directory as following:

<project name="SingletonStartupService" default="all">
<property name="jboss.home" value="/Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT" />
<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="test" />
<property name="application.dir" value="build" />
<property name="ear.name" value="TestEAR.ear" />
<property name="ejb.one.jar" value="remoteEjbOne.jar" />
<property name="client.jar.name" value="remoteEJBClient.jar" />

        <path id="jboss.classpath">
           <fileset dir="${jboss.module.dir}/system/layers/base/javax/ejb/api/main">
               <include name="jboss-ejb-api*.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.jar" />
           </fileset>  
        </path>
	 
        <target name="all" depends="buildEAR,message" />

        <target name="buildEAR" >
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}/META-INF" />
           <mkdir dir="${application.dir}" />
           <javac srcdir="${src.dir}" destdir="${tmp.dir}"  includes="Caller*.java" classpathref="jboss.classpath"/>
           <copy file="${src.dir}/CallerBean.java" todir="${tmp.dir}/ejb/one"/>
           <copy file="${src.dir}/CallerRemote.java" todir="${tmp.dir}/ejb/one"/>
           <jar jarfile="${output.dir}/${ejb.one.jar}" basedir="${tmp.dir}" compress="true" />

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

        <target name="message" depends="buildEAR">
            <echo message="*******************  ******************* *********************" />  
            <copy file="${application.dir}/${ear.name}" tofile="${jboss.home}/standalone/deployments/${ear.name}"/>
            <echo message="********** ${application.dir}/${ear.name} Build and Deployed Successfully **********" />  
            <echo message="*******************  ******************* *********************" />  
        </target>

        <target name="run">
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}" />
           <javac srcdir="${src.dir}" destdir="${tmp.dir}"  includes="CallerRemote.java,Client.java" classpathref="jboss.classpath"/> 
           <copy file="${src.dir}/CallerRemote.java" todir="${tmp.dir}/ejb3"/>
           <copy file="${src.dir}/Client.java" todir="${tmp.dir}/client"/>    
           <copy file="${src.dir}/jboss-ejb-client.properties" todir="${tmp.dir}"/>     
           <jar jarfile="${application.dir}/${client.jar.name}" basedir="${tmp.dir}" compress="true" />
           <delete dir="${tmp.dir}"/>

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

Step-10). We can run the above ANT based EJB client project simply by setting the ANT_HOME, JAVA_HOME and PATH, So open a command prompt and then run the following commands as following:

For Unix Based OS:

$ export ANT_HOME=/PATH/TO/apache_ant_1.9.2
$ export JAVA_HOME=/PATH/TO/jdk1.8.0_60
$ export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH
$ cd /PATH/TO/WildFly10_JMS_Client


<strong>For Windows Based OS</strong>
$ set ANT_HOME=C:\PATH\TO\apache_ant_1.9.2
$ set JAVA_HOME=C:\PATH\TO\jdk1.8.0_60
$ set PATH=%JAVA_HOME%\bin;%ANT_HOME%\bin;%PATH%
$ cd C:\WildFly10_JMS_Client

Step-11). Lets deploy the application by running the ANT:

$ ant
Buildfile: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/build.xml

buildEAR:
    [mkdir] Created dir: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp/META-INF
    [javac] /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/build.xml:32: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 2 source files to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp/ejb/one
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp/ejb/one
      [jar] Building jar: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/test/remoteEjbOne.jar
    [mkdir] Created dir: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/test/META-INF
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/test/META-INF
      [jar] Building jar: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/build/TestEAR.ear
   [delete] Deleting directory /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp

message:
     [echo] *******************  ******************* *********************
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT/standalone/deployments
     [echo] ********** build/TestEAR.ear Build and Deployed Successfully **********
     [echo] *******************  ******************* *********************

all:

BUILD SUCCESSFUL
Total time: 0 seconds

Step-12). Now Run the client using the same Client.

 ant run
Buildfile: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/build.xml

run:
    [mkdir] Created dir: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp
    [javac] /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/build.xml:60: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 2 source files to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp/ejb3
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp/client
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp
      [jar] Building jar: /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/build/remoteEJBClient.jar
   [delete] Deleting directory /Users/jsensharma/NotBackedUp/MM_Tests/Forums/WildFly/WildFly_EJB_Client_Reconnect/tmp
     1 
     1 	Got initial Context: javax.naming.InitialContext@ae3865e
     1 Nov 08, 2015 9:13:51 PM org.jboss.ejb.client.EJBClient <clinit>
     1 INFO: JBoss EJB Client version 2.1.2.Final
     1 Nov 08, 2015 9:13:51 PM org.xnio.Xnio <clinit>
     1 INFO: XNIO version 3.3.2.Final
     1 Nov 08, 2015 9:13:51 PM org.xnio.nio.NioXnio <clinit>
     1 INFO: XNIO NIO Implementation Version 3.3.2.Final
     1 Nov 08, 2015 9:13:51 PM org.jboss.remoting3.EndpointImpl <clinit>
     1 INFO: JBoss Remoting version 4.0.14.Final
     1 Nov 08, 2015 9:13:52 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
     1 INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 Nov 08, 2015 9:13:52 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
     1 INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@6f526c5f, receiver=Remoting connection EJB receiver [connection=org.jboss.ejb.client.remoting.ConnectionPool$PooledConnection@c490a12,channel=jboss.ejb,nodename=banl13bca644a-3]} on channel Channel ID b29f24ca (outbound) of Remoting connection 3af686da to localhost/127.0.0.1:8080
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!

EJB Client reconnection test

Now in order to see if the EJB Client is able to reconnect to the restarted WildFly automatically or not, Let the above EJB client keep running and in the mean time restart the WildFly, We will notice that the EJB Client gets the following exception for sometime until the WildFly is restarted and as soon as the WildFly is completely restarted then the EJB Client API approach based EJB Client automatically reconnects to it.

     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 	EXCEPTION: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@b10b9b2
     1 java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@3d600a0c
     1 	at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798)
     1 	at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
     1 	at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
     1 	at com.sun.proxy.$Proxy0.testMethod(Unknown Source)
     1 	at client.Client.main(Unknown Source)
     1 
     1 	EXCEPTION: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@3d600a0c
     1 Nov 08, 2015 9:17:39 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
     1 INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
     1 Nov 08, 2015 9:17:39 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
     1 INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@f342a0b, receiver=Remoting connection EJB receiver [connection=org.jboss.ejb.client.remoting.ConnectionPool$PooledConnection@1a8ed249,channel=jboss.ejb,nodename=banl13bca644a-3]} on channel Channel ID fe6d7219 (outbound) of Remoting connection 511533be to localhost/127.0.0.1:8080
     1 java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@5f51da55
     1 	at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798)
     1 	at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
     1 	at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
     1 	at com.sun.proxy.$Proxy0.testMethod(Unknown Source)
     1 	at client.Client.main(Unknown Source)
     1 
     1 	EXCEPTION: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@5f51da55
     1 java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@271d900d
     1 	at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798)
     1 	at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
     1 	at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
     1 	at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
     1 	at com.sun.proxy.$Proxy0.testMethod(Unknown Source)
     1 	at client.Client.main(Unknown Source)
     1 
     1 	EXCEPTION: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEAR, moduleName:remoteEjbOne, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@271d900d
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!
     1 
     1 	 remote.testMethod("MiddlewareMagic!!!") = [CallerBean] returned Welcome, MiddlewareMagic!!!

.
.
The Source Code for this demo can be found in:
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/WildFly/EJB/WildFly_EJB_Client_Reconnect
.
.
Regards
Jay SenSharma


Writing java based JMS Client for WildFly10 default ActiveMQ Artemis broker.

Hi,

The HornetQ codebase was donated to the Apache ActiveMQ project, and the HornetQ community joined to build a next-generation messaging broker. ActiveMQ Artemis includes many new features, and also retains protocol compatibility with the HornetQ broker. WildFly 10 includes this new exciting project as its JMS broker, and due to the protocol compatibility, it fully replaces the HornetQ project. So as part of this simple demo we will see how we can connect to the ActiveMQ broker present inside the WildFLy10 via Standalone java based client code using standard JMS APIs.

Find more about “Apache ActiveMQ Artemis” in http://hornetq.blogspot.in/2015/06/hornetq-apache-donation-and-apache.html
AND
http://activemq.apache.org/artemis/

This article is basically clone of http://middlewaremagic.com/jboss/?p=2724 with just few WildFly 10.x specific changes related to WildFly JMS configuration, However the client code will remain same.

In this example we will be learning the following things:

1. How to create a simple JMS Queue in WildFly 10.x
2. How to create a user in ApplicationRealm and assign it to “guest” role.
3. How to create the InitialContext on the standalone client side.
4. What all jars are needed on the client side in order to lookup the JNDI resources deployed on WildFly.
5. Some common issues which you might encounter while running sample java code are explained in the other article: http://middlewaremagic.com/jboss/?p=2724

Creating A Simple JMS Queue on WildFly 10 side

Step-1). Start the WildFly 10 “full” profile (which has messaging) as following:

   $ cd /PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/bin
   $ ./standalone.sh -c standalone-full.xml

Step-2). Create a simple JMS user on WildFly 10 side and this user must belong to “guest” role. Please see the “messaging subsystem” configuration of “standalone-full.xml” to know more about “guest” role.
username: jmsuser
password: jmsuser@123
user role: guest
Realm: ApplicationRealm

   $ cd /PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/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.
Using realm 'ApplicationRealm' as discovered from the existing property files.
Username : jmsuser
User 'jmsuser' already exists and is enabled, would you like to... 
 a) Update the existing user password and roles 
 b) Disable the existing user 
 c) Type a new username
(a): a
Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file.
 - The password should be different from the username
 - The password should not be one of the following restricted values {root, admin, administrator}
 - The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)
Password : 
Re-enter Password : 
What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[guest]: guest
Updated user 'jmsuser' to file '/Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT/standalone/configuration/application-users.properties'
Updated user 'jmsuser' to file '/Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT/domain/configuration/application-users.properties'
Updated user 'jmsuser' with groups guest to file '/Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT/standalone/configuration/application-roles.properties'
Updated user 'jmsuser' with groups guest to file '/Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT/domain/configuration/application-roles.properties'
Is this new user going to be used for one AS process to connect to another AS process? 
e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls.
yes/no? yes
To represent the user add the following to the server-identities definition <secret value="am1zdXNlckAxMjM=" />

Step-3). Creating a simple JMS Queue using the WildFly CLI command line utility. NOTE the JNDI name should contain “java:/jboss/exported” prefix or else the JMS queue will can not be looked up remotely.

   $ cd /PATH/TO/wildfly-10.0.0.CR3-SNAPSHOT/bin
   $ ./jboss-cli.sh -c
   
   [standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/jms-queue=TestQ/:add(entries=["java:/jboss/exported/jms/queue/TestQ"])
     {"outcome" => "success"}
     
   [standalone@localhost:9990 /] :reload
     {
       "outcome" => "success",
       "result" => undefined
     }

The generated XML snippet in the “standalone-full.xml” file will look like following:

        <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
            <server name="default">
                <security-setting name="#">
                    <role name="guest" delete-non-durable-queue="true" create-non-durable-queue="true" consume="true" send="true"/>
                </security-setting>
                <address-setting name="#" message-counter-history-day-limit="10" page-size-bytes="2097152" max-size-bytes="10485760" expiry-address="jms.queue.ExpiryQueue" dead-letter-address="jms.queue.DLQ"/>
                <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http"/>
                <http-connector name="http-connector-throughput" endpoint="http-acceptor-throughput" socket-binding="http">
                    <param name="batch-delay" value="50"/>
                </http-connector>
                <in-vm-connector name="in-vm" server-id="0"/>
                <http-acceptor name="http-acceptor" http-listener="default"/>
                <http-acceptor name="http-acceptor-throughput" http-listener="default">
                    <param name="batch-delay" value="50"/>
                    <param name="direct-deliver" value="false"/>
                </http-acceptor>
                <in-vm-acceptor name="in-vm" server-id="0"/>
                <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
                <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>

                <!-- Newly added JMS Queue is Here -->
                <jms-queue name="TestQ" entries="java:/jboss/exported/jms/queue/TestQ"/>

                <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
                <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
                <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm"/>
            </server>
        </subsystem>

NOTE: The “java:/jboss/exported” JNDI prefix is needed in the JNDI name here to ensure that a remote client (a client running outside of that JVM where the JNDI name is bound) can do the lookup.

Writing WildFly JMS Client

Step-4). Create a directory somewhere in your filesystem to place the project WildFly kms client project.

  $ mkdir WildFly10_JMS_Client
  $ mkdir -p WildFly10_JMS_Client/src/client

Step-5). Lets write the “WildFlyJmsQueueSender.java” program which will send some jms messages to the JMS Queue “TestQ” deployed on WildFly and Lets place it inside the “WildFly10_JMS_Client/src/client” as following:

package client;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;

//jms stuff
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.IOException;

public class WildFlyJmsQueueSender {
  public final static String JMS_CONNECTION_FACTORY_JNDI="jms/RemoteConnectionFactory";
  public final static String JMS_QUEUE_JNDI="jms/queue/TestQ";
  public final static String JMS_USERNAME="jmsuser";       //  The role for this user is "guest" in ApplicationRealm
  public final static String JMS_PASSWORD="jmsuser@123";  
  public final static String WILDFLY_REMOTING_URL="http-remoting://localhost:8080";

  private QueueConnectionFactory qconFactory;
  private QueueConnection qcon;
  private QueueSession qsession;
  private QueueSender qsender;
  private Queue queue;
  private TextMessage msg;

  public static void main(String[] args) throws Exception {
    InitialContext ic = getInitialContext();
    WildFlyJmsQueueSender queueSender = new WildFlyJmsQueueSender();
    queueSender.init(ic, JMS_QUEUE_JNDI);
    readAndSend(queueSender);
    queueSender.close();
  }

  public void init(Context ctx, String queueName) throws NamingException, JMSException {
    qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_CONNECTION_FACTORY_JNDI);
    
    //  If you won't pass jms credential here then you will get 
    // [javax.jms.JMSSecurityException: HQ119031: Unable to validate user: null]    
    qcon = qconFactory.createQueueConnection(this.JMS_USERNAME, this.JMS_PASSWORD);   
    
    qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    queue = (Queue) ctx.lookup(queueName);
    qsender = qsession.createSender(queue);
    msg = qsession.createTextMessage();
    qcon.start();
  }

  public void send(String message,int counter) throws JMSException {
    msg.setText(message);
    msg.setIntProperty("counter", counter);
    qsender.send(msg);
  }

  public void close() throws JMSException {
    qsender.close();
    qsession.close();
    qcon.close();
  }

  private static void readAndSend(WildFlyJmsQueueSender wildFlyJmsQueueSender) throws IOException, JMSException {
    String line="Test Message Body with counter = ";
    for(int i=0;i<10;i++) {
          wildFlyJmsQueueSender.send(line+i,i);
          System.out.println("JMS Message Sent: "+line+i+"\n");
       }
  }

  private static InitialContext getInitialContext() throws NamingException {
     InitialContext context=null;
     try {
           Properties props = new Properties();
           props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
           props.put(Context.PROVIDER_URL, WILDFLY_REMOTING_URL);   // NOTICE: "http-remoting" and port "8080"
           props.put(Context.SECURITY_PRINCIPAL, JMS_USERNAME);
           props.put(Context.SECURITY_CREDENTIALS, JMS_PASSWORD);
           //props.put("jboss.naming.client.ejb.context", true);
           context = new InitialContext(props);	
	       System.out.println("\n\tGot initial Context: "+context);		
      } catch (Exception e) {
           e.printStackTrace();
      }
    return context;
  }
}

Step-6). Lets write the “WildFlyJmsQueueReceive.java” program which will consume messages from the JMS Queue deployed in WildFly and Lets place it inside the “WildFly10_JMS_Client/src/client” as following:

package client;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;

//jms stuff
import javax.jms.JMSException;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Message;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.IOException;

public class WildFlyJmsQueueReceive  implements MessageListener {
  public final static String JMS_CONNECTION_FACTORY_JNDI="jms/RemoteConnectionFactory";
  public final static String JMS_QUEUE_JNDI="jms/queue/TestQ";
  public final static String JMS_USERNAME="jmsuser";       //  The role for this user is "guest" in ApplicationRealm
  public final static String JMS_PASSWORD="jmsuser@123";  
  public final static String WILDFLY_REMOTING_URL="http-remoting://localhost:8080";


  private QueueConnectionFactory qconFactory;
  private QueueConnection qcon;
  private QueueSession qsession;
  private QueueReceiver qReceiver;
  private Queue queue;
  private TextMessage msg;
  private boolean quit = false;

  public static void main(String[] args) throws Exception {
    InitialContext ic = getInitialContext();
    WildFlyJmsQueueReceive wildflyJmsQueueReceive = new WildFlyJmsQueueReceive();
    wildflyJmsQueueReceive.init(ic, JMS_QUEUE_JNDI);
    System.out.println("JMS Ready To Receive Messages (To quit, send a \"quit\" message from QueueSender.class).");
    // Waiting until a "quit" message has been received.
    synchronized(wildflyJmsQueueReceive) {
         while (! wildflyJmsQueueReceive.quit) {
             try {
                   wildflyJmsQueueReceive.wait();
             }
             catch (InterruptedException ie) {
                   ie.printStackTrace();
             }
         }
     }
     wildflyJmsQueueReceive.close();
  }
  
  public void init(Context ctx, String queueName) throws NamingException, JMSException {
    qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_CONNECTION_FACTORY_JNDI);

    //  If you won't pass jms credential here then you will get 
    // [javax.jms.JMSSecurityException: HQ119031: Unable to validate user: null]    
    qcon = qconFactory.createQueueConnection(this.JMS_USERNAME, this.JMS_PASSWORD);   
    
    qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    queue = (Queue) ctx.lookup(queueName);
    qReceiver = qsession.createReceiver(queue);
    qReceiver.setMessageListener(this);
    qcon.start();
  }

  public void onMessage(Message msg) {
     try {
           String msgText;
           if (msg instanceof TextMessage) {
              msgText = ((TextMessage)msg).getText();
           } else {
              msgText = msg.toString();
           }
           System.out.println("\n<Msg_Receiver> "+ msgText );
           if (msgText.equalsIgnoreCase("quit")) {
             synchronized(this) {
             	 quit = true;
             	 this.notifyAll(); // Notify main thread to quit
             }
           }
      } catch (JMSException jmse) {
          jmse.printStackTrace();
     }
  }

  public void close() throws JMSException {
    qReceiver.close();
    qsession.close();
    qcon.close();
  }
  
  private static InitialContext getInitialContext() throws NamingException {
     InitialContext context=null;
     try {
           Properties props = new Properties();
           props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
           props.put(Context.PROVIDER_URL, WILDFLY_REMOTING_URL);   // NOTICE: "http-remoting" and port "8080"
           props.put(Context.SECURITY_PRINCIPAL, JMS_USERNAME);
           props.put(Context.SECURITY_CREDENTIALS, JMS_PASSWORD);
           //props.put("jboss.naming.client.ejb.context", true);
           context = new InitialContext(props);	
	   System.out.println("\n\tGot initial Context: "+context);		
      } catch (Exception e) {
           e.printStackTrace();
      }
    return context;
  }
}

Step-7). In order to run the above program easily we are going to use ANT, However users can also run the above programs manually by adding the “$JBOSS_HOME/bin/client/jboss-client.jar” in the class path of the client. Here we will be writing the following ind of “build.xml” file inside the “WildFly10_JMS_Client” as following:

<project name="WildFly_Jms_Client" default="runSender">
<property name="jboss.home" value="/Users/jsensharma/NotBackedUp/Installed/wildfly-10.0.0.CR3-SNAPSHOT" />
<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="client.jar.name" value="wildfly_jms_client.jar" />

        <!-- 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.jar" />
           </fileset>  
        </path>

        <target name="runSender">
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}" />
           <javac srcdir="${src.dir}/client" destdir="${tmp.dir}" includes="WildFlyJmsQueueSender.java" classpathref="jboss.new.client.classpath"/> 
           <copy file="${src.dir}/client/WildFlyJmsQueueSender.java" todir="${tmp.dir}/client"/>        
           <jar jarfile="${output.dir}/${client.jar.name}" basedir="${tmp.dir}" compress="true" />
           <delete dir="${tmp.dir}"/>
           <java classname="client.WildFlyJmsQueueSender" fork="true" classpathref="jboss.new.client.classpath">
               <classpath>
                  <pathelement location="${output.dir}/${client.jar.name}"/>
               </classpath>
           </java>
        </target>     

        <target name="runReceive">
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}" />
           <javac srcdir="${src.dir}/client" destdir="${tmp.dir}" includes="WildFlyJmsQueueReceive.java" classpathref="jboss.new.client.classpath"/> 
           <copy file="${src.dir}/client/WildFlyJmsQueueReceive.java" todir="${tmp.dir}/client"/>        
           <jar jarfile="${output.dir}/${client.jar.name}" basedir="${tmp.dir}" compress="true" />
           <delete dir="${tmp.dir}"/>
           <java classname="client.WildFlyJmsQueueReceive" fork="true" classpathref="jboss.new.client.classpath">
               <classpath>
                  <pathelement location="${output.dir}/${client.jar.name}"/>
               </classpath>
           </java>
        </target>             
</project>

Running the WildFly 10 JMS client

Step-8). We can run the above ANT based kms client project simply by setting the ANT_HOME, JAVA_HOME and PATH as following :

For Unix Based OS:

$ export ANT_HOME=/PATH/TO/apache_ant_1.9.2
$ export JAVA_HOME=/PATH/TO/jdk1.8.0_60
$ export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH
$ cd /PATH/TO/WildFly10_JMS_Client


<strong>For Windows Based OS</strong>
$ set ANT_HOME=C:\PATH\TO\apache_ant_1.9.2
$ set JAVA_HOME=C:\PATH\TO\jdk1.8.0_60
$ set PATH=%JAVA_HOME%\bin;%ANT_HOME%\bin;%PATH%
$ cd C:\WildFly10_JMS_Client

Step-9). In the same above command prompt, Lets run the “WildFlyJmsQueueSender.java” program which will send to messages to the “TestQ” present on WildFly 8 as following :

$ ant runSender

Buildfile: /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/build.xml

runSender:
    [mkdir] Created dir: /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp
    [javac] /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/build.xml:20: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 1 source file to /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp/client
      [jar] Building jar: /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/build/wildfly_jms_client.jar
   [delete] Deleting directory /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp
     1 Nov 08, 2015 4:15:53 PM org.xnio.Xnio <clinit>
     1 INFO: XNIO version 3.3.2.Final
     1 Nov 08, 2015 4:15:53 PM org.xnio.nio.NioXnio <clinit>
     1 INFO: XNIO NIO Implementation Version 3.3.2.Final
     1 
     1 	Got initial Context: javax.naming.InitialContext@5e7f2a19
     1 Nov 08, 2015 4:15:53 PM org.jboss.remoting3.EndpointImpl <clinit>
     1 INFO: JBoss Remoting version 4.0.14.Final
     1 Nov 08, 2015 4:15:54 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
     1 INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
     1 Nov 08, 2015 4:15:54 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
     1 INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@785ae27e, receiver=Remoting connection EJB receiver [connection=Remoting connection <5720171f>,channel=jboss.ejb,nodename=banl13bca644a-3]} on channel Channel ID dfdae415 (outbound) of Remoting connection 13c57d7d to localhost/127.0.0.1:8080
     1 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
     1 SLF4J: Defaulting to no-operation (NOP) logger implementation
     1 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
     1 Nov 08, 2015 4:15:54 PM org.jboss.ejb.client.EJBClient <clinit>
     1 INFO: JBoss EJB Client version 2.1.2.Final
     1 JMS Message Sent: Test Message Body with counter = 0
     1 
     1 JMS Message Sent: Test Message Body with counter = 1
     1 
     1 JMS Message Sent: Test Message Body with counter = 2
     1 
     1 JMS Message Sent: Test Message Body with counter = 3
     1 
     1 JMS Message Sent: Test Message Body with counter = 4
     1 
     1 JMS Message Sent: Test Message Body with counter = 5
     1 
     1 JMS Message Sent: Test Message Body with counter = 6
     1 
     1 JMS Message Sent: Test Message Body with counter = 7
     1 
     1 JMS Message Sent: Test Message Body with counter = 8
     1 
     1 JMS Message Sent: Test Message Body with counter = 9
     1 

BUILD SUCCESSFUL
Total time: 2 seconds

Step-10). In the same above command prompt, Lets run the “WildFlyJmsQueueReceive.java” program which will receive the jms messages which are present in the “TestQ” present on WildFly 8 as following :

$ ant runReceive
Buildfile: /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/build.xml

runReceive:
    [mkdir] Created dir: /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp
    [javac] /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/build.xml:34: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 1 source file to /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp
     [copy] Copying 1 file to /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp/client
      [jar] Building jar: /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/build/wildfly_jms_client.jar
   [delete] Deleting directory /Users/jsensharma/NotBackedUp/MM_Tests/WildFly/WildFly10_JMS_Client/tmp
     1 Nov 08, 2015 4:28:23 PM org.xnio.Xnio <clinit>
     1 INFO: XNIO version 3.3.2.Final
     1 Nov 08, 2015 4:28:23 PM org.xnio.nio.NioXnio <clinit>
     1 INFO: XNIO NIO Implementation Version 3.3.2.Final
     1 Nov 08, 2015 4:28:23 PM org.jboss.remoting3.EndpointImpl <clinit>
     1 INFO: JBoss Remoting version 4.0.14.Final
     1 
     1 	Got initial Context: javax.naming.InitialContext@129458ea
     1 Nov 08, 2015 4:28:23 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
     1 INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
     1 Nov 08, 2015 4:28:23 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
     1 INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@67d07b41, receiver=Remoting connection EJB receiver [connection=Remoting connection <533a0538>,channel=jboss.ejb,nodename=banl13bca644a-3]} on channel Channel ID c898038c (outbound) of Remoting connection 7a73ad16 to localhost/127.0.0.1:8080
     1 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
     1 SLF4J: Defaulting to no-operation (NOP) logger implementation
     1 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
     1 Nov 08, 2015 4:28:23 PM org.jboss.ejb.client.EJBClient <clinit>
     1 INFO: JBoss EJB Client version 2.1.2.Final
     1 JMS Ready To Receive Messages (To quit, send a "quit" message from QueueSender.class).
     1 
     1 <Msg_Receiver> Test Message Body with counter = 0
     1 
     1 <Msg_Receiver> Test Message Body with counter = 1
     1 
     1 <Msg_Receiver> Test Message Body with counter = 2
     1 
     1 <Msg_Receiver> Test Message Body with counter = 3
     1 
     1 <Msg_Receiver> Test Message Body with counter = 4
     1 
     1 <Msg_Receiver> Test Message Body with counter = 5
     1 
     1 <Msg_Receiver> Test Message Body with counter = 6
     1 
     1 <Msg_Receiver> Test Message Body with counter = 7
     1 
     1 <Msg_Receiver> Test Message Body with counter = 8
     1 
     1 <Msg_Receiver> Test Message Body with counter = 9

Issues which you may encounter

You might see some error/exceptions while running this demo in that case you can refer to the following article which explains some common issues which you might encounter while running this code. The following link also contains the remedies of those common exceptions.

Wildfly 8 based standalone JMS client code common issues and remedies ?
http://middlewaremagic.com/jboss/?p=2724

Monitoring JMS Queue using CLI

If we want to monitor the JMS Queue using jboss-cli.sh script then we can do it as following:

/subsystem=messaging-activemq/server=default/jms-queue=TestQ/:read-resource(recursive=true,include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "consumer-count" => 0,
        "dead-letter-address" => "jms.queue.DLQ",
        "delivering-count" => 0,
        "durable" => true,
        "entries" => ["java:/jboss/exported/jms/queue/TestQ"],
        "expiry-address" => "jms.queue.ExpiryQueue",
        "legacy-entries" => undefined,
        "message-count" => 20L,
        "messages-added" => 30L,
        "paused" => false,
        "queue-address" => "jms.queue.TestQ",
        "scheduled-count" => 0L,
        "selector" => undefined,
        "temporary" => false
    }
}

.
.
The Source code of this demo can be found at: (The code should remain same for WildFly 8/9/10)
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/WildFly/JMS/WildFly_JMS_Client

.
.

Regards
Jay SenSharma


Copyright © 2010-2012 Middleware Magic. All rights reserved. |