EJB remote client migration from JBoss AS 7.1 to W

2019-03-04 12:33发布

问题:

We developed a training application which contains a standalone java clients communicating with EJBs. The working setup included a JBoss AS 7.1 on Windows 7 and an application user created via /bin/add-user.bat.

The client was coded like that:

Properties jndiProps = new Properties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
jndiProps.put("jboss.naming.client.ejb.context", true);
jndiProps.put(Context.PROVIDER_URL, "remote://localhost:4447");
jndiProps.put(Context.SECURITY_PRINCIPAL, "user");
jndiProps.put(Context.SECURITY_CREDENTIALS, "xxx");
Context ctx = new InitialContext(jndiProps);
MyBeanRemote myBean = (MyBeanRemote) ctx.lookup("ejb:/training//MyBean!mypackage.MyBeanRemote");
String result = myBean.greet("John");

The client was started with jboss-client.jar in the classpath.

Now we tried to use a WildFly 8.1 instead which deployed successfully, but the client fails with

Exception in thread "main" java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:, moduleName:syjeews, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@6e7d3146

Changing the JNDI lookup name into something which is printed out during deployment (e.g. java:global/training/MyBean!mypackage.MyBeanRemote) resulted in

Exception in thread "main" javax.naming.CommunicationException: Failed to connect to any server. Servers tried: [remote://localhost:4447 (java.net.ConnectException: Connection refused: no further information)]

After searching googling for a while we stumpled upon several articles on SO (e.g. this or that) or samples or the Wildfly Developer Guide, but all alternatives, may it be the minimal JNDI properties or the extended configuration via ClientContext didn't make it work.

So my question is, what needs to be done to migrate the code/configuration above to run it under WildFly?

Note: This is not production code, so security is not an issue - if I can simplify the whole configuration, it's fine - it should only demonstrate how to use an EJB remote interface from a standalone Java program.

回答1:

You need to do two changes

instead of using "remote://localhost:4447" use "http-remoting://localhost:8080"

jndiProps.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");

When you configure jndi properties in code, lookup name should not contain ejb:

MyBeanRemote myBean = (MyBeanRemote) ctx.lookup("/training//MyBean!mypackage.MyBeanRemote");

this solution is tested and working



回答2:

The provider URL should be http-remoting://localhost:8080 instead of remote://localhost:4447



回答3:

I'm using:

  • wildfly-10.0.0.Final(JBoss Application Server).

That works to me:

Properties jndiProperties = new Properties();
           jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
           jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
           jndiProperties.put("jboss.naming.client.ejb.context", true);
           jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");   //System.getProperty(Context.PROVIDER_URL, "http-remoting://localhost:8080"));

        /* jndiProperties.put(Context.SECURITY_PRINCIPAL, "user");
           jndiProperties.put(Context.SECURITY_CREDENTIALS, "xxx");*/

        InitialContext context = new InitialContext(jndiProperties);

        MyFirstEJBRemote ejb = (MyFirstEJBRemote) context.lookup("/EJBProjectName/MyFirstEJB!src.MyFirstEJBRemote");

Hope it helps!



回答4:

Here is my Project called "MyFirstEJBProject". Inside of the code are some notes to help.

package src.ejb;

import javax.ejb.Stateless;

/**
 * Session Bean implementation class MyFirstEJB
 */
@Stateless
public class MyFirstEJB implements MyFirstEJBRemote {

    public MyFirstEJB() {
    }

    @Override
    public String helloWorld() {
        return "Hello World EJB";
    }

}


package src.ejb;

import javax.ejb.Remote;

@Remote
public interface MyFirstEJBRemote {
    public String helloWorld();
}


package src.clientTest;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import src.ejb.MyFirstEJB;
import src.ejb.MyFirstEJBRemote;

public class EJBClient {

    public static void main(String[] args) throws NamingException {

        /**JNDI or Java Naming and Directory Interface.
         * When JNDI constructs an initial context, the context's environment
         * is initialized with properties defined in the environment parameter
         * passed to the constructor, the system properties, the applet parameters,
         * and the application resource files.
         * 
         * JNDI applications need a way to communicate various preferences
         * and properties that define the environment in which naming and
         * directory services are accessed.
         * */

        Properties jndiProperties = new Properties();
        jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        jndiProperties.put("jboss.naming.client.ejb.context", true);
        jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");

        /* jndiProperties.put(Context.SECURITY_PRINCIPAL, "user");
           jndiProperties.put(Context.SECURITY_CREDENTIALS, "xxx");*/

        /**Context For JNDI**/
        InitialContext context = new InitialContext(jndiProperties);

        /**The nameOfEJB appears on the console when the server is starting up.**/
        String nameOfEJB = "/MyFirstEJBProject/MyFirstEJB!src.ejb.MyFirstEJBRemote";

                                                  /**The Method .lookup("") search for EJB by name**/
        MyFirstEJBRemote ejb = (MyFirstEJBRemote) context.lookup(nameOfEJB);
        System.out.println(ejb.helloWorld());


        System.out.println("/** =============== 2º TEST ===============**/"); 

        /**getting a EJB name by a private Method.**/
        String nameOfEJB_2 = getEJBName("", "MyFirstEJBProject", "", 
                MyFirstEJB.class.getSimpleName(), MyFirstEJBRemote.class.getName());

        MyFirstEJBRemote ejb_2 = (MyFirstEJBRemote) context.lookup(nameOfEJB_2);
        System.out.println(ejb_2.helloWorld());
    }

    private static String getEJBName(String nameofAppEAR, String nameOfProjectModulo, 
            String distinctNameOfProject, String classBeanSimpleName, String classInterfaceName){
        /**Return a object name for search on JNDI */

        String finalNameOfEJB = nameofAppEAR + "/" + nameOfProjectModulo + "/" + distinctNameOfProject + 
                "/" + classBeanSimpleName + "!" + classInterfaceName;  

        return finalNameOfEJB; 

        /**Ex:                 
           String nameofAppEAR= "";                            // EAR  (if there is)
           String nameOfProjectModulo= "MyFirstEJBProject";
           String distinctNameOfProject= "";                   // Alias (if there is)
           String classBeanSimpleName= MyFirstEJB.class.getSimpleName(); 
           String classInterfaceName=  MyFirstEJBRemote.class.getName();

           String finalNameOfEJB = "" + "/" + "MyFirstEJBProject" + "/" + "" + 
                "/" + MyFirstEJB.class.getSimpleName() + "!" + MyFirstEJBRemote.class.getName();

           The nameOfEJB appears on the console when the server is starting up:
           String nameOfEJB = "/MyFirstEJBProject/MyFirstEJB!src.ejb.MyFirstEJBRemote";   
         */
    }
}

Notes: I am using Wildfly(JBoss), so it is needed to import the jboss-client.jar at wildfly-10.0.0.Final\bin\client\ folder.