How to create a simple EJB3 project in Eclipse (JBoss 7.1)

Environment Used

  • JDK 6 (Java SE 6)
  • EJB 3.0 (stateless session bean)
  • Eclipse Indigo IDE for Java EE Developers (3.7.1)
  • JBoss Tools – Core 3.3.0 M5 for Eclipse Indigo (3.7.1)
  • JBoss Application Server (AS) 7.1.0.CR1b / Final

Setting up development environment:
Read this page for installing and setting up the environment for developing and deploying EJB 3.0 Session bean on JBoss application server.

Project Description:

  • We are going to create a simple EJB 3 HelloWorld stateless session bean project and a remote Java application client which will call/invoke the bean.
  • This “HelloWorld” example explains how to develop, deploy and run EJB3 Session Bean (stateless and stateful) in JBoss application server.
  • For testing this “HelloWorld” example we write a remote Java Application Client (main() method).
  • For simplicity, the session bean and the client to access the session bean are created in the same project.

Creating New EJB Project

  • Open Eclipse IDE and create a new EJB project which can be done in three ways,
    • Right click on Project Explorer -> New -> EJB Project
    • File menu -> New -> EJB Project
    • Click on the down arrow on New icon on toolbar -> EJB Project

  • Enter the project name as “HelloWorldSessionBean” and make sure the JBoss 7.1 Runtime has been selected with the EJB 3.0 Module version.

  • Click Next -> Next -> and Finish.
  • You will see an EJB project in the Project Explorer view.

Creating Session Bean and Bean Interface

  • Right click on ejbModule -> New -> Session Bean (EJB 3.x)

  • Enter the Java package name as com.ibytecode.businesslogic
  • Enter the Class name as HelloWorldBean
  • Select the State type as Stateless
  • Check the Remote Business Interface and enter the name as com.ibytecode.business.HelloWorld. The business interface will be created in different package (com.ibytecode.business)
  • Click Finish

Coding Bean and the Interface

  • Open Bean Interface and type the following code and save the file (Ctrl+s).
  • Interface can be either @Remote or @Local. In this example we have used @Remote.
package com.ibytecode.business;
import javax.ejb.Remote;

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

  • Open Bean and type the following code and save the file.
  • Bean type can either be @Stateful or @Stateless. In this example we have used @Stateless.
package com.ibytecode.businesslogic;

import com.ibytecode.business.HelloWorld;
import javax.ejb.Stateless;

@Stateless
public class HelloWorldBean implements HelloWorld {
    public HelloWorldBean() {
    }

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

Now the Stateless Session Bean has been created. The next step is to deploy the bean on the server.

Deploying EJB project

  • Now we need to deploy the stateless session bean “HelloWorldBean” on server.
  • Deploying the project can be done in two ways,
    • Right click on the EJB project -> Run As -> Run On Server. Select the existing “JBoss 7.1 Runtime Server” and click Finish.
    • Right click on “JBoss 7.1 Runtime Server” available in Servers view -> Add and Remove… -> Select the EJB JAR file from the left pane and click Add-> and then Finish.

Start/Restart the Server

Right click on “JBoss 7.1 Runtime Server” from Servers view and click on Start if it has not yet been started.
If the project is deployed properly with global JNDI mapping then you will see the following message in the console.

Creating Client

  • The next step is to write a remote Java client application (with main()) for accessing and invoking the EJBs deployed on the server
  • Client uses JNDI to lookup for a proxy of your bean and invokes method on that proxy.

Creating JNDI InitialContext

Obtaining a Context using InitialContext

  • All naming service operations are performed on some implementation of the javax.naming.Context interface. Therefore, the starting point of interacting with the naming service is to obtain a Context by providing the properties specific to the server implementation being used. In our case it is, JBoss Application Server.
  • To create a javax.naming.InitialContext, we need to initialize it with properties from the environment. JNDI verifies each property’s value by merging the values from the following two sources,
    • Using parameterized constructor of InitialContext which takes properties of supplied environment
    • jndi.properties resource files found on the classpath.

NOTE:We will use parameterized constructor for initializing the InitialContext.

For JBoss AS 7 we need to set the Context.URL_PKG_PREFIXES property with value “org.jboss.ejb.client.naming” to obtain the InitialContext.

The following utility class is used to create InitialContext for JBoss AS and can be reused in all applications. Otherwise the code written in this class should be repeated in all clients.

  • Right click on ejbModule -> New -> Class
  • Enter the package name as com.ibytecode.clientutility
  • Enter the Class name as ClientUtility
  • Click on Finish

package com.ibytecode.clientutility;

import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ClientUtility {

	private static Context initialContext;

	private static final String PKG_INTERFACES = "org.jboss.ejb.client.naming";

	public static Context getInitialContext() throws NamingException {
		if (initialContext == null) {
			Properties properties = new Properties();
			properties.put(Context.URL_PKG_PREFIXES, PKG_INTERFACES);

			initialContext = new InitialContext(properties);
		}
		return initialContext;
	}
}

Creating client class

  • Right click on ejbModule -> New -> Class
  • Enter the package name as com.ibytecode.client
  • Enter the Class name as EJBApplicationClient
  • Check the main() method option
  • Click on Finish

package com.ibytecode.client;

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

import com.ibytecode.business.HelloWorld;
import com.ibytecode.businesslogic.HelloWorldBean;
import com.ibytecode.clientutility.ClientUtility;

public class EJBApplicationClient {
	
	public static void main(String[] args) {
		HelloWorld bean = doLookup();
		System.out.println(bean.sayHello()); // 4. Call business logic
	}

	private static HelloWorld doLookup() {
		Context context = null;
		HelloWorld bean = null;
		try {
			// 1. Obtaining Context
			context = ClientUtility.getInitialContext();
			// 2. Generate JNDI Lookup name
			String lookupName = getLookupName();
			// 3. Lookup and cast
			bean = (HelloWorld) context.lookup(lookupName);

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

	private static String getLookupName() {
/* 
The app name is the EAR name of the deployed EJB without .ear suffix. 
Since we haven't deployed the application as a .ear, 
the app name for us will be an empty string
*/
		String appName = "";

		/* The module name is the JAR name of the deployed EJB 
        without the .jar suffix.
		*/
		String moduleName = "HelloWorldSessionBean";

/*AS7 allows each deployment to have an (optional) distinct name. 
This can be an empty string if distinct name is not specified.
*/
		String distinctName = "";

		// The EJB bean implementation class name
		String beanName = HelloWorldBean.class.getSimpleName();

		// Fully qualified remote interface name
		final String interfaceName = HelloWorld.class.getName();

		// Create a look up string name
		String name = "ejb:" + appName + "/" + moduleName + "/" + 
			distinctName 	+ "/" + beanName + "!" + interfaceName;

		return name;
	}
}

Setting up EJB client context properties

An EJB client context is a context which contains contextual information for carrying out remote invocations on EJBs. This is a JBoss AS specific API. The EJB client context can be associated with multiple EJB receivers. Each EJB receiver is capable of handling invocations on different EJBs.
For example, an EJB receiver “ClientA” might be able to handle invocation on a bean identified by app-A/module-A/distinctinctName-A/BeanA!com.ibc.RemoteBeanA, app-B/module-B/distinctName-B/BeanB!RemoteBeanB, etc. Each such EJB receiver knows about what set of EJBs it can handle and each of the EJB receiver knows which server target to use for handling the invocations on the bean. The server IP address and its remoting port should be specified in the properties file placed in the client classpath. This properties file (EJB client context) will then be used internally by the JNDI implementation to handle invocations on the bean proxy.

Create a file “jboss-ejb-client.properties” in the classpath of the application. We can place it in ejbModule folder of our application. The jboss-ejb-client.properties contains the following properties:

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

Adding JAR files required for the client to run the client application

  • Open Run Configurations… in Run menu or Run Configurations in Run icon

  • Select the client application (EJBApplicationClient) under Java Application from left pane and open the Classpath tab from right side pane. If you don’t see your client application, run it once. Select “User Entries” and click on “Add External JARs”

  • Add the following JAR files.
    JAR name Location
    jboss-transaction-api_1.1_spec-1.0.0.Final.jar AS7_HOME/modules/javax/transaction/api/main/
    jboss-ejb-api_3.1_spec-1.0.1.Final.jar AS7_HOME/modules/javax/ejb/api/main/
    jboss-ejb-client-1.0.0.Beta10.jar AS7_HOME/modules/org/jboss/ejb-client/main/
    jboss-marshalling-1.3.0.GA.jar AS7_HOME/modules/org/jboss/marshalling/main/
    xnio-api-3.0.0.CR5.jar AS7_HOME/modules/org/jboss/xnio/main/
    jboss-remoting-3.2.0.CR6.jar AS7_HOME/modules/org/jboss/remoting3/main/
    jboss-logging-3.1.0.Beta3.jar AS7_HOME/modules/org/jboss/logging/main/
    xnio-nio-3.0.0.CR5.jar AS7_HOME/modules/org/jboss/xnio/nio/main/
    jboss-sasl-1.0.0.Beta9.jar AS7_HOME/modules/org/jboss/sasl/main/
    jboss-marshalling-river-1.3.0.GA.jar AS7_HOME/modules/org/jboss/marshalling/river/main/

    You can also add it in Build path (Right click on your EJB Project->Properties, select Java Build Path from left side pane and select Libraries from right side and click on Add External JARs)

If you are using JBoss Application Server (AS) 7.1.0 Final version then it is sufficient to add only one client JAR file (jboss-client-7.1.0.Final.jar) which is located in AS7_HOME/bin/client

The figure below shows the final directory structure of this example.

Run the client

Use Ctrl + F11 to run the client.

Hello World !!!

Showing 3 comments
  • javier abaroa
    Reply

    Hello;

    Very useful code. The client utility is an interesting option to introduce constant PKG_PARAMETERS for the EJB client call to jboss-server.

    For all people interested in Wildfly utilisation (Wildfly 17.0.1 Versión is that i used), the parameters for correct use are:

    PKG_FACTORY = “org.wildfly.naming.client.WildFlyInitialContextFactory”;
    PKG_PROVIDER_URL = “remote+http://localhost:8080”;

    Made the following modification to the utility for obtain the initialContext:

    public class ClientUtility {

    private static Context initialContext;
    private static final String PKG_PROVIDER_URL = “remote+http://localhost:8080”;
    private static final String PKG_FACTORY = “org.wildfly.naming.client.WildFlyInitialContextFactory”;

    public static Context getInitialContext() throws NamingException {
    if (initialContext == null) {
    final Hashtable jndiProperties = new Hashtable();
    jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, PKG_FACTORY);
    jndiProperties.put(Context.PROVIDER_URL,PKG_PROVIDER_URL);
    initialContext = new InitialContext(jndiProperties);
    }
    return initialContext;
    }

    }

    • Sher Ali Khan
      Reply

      Hi javier abaroa,

      Can you please share you wildfly and EJB project

  • javier abaroa
    Reply

    I have missed to say, that in wildfly 17, is not needed te pkg_prefixes parameter for the ClientUtility, only with the initialFactory and with the remoteURL, the client will be able to locate the remote bean.

    All the rest of the code is the same, except that in jboss-ejb-client.properties, the port is 8080 instead of 4447 and that the only jars needed for the ejb-client are; (Added in Build-Path with the following order in my code, you can obtain in maven repository and in wildfly_17_bin/client/ server folder);

    Added with “External jars”, downloaded from Maven Repository:

    jboss-ejb-api_3.2_spec-1.0.2-final.jar

    jboss-logging-3.4.1-final-jar

    Added with “External jars” from the /bin/client folder of the Wildfly-17.0.1 server installation folder:

    jboss-client.jar

    Added with option “Add-Library” of the “Build Path” option of Project -> Properties:

    EAR Libraries

    JBoss EJB 3.x Libraries

    JRE System Library(jre1.8.0_221) ; (Runtime created from Oracle jdk_1.8u221)

    Wildfly 17 Runtime ; (Runtime created updating JBoss Tools from Market Place to last version and creating a new Wildfly 17.0.1 Server.)

    Perhaps not all that jars are needed and only with JBoss EJB 3.x and the jboss-client.jar, the client be able to locate the bean, but in my case, the project have success.

    Sorry for the mistakes and for the extension of that message.

    Thanks to Nythia Vasudevan for that excellent article.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.