Table of Contents
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
- Details about context close BUG: https://issues.jboss.org/browse/EJBCLIENT-98
- Remote EJB invocations via JNDI – EJB client API or remote-naming project
Your post very helped me to run remote EJB client for WildFly 8.2. Thank you.
However, while the similar code did EJB lookup. It couldn’t perform remote invocation. It failed with an exception:
Exception in thread “main” java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:TestEE, moduleName:TestEE-ejb, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@3632be31
This is not a lookup issue, because it fired on EJB method invocation, rather than on lookup. In order to overcome it, I have added jboss-ejb-client.properties file to my project:
###
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port = 8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=test
remote.connection.default.password=p@ssw0rd
###
After that I successfully invoked EJB from remote client.