Hot questions for Using Enterprise JavaBeans in wildfly 10

Question:

I have a problem with my EJBTest.

I have installed WildFly and configured user management and application management.

I wrote an EJB 3.0 and deployed it:

@Stateless
@Remote(NewSessionBeanRemote.class)
public class NewSessionBean implements NewSessionBeanRemote {

    List<String> bookShielf;

    /**
     * Default constructor. 
     */
    public NewSessionBean() {
        bookShielf = new ArrayList<String>();
    }

    @Override
    public void addBook(String bookName) {
        bookShielf.add(bookName);
    }

    @Override
    public List getBook() {
        return bookShielf;
    }
}

Afterwards, I wrote a simple client to connect it:

private static void invokeStatelessBean() throws NamingException {
    // Let's lookup the remote stateless calculator
    NewSessionBeanRemote remoteEjb = lookupRemoteSessionBean();
    System.out.println("Obtained a remote stateless calculator for invocation");
    String bookName = "TEST book";
    remoteEjb.addBook(bookName);
}

private static NewSessionBeanRemote lookupRemoteSessionBean() throws NamingException {

    final Hashtable jndiProperties = new Hashtable();
    jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
    jndiProperties.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:10090");
    jndiProperties.put(Context.SECURITY_PRINCIPAL, "ejb"); //this is the application user name, not management! it's correct?
    jndiProperties.put(Context.SECURITY_CREDENTIALS, "ejb");//this is the application password, not management! it's correct?
    jndiProperties.put("jboss.naming.client.ejb.context", true);
    final Context context = new InitialContext(jndiProperties);
    final String appName = "";
    final String moduleName = "EjbComponent";
    final String distinctName = "";
    final String beanName = NewSessionBean.class.getSimpleName();
    final String viewClassName = NewSessionBeanRemote.class.getName();
    System.out.println("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);
    return (NewSessionBeanRemote) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);
}

Both username and password are the application user credential, not management! Is it correct?

I'm receiving this error:

Exception in thread "main" java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:, moduleName:EjbComponent, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@5034c75a at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798) at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:128) 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.$Proxy2.addBook(Unknown Source) at com.studio.java.client.EjbTester.invokeStatelessBean(EjbTester.java:34) at com.studio.java.client.EjbTester.main(EjbTester.java:21)

I don't know why! Anyone have an idea?


Answer:

You're receiving the mentioned error because you're trying to access a remote EJB using the absolute JNDI name.

As stated by the documentation:

The http-remoting client assumes JNDI names in remote lookups are relative to java:jboss/exported namespace, a lookup of an absolute JNDI name will fail.

So, after you've deployed your application on WildFly, you should see something like this on your server console:

JNDI bindings for session bean named NewSessionBean in deployment unit deployment <your_deployment_unit> are as follows:

    java:global[/<application_name>]/<module_name>/<ejb_name>[!<interface_name>]
    java:app[/<module_name>]/<ejb_name>[!<interface_name>]
    java:module/<ejb_name>[!<interface_name>]
    java:jboss/exported[/<application_name>]/<module_name>/<ejb_name>[!<interface_name>]
    java:global/[/<application_name>]/<module_name>/<ejb_name>
    java:app[/<module_name>]/<ejb_name>
    java:module/<ejb_name>

Therefore, taking into account the java:jboss/exported context, the correct way of attaining your EJB should be:

// Normally the appName is the EAR name
// Leave it empty if your application isn't packaged in a EAR
String appName = "your_application_name/";
// The EJB module name
String moduleName = "ejb_module_name/";
String beanName = NewSessionBean.class.getSimpleName();
String viewClassName = NewSessionBeanRemote.class.getName();

(NewSessionBeanRemote) context.lookup(appName + moduleName + beanName + "!" + viewClassName);

For further reading, I'd suggest you also to take a look at the Java EE JNDI Syntax as well as to WildFly's JNDI Reference.

Regarding your credentials, they're not necessary since your EJB does not require any type of authentication in order for you to access it. Normally, that's only necessary when you have, for example, an application that uses a LDAP service provider.

Question:

WildFly 10.0.0-final

Infinispan 8.1.0-Final

Im working with 2 nodes same config standalone-full-ha

/subsystem=infinispan/cache-container=infinispan_cache:add( aliases=["infinispan_cache-alias"], default-cache=default_cache, start=LAZY)
/subsystem=infinispan/cache-container=infinispan_cache/transport=TRANSPORT/:add(lock-timeout=60000, stack=tcp)
/subsystem=infinispan/cache-container=infinispan_cache/replicated-cache=default_cache:add(mode=ASYNC)

I get the cache in this way

@Resource(lookup = "java:jboss/infinispan/cache/infinispan_cache/default_cache")
private org.infinispan.Cache<String, Object> cache;

I'm using putForExternalRead then the other node knows the value using get, the other side, everything go well, but when I use get from the node witch put the value, returns null.

cache.putForExternalRead("hola","Hola prueba");
Object o = cache.get("hola");//This o is null

Answer:

The solution was to configure properly Jgroups with TCP stack and my own Cache under batch SYNC transaction

<subsystem xmlns="urn:jboss:domain:infinispan:4.0">
        ...
        <cache-container name="my_infinispan_cache" aliases="my_infinispan_cache-alias" default-cache="default_cache">
            <transport lock-timeout="60000"/>
            <replicated-cache name="default_cache" mode="SYNC">
                <locking isolation="READ_COMMITTED"/>
                <transaction locking="OPTIMISTIC" mode="BATCH"/>
                <eviction strategy="NONE" max-entries="-1"/>
                <expiration lifespan="-1" max-idle="-1"/>
            </replicated-cache>
        </cache-container>
    </subsystem>
    ...
    <subsystem xmlns="urn:jboss:domain:jgroups:4.0">
        <channels default="ee">
            <channel name="ee" stack="tcp"/>
        </channels>
        <stacks>           
            <stack name="udp">
                ...
            </stack>
            <stack name="tcp">
                <transport type="TCP" socket-binding="jgroups-tcp"/>
                <protocol type="MPING" socket-binding="jgroups-mping"/>
                <protocol type="MERGE3"/>
                <protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
                <protocol type="FD"/>
                <protocol type="VERIFY_SUSPECT"/>
                <protocol type="pbcast.NAKACK2"/>
                <protocol type="UNICAST3"/>
                <protocol type="pbcast.STABLE"/>
                <protocol type="pbcast.GMS"/>
                <protocol type="MFC"/>
                <protocol type="FRAG2"/>
            </stack>
        </stacks>
    </subsystem>