Hot questions for Using Enterprise JavaBeans in initial context

Question:

When we create a new InitialContext for remote access to Enterprise Java Beans, after work is done, should we always close the context via context.close() ?

Here is a code sample:

// Client side method
private void doSomeActionMethod() {
    RouteTransactionFacadeBeanRemote remote = null;
    final Hashtable jndiProperties = new Hashtable();
    jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    Context context = null;
    try {
        context = new InitialContext(jndiProperties);
        remote = (RouteTransactionFacadeBeanRemote) context
                 .lookup("ejb:EJBEAR/EJBServer//RouteTransactionFacadeBean!facade.RouteTransactionFacadeBeanRemote");

        //DO SOMETHING WITH REMOTE EJB

        } catch (NamingException e) {
            e.printStackTrace();
        } finally {
            try {
                // Should we always do this?
                if (context != null) context.close();
            } catch (NamingException ex) {
                ex.printStackTrace();
            }
        }
    }

Answer:

From javadocs:

Closes this context. This method releases this context's resources immediately, instead of waiting for them to be released automatically by the garbage collector. This method is idempotent: invoking it on a context that has already been closed has no effect. Invoking any other method on a closed context is not allowed, and results in undefined behaviour.

Although, garbage collector will collect them but instead of waiting for gc, you should close it by the provided function. So, my answer is, yes you should close this as well as any other resource that should be closed.

Question:

I am trying to set a new InitialContext in the following manner (which is pretty standard I believe):

private static InitialContext getInitialContext() throws NamingException {

    InitialContext context = null;

    try {
        Properties properties = new Properties();
        properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
        properties.put(Context.PROVIDER_URL, "remote://localhost:4447");
        properties.put(Context.SECURITY_PRINCIPAL, "username");
        properties.put(Context.SECURITY_CREDENTIALS, "password");
        context = new InitialContext(properties);
        System.out.println("\n\tGot initial Context: " + context);
    } 
    catch (Exception e) {
        e.printStackTrace();
    }
    return context;
}

public static void sendMessage(RoboticsParameters object_msg) throws Exception {

    InitialContext context = getInitialContext();

    // other code
}

The code "fails" at the line where the new InitialContext is created using the properties and i get a java.lang.NullPointerException. I suspect I am missing an argument. Here is the stack trace:

WARN: EJB client integration will not be available due to a problem setting up the EJB client handler java.lang.NullPointerException
at org.jboss.naming.remote.client.InitialContextFactory.<clinit>(InitialContextFactory.java:118)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:72)
at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:61)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:672)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.InitialContext.<init>(InitialContext.java:216)

Any suggestions?

I am running JBoss EAP 6.4 and using EJB 3. I have jboss-client.jar in the class path.


Answer:

I checked the source code for:

jboss-remote-naming/src/main/java/org/jboss/naming/remote/client/InitialContextFactory.java

and found where the log message was coming from:

public class InitialContextFactory implements javax.naming.spi.InitialContextFactory {
    // code
    private static final String REMOTE_NAMING_EJB_CLIENT_HANDLER_CLASS_NAME = "org.jboss.naming.remote.client.ejb.RemoteNamingStoreEJBClientHandler";
    // code
        try {
            klass = classLoader.loadClass(REMOTE_NAMING_EJB_CLIENT_HANDLER_CLASS_NAME);
            method = klass.getMethod("setupEJBClientContext", new Class<?>[] {Properties.class, List.class});
        } catch (Throwable t) {
            logger.warn("EJB client integration will not be available due to a problem setting up the EJB client handler", t);
        }
    // other code
}

The class org.jboss.naming.remote.client.ejb.RemoteNamingStoreEJBClientHandler was in the jar that I added to the class path but for some reason there were problems loading the class.

Then I stumbled upon this small README-EJB-JMS.txt file in the [jboss_home]/bin/client folder which states the following:

"Maven users should not use this jar, but should use the following BOM dependencies instead

<dependencies>
    <dependency>
        <groupId>org.jboss.as</groupId>
        <artifactId>jboss-as-ejb-client-bom</artifactId>
        <type>pom</type>
    </dependency>
    <dependency>
        <groupId>org.jboss.as</groupId>
        <artifactId>jboss-as-jms-client-bom</artifactId>
        <type>pom</type>
    </dependency>
</dependencies>

This is because using maven with a shaded jar has a very high chance of causing class version conflicts, which is why we do not publish this jar to the maven repository."

So, I added the maven dependency instead of having the jar in my class path and VOILA! It works!

Question:

This issue is very common. I have read some articles but can't find the problem. I want to create a simple HelloWorld program in EJB 3.0, eclipse luna, jboss 7.1.1 Final.

Here is my bean:

package com.tcs.HelloWorldPack;

import javax.ejb.Stateless;

/**
 * Session Bean implementation class HelloWorld
 */
@Stateless(mappedName="HelloWorldBean")
public class HelloWorld implements HelloWorldRemote {

    /**
     * Default constructor. 
     */
    public HelloWorld() {
        // TODO Auto-generated constructor stub

    }

    @Override
    public void displayMsg() {
        // TODO Auto-generated method stub 
        System.out.println("Hello World!!");

    }

}

Here is my remote interface:

package com.tcs.HelloWorldPack;

import javax.ejb.Local;
//import javax.ejb.Remote;
import javax.ejb.Remote;

@Remote
public interface HelloWorldRemote {

    void displayMsg();
}

Here is my client which is running in the same machine:

package com.tcs.HelloWorldClient;

import java.util.Hashtable;
import java.util.Properties;

import com.tcs.HelloWorldPack.*;

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

public class HelloWorldClient {


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


        final Hashtable jndiProperties = new Hashtable();
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        jndiProperties.put(javax.naming.Context.SECURITY_PRINCIPAL, "myUser");
        jndiProperties.put(javax.naming.Context.SECURITY_CREDENTIALS, "myPass");
//        jndiProperties.put(javax.naming.Context.PROVIDER_URL, "jnp://localhost:1099");
//        jndiProperties.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
        jndiProperties.put("jboss.naming.client.ejb.context", true);

        final Context context = new InitialContext(jndiProperties);

        final String appName= "HeloWorldEJBEAR";
        final String moduleName= "";
        final String distinctName ="";
        final String beanName = "HeloWorld";
        final String viewClassName = "com.tcs.HelloWorldPack.HelloWorldRemote";
        HelloWorldRemote hello = (HelloWorldRemote) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);

        hello.displayMsg();


    }

}

This is my jboss-ejb-client.properties file:

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.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

remote.connection.default.username=myUser
remote.connection.default.password=myPass

I have put the properties file in the classpath also.But this is happening when I am trying to run it:

Exception in thread "main" java.lang.IllegalStateException: No EJB receiver available for handling [appName:HeloWorldEJBEAR,modulename:,distinctname:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@413ded77
    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:584)
    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:119)
    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:181)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:136)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:121)
    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:104)
    at com.sun.proxy.$Proxy0.displayMsg(Unknown Source)
    at com.tcs.HelloWorldClient.HelloWorldClient.main(HelloWorldClient.java:71)
Jan 08, 2015 3:34:44 PM org.jboss.ejb.client.remoting.ChannelAssociation$ResponseReceiver handleEnd
INFO: Channel Channel ID de8d2aa6 (outbound) of Remoting connection 44477156 to localhost/127.0.0.1:4447 can no longer process messages

I have also uploaded my directory structure. I am new to the EJB concept. Please help me to find where is the problem. Thanks in advance.


Answer:

Your module name is an empty String, but the module name can't be an empty string in the JNDI name. Look here

you have to set the name of your ejb module .jar, without the .jar suffix.

final String moduleName = "HeloWorldEJB";

Then it should work.