Portable JNDI lookup of REMOTE EJBs

Overview

  • The EJBs described below are deployed as a JEE6 project to the following Application Servers
    • Glassfish 4.1 ( JEE6 / JEE7 )
    • Weblogic 12.1.3 ( JEE6 )
    • Wildfly 8.2 ( JEE6 / JEE7 )
  • Deleveloping 2 EJBs
    • BrokerEJB deployed as a simple EJB in a plain JAR file ( BrokerEJB.jar )
    • OnlineBroker is deployed as a Enterprise Application in an EAR file ( OnlineBroker.ear )
  • Both EBJs are deployed to all of the Application Servers (note here we do need any code changes )
  • The Remote client lookup needs different coding for different App Servers and Packaging ( JAR / EAR )

Server Setup BrokerEJB : deployed as a simple EJB in a plain JAR file

  • BrokerEJB.jar
 
   View  BrokerEJB.jar content : 
	   [oracle@wls1 ~]$ jar tvf ./NetBeansProjects/BrokerEJB/dist/BrokerEJB.jar
	     0 Thu Dec 25 10:20:42 CET 2014 META-INF/
	   103 Thu Dec 25 10:20:40 CET 2014 META-INF/MANIFEST.MF
	     0 Thu Dec 25 10:20:40 CET 2014 test/
	    48 Thu Dec 25 10:20:40 CET 2014 META-INF/jboss.xml
	   401 Thu Dec 25 10:20:40 CET 2014 META-INF/weblogic-ejb-jar.xml
	  1624 Thu Dec 25 10:20:40 CET 2014 test/Main.class
	   822 Thu Dec 25 10:20:40 CET 2014 test/StockBean.class
	   243 Thu Dec 25 10:20:40 CET 2014 test/StockBeanRemote.class

  test/StockBean.java ( Business Logic )
	package test;
	import javax.ejb.Stateless;
	import javax.ejb.Remote;
	@Stateless 
	@Remote(StockBeanRemote.class)
	public class StockBean implements StockBeanRemote  {

	 @Override
	public String get_stockprize(String stock_name) {
	   return "Message from BrokerEJB: Current share prize  for  "+" "+stock_name + " : 200 € ";
	   }
	}

   test/StockBeanRemote.class   (  Remote Business Interface )
	package test;
	import javax.ejb.Remote;
	@Remote
	public interface StockBeanRemote {
    	    public String get_stockprize(String name);
        }

Server Setup OnlineBroker : deployed as a Enterprise Application in an EAR file

  • OnlineBroker.ear
 
   View OnlineBroker.ear  content : 
	[oracle@wls1 ~]$  jar tvf ./NetBeansProjects/GIT/OnlineBroker/dist/OnlineBroker.ear 
	     0 Mon Dec 29 08:12:44 CET 2014 META-INF/
	   103 Mon Dec 29 08:12:42 CET 2014 META-INF/MANIFEST.MF
	   529 Mon Dec 29 08:12:42 CET 2014 META-INF/application.xml
	   418 Mon Dec 29 08:12:42 CET 2014 META-INF/weblogic-application.xml
	  2693 Mon Dec 29 08:12:42 CET 2014 OnlineBroker-ejb.jar
	  2574 Mon Dec 29 08:12:42 CET 2014 OnlineBroker-war.war

   View  OnlineBroker-ejb.jar content 
	  [oracle@wls1 ~]$ jar xvf ./NetBeansProjects/GIT/OnlineBroker/dist/OnlineBroker.ear OnlineBroker-ejb.jar ;  jar tvf OnlineBroker-ejb.jar
	   0 Mon Dec 29 08:12:42 CET 2014 META-INF/
	   103 Mon Dec 29 08:12:40 CET 2014 META-INF/MANIFEST.MF
	     0 Mon Dec 29 08:12:42 CET 2014 broker/
	   269 Mon Dec 29 08:12:40 CET 2014 META-INF/beans.xml
	   401 Mon Dec 29 08:12:40 CET 2014 META-INF/weblogic-ejb-jar.xml
	   841 Mon Dec 29 08:12:42 CET 2014 broker/StockBean2.class
	   247 Mon Dec 29 08:12:42 CET 2014 broker/StockBeanRemote2.class

   broker/StockBean2.java ( Business Logic )
	package broker;
	import javax.ejb.Stateless;
	import javax.ejb.Remote;

	@Stateless 
	@Remote(StockBeanRemote2.class)
	public class StockBean2 implements StockBeanRemote2 
	{
	    @Override
	    public String get_stockprize(String stock_name) 
	    {
		return "Message from EAR BrokerEJB : Current share prize  for  "+" "+stock_name + " : 200 € ";
	    }
	} 

   broker/StockBeanRemote2.java (  Remote Business Interface )
	package broker;
	import javax.ejb.Remote;

        @Remote
	public interface StockBeanRemote2 
	{
	    public String get_stockprize(String name);
	}

 

Details running a  Stand-alone REMOTE EJB client using JNDI on Glassfish 4.1

  • The Glassfish 41 standalone JNDI client needs  more than a single JAR  gf-client.jar  to operate as a full JNDI client
  • The client lib gf-client.jar  is located at :  appclient/glassfish/lib
  • Other needed JAR files can be found at : appclient/glassfish/modules/ [ like glassfish-naming.jar ]
  • This makes Glassfish 41 not very handy compared to Weblogic 12.1.3 and WildFly 8.2 where we need only a single client JAR
  • Portable JNDI Name  ( for JAR file destribution) : java:global/BrokerEJB/StockBean!test.StockBeanRemote
  • Portable JNDI Name  ( for EAR file destribution) : java:global/OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2
Create a standalone  client with Glassfish libs using the package-appclient Script
You can package the GlassFish Server system files required to launch application clients on remote systems into a 
single JAR file using the package-appclient script
[root@wls1 ~]# /usr/local/glassfish-4.1/glassfish/bin/package-appclient
Creating /usr/local/glassfish-4.1/glassfish/lib/appclient.jar
-> copy appclient.jar to the remote system and unzip that file --> /home/oracle/JEE7/lib/

Verify JNDI settings by exploring the GlassFish 4.1 server 
[oracle@wls1 GLASSFISH_EJB]$ asadmin list-jndi-entries --context java:global
     BrokerEJB: com.sun.enterprise.naming.impl.TransientContext
     OnlineBroker: com.sun.enterprise.naming.impl.TransientContext
  --> BrokerEJB and OnlineBroker are listed are accessible as global JNDI names

Invoke GlassFish management console : http://localhost:4848/common/index.jsf 
Verify  EAR lookup:
 --> Applications -> OnlineBroker
    -> Modules and Components : OnlineBroker-ejb.jar     StockBean2     StatelessSessionBean
This translates to followowing global JNDI naming
   "java:global/OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2"; 

Verify JAR lookup:    
 --> Applications -> BrokerEJB
    -> Modules and Components :  BrokerEJB     StockBean2     StatelessSessionBean
 This translates to followowing global JNDI naming
          "java:global/BrokerEJB/StockBean!test.StockBeanRemote"; 

JNDI client Java code 
./EjbClient.java                - Remote JNDI Client program
./test/StockBeanRemote.java     - Remote Interface for the JAR test 
./broker/StockBeanRemote2.java  - Remote Interface for the EAR test 

Java Code extract :  ./EjbClient.java  
            Properties prop = new Properties();
            prop.put("org.omg.CORBA.ORBInitialHost","wls1.example.com"); 
            prop.put("org.omg.CORBA.ORBInitialPort","3700");
            prop.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
            prop.put("java.naming.factory.url.pkgs","com.sun.enterprise.naming");
            prop.put("java.naming.factory.state","com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
            ctx = new InitialContext(prop);

              // GlassFish 41 EJB Remote lookup for single EJB class named StockBean
              // EJB name container: BrokerEJB.jar 
              // Bean name         : StockBean2
              // Java package      : test  
              // Remote Interface  : StockBeanRemote2
              // This translates to the following global JNDI naming: 

            String ejb_class_name = "java:global/BrokerEJB/StockBean!test.StockBeanRemote";  
            System.out.println("\n-> EJB remote lookup ( JAR file destribution) : " + ejb_class_name);
            Object o = ctx.lookup(ejb_class_name);
            StockBeanRemote stockb =(StockBeanRemote)o;
            System.out.println(stockb.get_stockprize("Google"));

              // GlassFish 41 EJB Remote lookup for single EJB class named StockBean
              // java:global.shop1.shop1-ejb.StockBean2!myshop.StockBeanRemote2
              // EAR name:         : OnlineBroker.ear
              // EJB name container: OnlineBroker-ejb.jar 
              // Bean name         : StockBean2
              // Java package      : broker
              // Remote Interface  : StockBeanRemote2
              // This translates to the following global JNDI naming: 
            String ejb_ear_name = "java:global/OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2"; 
            System.out.println("-> EJB remote lookup ( EAR distribution) : " + ejb_ear_name);
            Object o2 = ctx.lookup(ejb_ear_name);
            StockBeanRemote2 stockb2 =(StockBeanRemote2)o2;
            System.out.println(stockb2.get_stockprize("Google"));
..
Remote Interface for EAR distribution - broker/StockBeanRemote2.java )
package broker;
import javax.ejb.Remote;
@Remote
public interface StockBeanRemote2 {
    public String get_stockprize(String name);
}

Remote Interface for plain JAR distribution - test/StockBeanRemote.java )
package test;
import javax.ejb.Remote;

@Remote
public interface StockBeanRemote {
    public String get_stockprize(String name);
}

Full Glassfish 41 client can be found here .

Compile and run testcase:
CLASSPATH=.:/home/oracle/JEE7/lib/appclient/glassfish/lib/gf-client.jar
+ javac test/StockBeanRemote.java
+ javac broker/StockBeanRemote2.java
+ javac EjbClient.java
+ /home/oracle/JEE7/lib/appclient/glassfish/bin/appclient EjbClient

Output: 
-> EJB remote lookup ( JAR file destribution) : java:global/BrokerEJB/StockBean!test.StockBeanRemote
Message from BrokerEJB: Current share prize  for   Google : 200 € 
-> EJB remote lookup ( EAR distribution) : java:global/OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2
Message from Broker_EAR_EJB : Current share prize  for   Google : 200 €

Details running a  Stand-alone REMOTE EJB client using JNDI for Oracle WebLogic Server 12.1.3

  • WebLogic Server 12.1.3 is not using IIOP insteat uses the WebLogic T3 protocol
  • WebLogic Server 12.1.3 only need  wlthint3client.jar  to operate as a full JNDI client
  • Portable JNDI Name  ( for JAR file destribution) : java:global/classes/StockBean!test.StockBeanRemote
  • Portable JNDI Name  ( for EAR file destribution) : java:global.OnlineBroker.OnlineBroker-ejb.StockBean2!broker.StockBeanRemote2
Details about WebLogic Thin T3 Client
The WebLogic full client, wlfullclient.jar, is deprecated as of WebLogic Server 12.1.3 and may be removed in a future release.
Oracle recommends using the WebLogic Thin T3 client or other appropriate client depending on your environment. For more
information on WebLogic client types, see WebLogic Server Client Types and Features.

Understanding the WebLogic Thin T3 Client
The WebLogic Thin T3 Client jar (wlthint3client.jar) is a light-weight, high performing alternative to the wlfullclient.jar
and wlclient.jar (IIOP) remote client jars. The Thin T3 client has a minimal footprint while providing access to a rich set of
APIs that are appropriate for client usage. As its name implies, the Thin T3 Client uses the WebLogic T3 protocol, which provides
significant performance improvements over the wlclient.jar, which uses the IIOP protocol.

Verify JNDI settings by exploring the WebLogic 12.1.3 server with  Admin Console : http://wls1.example.com:7001 
  Domain (wl_server ) -> Enviroments -> Servers -> AdminServer(admin) -> View JNDI Tree ( right below Save button ) 

  EAR lookup: [ Enterprise Application: EJB + WAR ]
    java:global -> shop1 -> shop1-ejb -> StockBean2!myshop -> StockBeanRemote2
    Binding Name: java:global.OnlineBroker.OnlineBroker-ejb.StockBean2!broker.StockBeanRemote2

  JAR lookup: [ EJB ]    
    java:global -> classes -> StockBean!test -> StockBeanRemote
    Binding Name: java:global.classes.StockBean!test.StockBeanRemote
    --> Expect to get java:global.brokerEJB.StockBean!test.StockBeanRemote instead of 
        java:global.classes.StockBean!test.StockBeanRemote

Java code
./EjbClient.java                - Remote JNDI Client program
./test/StockBeanRemote.java     - Remote Interface for the JAR test
./broker/StockBeanRemote2.java  - Remote Interface for the EAR test

Java Code extract :  ./EjbClient.java  
        Properties prop = new Properties();
        prop.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory");
        prop.put("java.naming.provider.url","t3://wls1.example.com:7001");
        prop.put("java.naming.security.principal","weblogic");
        prop.put("java.naming.security.credentials","helmut11");
            ctx = new InitialContext(prop);

              // Weblogic 12.1.3 EJB Remote lookup for single EJB class named StockBean
              // EJB name container: brokerEJB.jar 
              // Bean name         : StockBean2
              // Java package      : test  
              // Remote Interface  : StockBeanRemote2
              // This translates to the following global JNDI naming: 
            String ejb_class_name = "java:global/classes/StockBean!test.StockBeanRemote";  
            System.out.println("\n-> EJB remote lookup ( JAR file destribution) : " + ejb_class_name);
            Object o = ctx.lookup(ejb_class_name);
            StockBeanRemote stockb =(StockBeanRemote)o;
            System.out.println(stockb.get_stockprize("Google"));

              // Weblogic 12.1.3 EJB Remote lookup for single EJB class named StockBean
              // java:global.shop1.shop1-ejb.StockBean2!myshop.StockBeanRemote2
              // EAR name:         : OnlineBroker.ear
              // EJB name container: OnlineBroker-ejb.jar 
              // Bean name         : StockBean2
              // Java package      : broker
              // Remote Interface  : StockBeanRemote2
              // This translates to the following global JNDI naming: 
            String ejb_ear_name = "java:global.OnlineBroker.OnlineBroker-ejb.StockBean2!broker.StockBeanRemote2"; 
            System.out.println("-> EJB remote lookup ( EAR distribution) : " + ejb_ear_name);
            Object o2 = ctx.lookup(ejb_ear_name);
            StockBeanRemote2 stockb2 =(StockBeanRemote2)o2;
            System.out.println(stockb2.get_stockprize("Google"));

..
Remote Interface for EAR distribution - broker/StockBeanRemote2.java )
package broker;
import javax.ejb.Remote;
@Remote
public interface StockBeanRemote2 {
    public String get_stockprize(String name);
}

Remote Interface for plain JAR distribution - test/StockBeanRemote.java )
package test;
import javax.ejb.Remote;

@Remote
public interface StockBeanRemote {
    public String get_stockprize(String name);
}

Full Weblogic 12.1.3  client can be found: here .

Compile and run testcase
CLASSPATH=.:./lib/wlthint3client.jar
+ javac test/StockBeanRemote.java
+ javac broker/StockBeanRemote2.java
+ javac EjbClient.java
+ java EjbClient

Output :
-> EJB remote lookup ( JAR file destribution) : java:global/classes/StockBean!test.StockBeanRemote
Message from BrokerEJB: Current share prize  for   Google : 200 € 
-> EJB remote lookup ( EAR distribution) : java:global.OnlineBroker.OnlineBroker-ejb.StockBean2!broker.StockBeanRemote2
Message from Broker_EAR_EJB : Current share prize  for   Google : 200 €

Reference

 

Details running a  Stand-alone REMOTE EJB client using JNDI for WildFly 8.2

  • Wildfy 8.2 only needs jboss-client.jar to run an EJB remote client
  • Starting WildFly 8, the JNP project is not used. Neither on the server side nor on the client side.
  • The client side of the JNP project has now been replaced by jboss-remote-naming project
  • Portable JNDI Name  ( for JAR file destribution) : BrokerEJB/StockBean!test.StockBeanRemote
  • Portable JNDI Name  ( for EAR file destribution) : OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2
  • EJB remotely accessible are such objects which can found under java:jboss/exported/ namespace.

 

Know Bugs/Problems
Closing context with Wildfly 8.2 crashes with following stack  dumped to stderr 
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1e4000e7 rejected from java.util.concurrent.Th
readPoolExecutor@7bfb4d34[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)

Crash in context close ( ctx.close() ) is  a JBOSS/Wildfly problem only.
For details please read following BUG https://issues.jboss.org/browse/EJBCLIENT-98
java.util.concurrent.RejectedExecutionException if a remote-naming InitialContext should be closed
Problem code: ctx.close() 
private static void close_context(Context ctx)
    {
        if ( ctx != null)
        { 
            try
            {
                ctx.close();
                System.out.println("Context closed()   " ); <-- This is still reached
            }

Verify JNDI settings by exploring the WildFly 8.2 server with  Admin Console :  localhost:9990
 EAR lookup:
   Runtime -> JNDI View -> java:global -> OnlineBroker -> OnlineBroker-ejb -> StockBean2!broker.StockBeanRemote2
   This translates to followowing global JNDI naming
       "OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2"; 
   Note the java:global/ prefix needs to be removed 

 JAR lookup:    
   Runtime -> JNDI View -> java:global -> BrokerEJB -> StockBean2!broker.StockBeanRemote2
    -> Modules and Components :  BrokerEJB     StockBean2     StatelessSessionBean
   This translates to followowing global JNDI naming
            "BrokerEJB/StockBean!test.StockBeanRemote";  
   Note the java:global/ prefix needs to be removed 

  Under Deployments you should see BrokerEJB.jar and OnlineBroker.ear !

Java code
./EjbClient.java                - Remote JNDI Client program
./test/StockBeanRemote.java     - Remote Interface for the JAR test
./broker/StockBeanRemote2.java  - Remote Interface for the EAR test

Java Code extract :  ./EjbClient.java  
..
        Properties prop = new Properties();
        prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
        prop.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8180");
        prop.put(Context.SECURITY_PRINCIPAL, "oracle");
        prop.put(Context.SECURITY_CREDENTIALS, "helmut11");
        prop.put("jboss.naming.client.ejb.context", true);
        ctx = new InitialContext(prop);

              // WildFly 8.2 EJB Remote lookup for single EJB class named StockBean
              // EJB name container: BrokerEJB.jar 
              // Bean name         : StockBean2
              // Java package      : test  
              // Remote Interface  : StockBeanRemote2
              // This translates to the following global JNDI naming: 

            String ejb_class_name = "BrokerEJB/StockBean!test.StockBeanRemote";  
            System.out.println("\n-> EJB remote lookup ( JAR file destribution) : " + ejb_class_name);
            Object o = ctx.lookup(ejb_class_name);
            StockBeanRemote stockb =(StockBeanRemote)o;
            System.out.println(stockb.get_stockprize("Google"));

              // WildFly 82 EJB Remote lookup for single EJB class named StockBean
              // java:global.shop1.shop1-ejb.StockBean2!myshop.StockBeanRemote2
              // EAR name:         : OnlineBroker.ear
              // EJB name container: OnlineBroker-ejb.jar 
              // Bean name         : StockBean2
              // Java package      : broker
              // Remote Interface  : StockBeanRemote2
              // This translates to the following global JNDI naming: 
            String ejb_ear_name = "OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2"; 
            System.out.println("-> EJB remote lookup ( EAR distribution) : " + ejb_ear_name);
            Object o2 = ctx.lookup(ejb_ear_name);
            StockBeanRemote2 stockb2 =(StockBeanRemote2)o2;
            System.out.println(stockb2.get_stockprize("Google"));

Remote Interface for plain JAR distribution - test/StockBeanRemote.java )
package test;
import javax.ejb.Remote;

@Remote
public interface StockBeanRemote {
    public String get_stockprize(String name);
}

Full WildFly 8.2  client can be found:  here.

Compile and run testcase
CLASSPATH=:./lib/jboss-client.jar
+ javac test/StockBeanRemote.java
+ javac broker/StockBeanRemote2.java
+ javac EjbClient.java
+ java EjbClient
Output 
-> EJB remote lookup ( JAR file destribution) : BrokerEJB/StockBean!test.StockBeanRemote
Message from BrokerEJB: Current share prize  for   Google : 200 € 
-> EJB remote lookup ( EAR distribution) : OnlineBroker/OnlineBroker-ejb/StockBean2!broker.StockBeanRemote2
Message from EAR BrokerEJB : Current share prize  for   Google : 200 €

Reference