Hot questions for Using Enterprise JavaBeans in wildfly 8

Question:

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.


Answer:

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

Question:

Wildfly 8.2.0

I have a Stateless EJB and an interface.

@Local
@Stateless
public class Bean implements IBean{
...
}

@Local
public interface IBean {
...
}

But I get a WELD Error. If Bean doesn't implement the interface there is no errors. According to https://stackoverflow.com/a/13988450/2023524 and https://blogs.oracle.com/arungupta/entry/what_s_new_in_ejb there should be no error.

Error:

WELD-001408: Unsatisfied dependencies for type Bean with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private mypackage.anotherBean.bean

Update: I've tried all possible combinations with Local but it doesn't help. Only if interface is removed there is no error.

@Stateless
public class Bean implements IBean{
...
}

@Local
public interface IBean {
...
}

//*****************************
@Stateless
public class Bean implements IBean{
...
}

public interface IBean {
...
}
//************************************
@Local
@Stateless
public class Bean implements IBean{
...
}

public interface IBean {
...
}

Answer:

When you want to inject a bean whether by EJB (using @EJB) or CDI (using @Inject) container you declare a variable with interface type. Concrete implementation of declared interface is found by a container during application deployment. In your example the problem is not with annotations but with a declared type being injected (Bean instead of IBean).

Question:

I'm trying to create EJB 3.2 Stateless Bean Project but still no avail until now. I hope anyone can help me.

Here is the EJB Project structure on my eclipse:

SLBean.java

package com.example.ejbtest;

import javax.ejb.Stateless;


@Stateless
public class SLBean implements SLBeanRemote {

    public SLBean() {
    }

    @Override
    public String sayHello() {
        return "Hello World !!!";
    }

}

SLBeanRemote.java

package com.example.ejbtest;

import javax.ejb.Remote;

@Remote
public interface SLBeanRemote {
    public String sayHello();
}

jboss-ejb-client.properties

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=4447
remote.connection.default.username=user1
remote.connection.default.password=password
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

Test.java

package com.example.ejbtest;

import java.util.Properties;

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

public class Test {

    public static void main(String[] args) {
        Context context;
        try {
            Properties properties = new Properties();
            properties.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming");
            properties.put("jboss.naming.client.ejb.context", true);
            context = new InitialContext(properties);

            String appName = "";
            String moduleName = "EJBTest";
            String distinctName = "";
            String beanName = SLBean.class.getSimpleName();
            String viewClassName = SLBeanRemote.class.getName();

            String ejbString = "ejb:" + appName + "/" + moduleName + "/"
                    + distinctName + "/" + beanName + "!" + viewClassName;

            System.out.println(ejbString);

            SLBeanRemote remote = (SLBeanRemote) context.lookup(ejbString);
            System.out.println(remote.sayHello());

        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
}

So after I run the EJBTest project on Wildfly Server through Eclipse, I run the Test.java as client program to connect to the remote stateless bean.

But what I got was error like this:

Exception in thread "main" java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:, moduleName:EJBTest, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@28d72e3f at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:749) at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116) at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)

Anyone can help?


Answer:

Ok, I found the answer. I had made two mistakes:

  1. I didn't put the jboss-ejb-client.properties file in correct place, i.e. the root of source folder (ejbModule).

  2. According to this article, the remote port for Wildfly 8 has been incorporated to port 8080, so I just need to change the remote.connection.default.port to 8080 in jboss-ejb-client.properties.

Question:

I'm currently struggling with getting remote EJB invocation to work on wildfly (8.x and 9.x).

In detail it's about remote invocation from a standalone client application (not from another app server) using the EJB Client API approach. The remote naming approach works for me but isn't applicable in my scenario because I need to use client-side interceptors for passing context data to a server-side interceptor for the remote invocations.

But for now I try to get remote invocations with the client API to work for a simple example. Therefore I tried the quickstart for remote ejb invocation which is available on github (wildfly/quickstart/ejb-remote). The point is that this quickstart raises the same error as my on simple sample app. Here are some details of my application:

My remote interface:

package test.ejb;

public interface HelloRemote {
  String greet(String name);
}

My Bean implementation:

package test.ejb;
import javax.ejb.Remote;
import javax.ejb.Stateless;

@Stateless(name = "Hello")
@Remote(HelloRemote.class)
public class HelloBean implements HelloRemote {

  public String greet(String name) {
    return "Hello " + name;
  }
}

The remote view of the bean is correctly registered at the server (in export namespace):

java:jboss/exported/ejb-test-backend.jar/Hello!de.coryx.HelloRemote

Here now the client side:

My Main class:

import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.ejb.client.EJBClientContext;
import test.ejb.HelloRemote;

public class Main {
  public static void main(String[] args) throws Exception {
    Properties props = new Properties();
    props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    Context context = new InitialContext(props);

    String jndiLookup = "ejb:/ejb-test-backend.jar/Hello!" + HelloRemote.class.getName();
    HelloRemote hello = (HelloRemote) context.lookup(jndiLookup);
    System.out.println(hello.greet("World"));
  }
}

The jboss-ejb-client.properties (packaged in jar/META_INF):

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

When I execute the main Method I get the following error message (same thing occurs when trying the wildfly quickstart that I mentioned above):

Exception in thread "main" java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:, moduleName:ejb-test-backend.jar, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@497470ed
    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:774)
    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
    at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
    at com.sun.proxy.$Proxy0.greet(Unknown Source)
    at Main.main(Main.java:16)

When I use the remote naming approach everything is fine:

Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
props.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
props.put("jboss.naming.client.ejb.context", true);
props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
Context context = new InitialContext(props);

String jndiLookup = "/ejb-test-backend.jar/Hello!" + HelloRemote.class.getName();
HelloRemote hello = (HelloRemote) context.lookup(jndiLookup);
System.out.println(hello.greet("World"));

Output here is (as expected):

Hello World

So is there anyone who knows what could be wrong here or better, who has a working example for remote EJB invocation on Wildfly using the EJB client API? Thanks in advance!


Answer:

As so often, I stumbled over the solution shortly after writing down the question and talking about it.

The problem with this setup was that the jboss-ejb-client.properties file has not been loaded by the client API which was then missing the connection url, ...

I don't know whether there where changes to the required location where these properties have to be placed or whether I was too dumb to read it correctly or whether I just adapted a tutorial that was corrupted. It doesn't even matter ;)

The solution is to place the properties file toplevel on the classpath and not in the META-INF directory of the JAR!

It works now as expected and I can register client-side interceptors.

Question:

I use Wildfly 8, SDK 1.7, and Intellij IDE and try to make basic ejb server.

I made the project which contains two child modules: interface and server.

Interface:

package testing;
...
@Remote
public interface Test {
public void sayHi();
}

Server:

package srv;
...
import testing.Test;

@Stateless
public class TestBean implements Test {

    @Override
    public void sayHi() 
    {
        System.out.println("Hi");
    }
}

The dependencies are javax.ejb.jar for both modules and jboss-client + my interface for server one. Everything compiles fine.

So, i tried to deploy server:ejb artifact into Wildfly, but it's unsuccessful:

ERROR [org.jboss.msc.service.fail] (MSC service thread 1-3) MSC000001: Failed to start service jboss.deployment.unit."server_ejb.jar".POST_MODULE: org.jboss.msc.service.StartException in service jboss.deployment.unit."server_ejb.jar".POST_MODULE: JBAS018733: Failed to process phase POST_MODULE of deployment "server_ejb.jar"
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:166) [wildfly-server-8.1.0.Final.jar:8.1.0.Final]
...
Caused by: java.lang.LinkageError: Failed to link srv/TestBean (Module "deployment.server_ejb.jar:main" from Service Module Loader)
...
Caused by: java.lang.NoClassDefFoundError: testing/Test
at java.lang.ClassLoader.defineClass1(Native Method) [rt.jar:1.7.0_67]
at java.lang.ClassLoader.defineClass(ClassLoader.java:800) [rt.jar:1.7.0_67]
at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:361) [jboss-modules.jar:1.3.3.Final]
at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:482) [jboss-modules.jar:1.3.3.Final]
... 19 more

Whats wrong?


Answer:

The EJB JAR contains one or more EJBs, including their interface definitions, any related Java classes that are being used by the EJBs, and a deployment descriptor describing these EJBs.

Given this exception:

Caused by: java.lang.NoClassDefFoundError: testing/Test

server_ejb.jar not include Test interface, you must include that in your deployment.

I hope this help.

Question:

I have a simple multimodule maven project with a war ejb and ear

When i am trying to access my ejb from a java pojo class using lookup it gives me class cast exception on wildfly it runs perfectly on jboss 7..

I have checked almost all the links related to this post please do help if anyone know how to resolve this..Here is my sample code:

My ejb interface:

package interfacejar;

import javax.ejb.Local;


public interface HelloWorldRemote {
       public String sayHello();       
       public void helloWait() ;  
}

Session Bean

@Stateless
public class HelloWorld implements Serializable, HelloWorldRemote {

    public String sayHello() {
        // TODO Auto-generated method stub
        return "hello";
    }

    public void helloWait(){
        // TODO Auto-generated method stub
    System.out.println("in ejb");   
    }



}  

My War Interface: //As i am accessing ejb from pojo class which is in different module of my maven project so it requires to create interface here also in this module

package interfacejar;

public interface HelloWorldRemote {
       public String sayHello();  

       public void helloWait() throws Exception;  
}

My Java class

public class Testnew{




    public HelloWorldRemote getProps(){
        HelloWorldRemote ref=null;
         try {
        Properties props = new Properties();
        props.setProperty("java.naming.factory.initial","org.jboss.as.naming.InitialContextFactory");
        props.setProperty("java.naming.provider.url", "localhost");
        props.setProperty("jboss.naming.client.ejb.context", "true");
        props.setProperty("java.naming.factory.url.pkgs", "org.jboss.ejb.client.naming");



            Context context = new InitialContext(props);

            Object obj =    context.lookup("java:global/MyEarFile/testejb-0.0.1-SNAPSHOT/HelloWorld!interfacejar.HelloWorldRemote");

             ref=(HelloWorldRemote) obj;

        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         return ref;

    }




        public void getRemote(){
            HelloWorldRemote ref=null;
            try {
                ref=getProps();

                ref.helloWait();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
            }

}

Servlet that calls this class

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub

    this.processRequest(request, response);

}

/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
 */
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    this.processRequest(request, response);
}
//java:global/MyEarFile/testejb-0.0.1-SNAPSHOT/HelloWorld!interfacejar.HelloWorldRemote*
/*@Resource(mappedName = "java:global/MyEarFile/tstwar-0.0.1-SNAPSHOT/HelloWorld!interfacejar.HelloWorldRemote")
private HelloWorldRemote helloWorldRemote;*/

protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("in servlet");

    Testnew testnew = new Testnew();
    testnew.getRemote();


}

This is the error that i got

21:06:49,205 ERROR [stderr] (default task-3) java.lang.ClassCastException: interfacejar.HelloWorldRemote$$$view4 cannot be cast to interfacejar.HelloWorldRemote

21:06:49,205 ERROR [stderr] (default task-3)    at com.test.Testnew.getProps(Testnew.java:43)

21:06:49,205 ERROR [stderr] (default task-3)    at com.test.Testnew.getRemote(Testnew.java:59)

Answer:

As i am accessing ejb from pojo class which is in different module of my maven project so it requires to create interface here also in this module

This is a mistake, to be honest I don't know how it worked for you on JBoss. You can't just create a class and cast into it, you need to add that module with session beans as a dependency to your war module.

Two classes, beside the same package and name, need to be loaded with the same class loader in order to be treated as the same class.