Platinum Partner
netbeans

Call EJBs Deployed in GlassFish from the NetBeans Platform

A lot of people have been asking whether it is possible to call an EJB deployed in GlassFish from a NetBeans Platform application. Should be simple, right? But it seems it's more complicated than expected:

http://netbeans.org/bugzilla/show_bug.cgi?id=125107
http://netbeans.org/bugzilla/show_bug.cgi?id=151368
http://forums.netbeans.org/viewtopic.php?t=37499

The last link above describes the problem of a user wanting to use the NetBeans Platform with Java SE 6 to call Session Beans deployed to GlassFish 3. Additional requirements are authentication, encryption, and using the same API on the client and the server. The user wants to use this code on the client:

System.setProperty("java.security.auth.login.config", "D:\\appclientlogin.conf");

GreeterBeanRemote greeterRemote = null;

Properties props = new Properties();
props.setProperty("org.omg.CORBA.ORBInitialHost", "10.1.1.13"); // default!
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700"); // default!

InitialContext context = new InitialContext(props);

ProgrammaticLogin login = new ProgrammaticLogin();
login.login("john.doe", "xxxxx");

greeterRemote = (GreeterBeanRemote) context.lookup("foo.bar.blubb.GreeterBeanRemote");

String output = greeterRemote.greetMe("John Doe");
System.out.printf("Got Answer:%ngreeting=%s%n", output);
So, let's create a simple example and see if we get this to work! I'm using NetBeans 7.0.1 with Glassfish 3.1 for the instructions below.

Server Side

We will start by implementing the GreeterBean, a simple "HelloWorld" EJB:

  1. In NetBeans IDE (I use 7.0.1), create a new EJB Module Project (New Project -> JavaEE -> EJB Module) and call it "HelloWorldEJB" and choose Glassfish Server 3.1 (default) as the server.

  2. Create a Client (New Project -> Java -> Java Application) and call it "GreeterClient". We'll use this to demo the use case in a non NetBeans Platform project, i.e, outside the NetBeans Platform.

  3. Inside "HelloWorldEJB", create a new Session Bean (New -> Enterprise Java Beans -> Session Bean), call it "GreeterBean" in package "foo.bar.blubb", make it stateless (default), and create remote interface (Create Interface -> Remote in Project). As Project, select GreeterClient.

  4. Add business logic to the GreeterBean (Right-click in editor and choose "Insert Code -> Add Business Method"). Method name is "greetMe", make it return a String instead of void and add a String parameter "name", and implement like this:
  5. @Override
    public String greetMe(String name) {
       return "Hello "+ name;
    }
    The system will automatically add the method definition to the interface as well.

  6. Now cut the GreeterBeanRemote interface from the GreeterClient Module foo.bar.blubb package and paste it in the HelloWorldEJB projects foo.bar.blubb package via drag & drop because one requirement is to reuse the server code in different projects, so we want everything in one place.

OK, that's the server part. You should now be able to deploy the project, and we can take care of the client side.

Client Side

First we'll try to get it to work in a standard Java Project. Afterwards, we'll port the code to the NetBeans Platform. We've already created a Java Application, "GreeterClient", which we can use for the standard Java client.

  1. In GreeterClient, open greeterclient.GreeterClient.java in the editor. Copy the code from the problem description with which this article started into the main method:
    System.setProperty("java.security.auth.login.config", "D:\\appclientlogin.conf");

    GreeterBeanRemote greeterRemote = null;

    Properties props = new Properties();
    props.setProperty("org.omg.CORBA.ORBInitialHost", "10.1.1.13"); // default!
    props.setProperty("org.omg.CORBA.ORBInitialPort", "3700"); // default!

    InitialContext context = new InitialContext(props);

    ProgrammaticLogin login = new ProgrammaticLogin();
    login.login("john.doe", "xxxxx");

    greeterRemote = (GreeterBeanRemote) context.lookup("foo.bar.blubb.GreeterBeanRemote");

    String output = greeterRemote.greetMe("John Doe");
    System.out.printf("Got Answer:%ngreeting=%s%n", output);

  2. Replace the location of the "D:\\appclientlogin.conf" with a real conf file on your machine. There is one in the Glassfish directory "<GLASSFISH_HOME>/lib/appclient/appclientlogin.conf".

  3. Replace the string "10.1.1.13" with "localhost" for our demo. Later, when running the client, if you see an error message starting with this line:
    org.omg.CORBA.COMM_FAILURE: FINE: IOP00410001: Connection failure: socketType: IIOP_CLEAR_TEXT; hostname: localhost; port: 3700  vmcid: OMG  minor code: 1  completed: No

    ...the reason may be that your port number is wrong. Above, it is 3700. Go to the GlassFish Admin Console, which is accessible from the GlassFish node in the Services window, and then look in Configurations | server-config | ORB | IIOP Listeners and use the listener port of "orb-listener-1".

  4. This will still leave you with a lot of errors due to missing dependencies. To fix those, right-click the project's Libraries node and choose "Add Project" from the context menu. Select "HelloWorldEJB" as the project. (Avoid the cyclic reference problem by removing the GreeterClient project from the Libraries node of the HelloWorldEJB first.) This should fix the first part of your imports.

  5. When the RemoteInterface was created in our GreeterClient, the system automatically added a "Java EE 6" library. Remove it. Instead, we'll add some GlassFish libraries. To do that, right click on the GreeterClient project node in the Projects window and choose Properties -> Libraries -> Add JAR/Folder to add the following jar files:

    •     appserv-rt.jar
    •     javaee.jar
    •     ejb.security.jar
    •     security.jar

    Update: Since Glassfish version 3, you can use gf-client.jar instead. It contains all the above dependencies. Note: You'll find the above in the $GLASSFISH_HOME/lib and the  $GLASSFISH_HOME/modules directory. 

  6. Now use the editor hint to throw the NamingException (add throws clause for javax.naming.NamingException).

We've now put everything together. The demo should work now as expected, once you run it, and you should get a response as follows:
Got Answer:
greeting=Hello John Doe


Port to the NetBeans Platform

Now, back to our problem... let's use this from the NetBeans Platform.

  1. Create a new NetBeans Platform Application (New Project -> NetBeans Modules -> NetBeans Platform Application).

  2. Create a module "GreeterClient", with code name base "de.eppleton.ejbclient".

  3. Create a new Library Wrapper module and wrap the 4 JARs we used before, that is, appserv-rt.jar, javaee.jar, ejb.security.jar, and security.jar. Name the module "security" and give it any code name base you want. 

  4. Create another Library Wrapper module and name it "ejb-container", wrapping the "ejb-container.jar" you'll find in <GLASSFISH_HOME>/modules/.

  5. Now create a third Library Wrapper module for the JAR file of the HelloWorldEJB project (HelloWorldEJB/dist/HelloWorldEJB.jar). If the "dist" dirrectory doesn't exist, do a "Clean & Build" on the HelloWorldEJB project first.

  6. In your GreeterClient module, create an Installer (New -> Installer/Activator) and, in the "restored()" method, add the code from your regular Java Client (including the customizations you made earlier). 

  7. Fix the imports, after adding the Library Wrapper modules you just created as dependencies, and surround the block with a try/catch as indicated by the editor hint.

  8. Now move to the NetBeans Platform Application project and locate the "project.properties" file. Insert this configuration code to put everything you need on the classpath and configure Corba settings:
  9. run.args.extra=-J-da -J-Dorg.omg.CORBA.ORBInitialHost=localhost -J-Dorg.omg.CORBA.ORBInitialPort=3700 \
                   -cp:a <GLASSFISH_HOME>/lib/appserv-rt.jar:<GLASSFISH_HOME>/lib/appserv-ext.jar:\
                         <GLASSFISH_HOME>/lib/appserv-deployment-client.jar:<GLASSFISH_HOME>/lib/javaee.jar:\
                         <GLASSFISH_HOME>/lib/jmxremote_optional.jar

    Replace <GLASSFISH_HOME> with the real locations on your machine. These settings put everything you need on the classpath. The classpath always takes precedence over the modules.

  10. Now run your application. You should see this, somewhere in your Output Window (not right at the end, but higher up):
    Got Answer:
    greeting=Hello John Doe

Troubleshooting

Originally I worked on a solution for Glassfish 3.1-b29 and earlier versions, where the above did not work due to conflicting ClassLoader Hierarchies. It seems that problem has been fixed in Glassfish in the meantime. Still, if the above doesn't work for you, and you're getting ClassNotFound Errors instead, you can temporarily switch to the Glassfish ClassLoader like this in the "restored()" method of the ModuleInstall class:

        ClassLoader prev = Thread.currentThread().getContextClassLoader();
        try {

            Thread.currentThread().setContextClassLoader(EJBUtils.class.getClassLoader());
            System.setProperty("java.security.auth.login.config", "<GLASSFISH_HOME>/lib/appclient/appclientlogin.conf");

            GreeterBeanRemote greeterRemote = null;
            Properties props = new Properties();
            props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
            props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");

            InitialContext context = new InitialContext(props);
            ProgrammaticLogin login = new ProgrammaticLogin();
            login.login("john.doe", "xxxxx");
            greeterRemote = (GreeterBeanRemote) context.lookup("foo.bar.blubb.GreeterBeanRemote");
            String output = greeterRemote.greetMe("John Doe");
            System.out.printf("Got Answer:%ngreeting=%s%n", output);
        } catch (NamingException ex) {
            Exceptions.printStackTrace(ex);

        } finally {
            Thread.currentThread().setContextClassLoader(prev);
        }
 
The problem now might be that the classloader can't see the GreeterBeanRemote. To fix that, you also need to add the HelloWorldEJB.jar to the Application classpath in the suite project.properties:
run.args.extra=-J-da -J-Dorg.omg.CORBA.ORBInitialHost=localhost -J-Dorg.omg.CORBA.ORBInitialPort=3700 \
               -cp <path_to_your>/HelloWorldEJB.jar:<glassfish_home>/glassfish/lib/gf-client.jar
{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}