FAQ for Assignment 1: Remote-Access with JEE/EJB 3.0

Here are some tips on how to tackle assignment 1 regarding distributed transactions over two JEE containers using EJB 3.0 and the GlassFish open source JEE server from Sun which we are using so far.

Tip 1: Netbeans Configuration

We finally figured it out!
You should be able to re-use your Netbeans configuration without having to enter every detail every time again when you login:
  1. Create a comp5348 directory on your network drive U:
  2. Next, make sure that you see 'hidden files' in the Windows Explorer.
    (open windows explorer,
    select the menu 'Tools / Folder Options'
    select the 'View' tab
    enable 'Show hidden files and folders' option)
  3. Start Netbeans, do all your project work and JEE configuration
  4. After closing Netbeans, copy the
    C:\Documents and Settings\\.netbeans
    directory to U:\comp5348\
  5. Before starting Netbeans the next time, copy this .netbeans directory back from U:\comp5348 to C:\Documents and Settings\

Tip 2: How to tackle the assignment in general?

Your first step should be to analyse the existing project structure and to identify the function and source code location where a transfer between two accounts takes place.

This part of the source you will need to change. Several options on how to do this depending on how flexible you want be. In the one extreme case, you hard-code one account to be always the remote one (probably will not get maximum marks on the 'Design' component of the assignment). In the other, you extend the GUI and the parameters of the function and let the user enter a, say, BSB code per account. Something in between would be to have a business rule that, say, each account, whose id is in a certain range (e.g. below 1000), is located on the remote server. If you do this last approach, make sure to edit account numbers and the customer-account-relation accordingly in one of your two back-end databases.

Important: Duke's Bank assumes an US-style online banking scenario where end-users are typically only allowed to transfer money between accounts owned by the same user, but not to any other account...
For the purpose of this assignment, it is fine to assume that the same(!) user has accounts handled by two separate Duke's Bank instances. It is fine if you restrict this further to just remote Savings or Checkings accounts.

After you have decided on your application logic on where and how to decide whether a local or a remote Bank is accessed, you need to get hold of the remote application server. That is the most difficult thing of this assignment with the given application server. See Tip 3 for it.

Once you have a remote object reference, you must decide which object and method on it to invoke. There are again some choices, some more elegant than others. Rule of thumb: Try to avoid fine-grained remote entity bean access. This step also usually will involve additional exception / error handling because some new things can now go wrong which the original code does not cater for.

Finally, transaction semantic: You have to take care of two things here: That a transaction with the right boundaries is used in the first place; and that the data stores - both the local and the remote - are configured to be able to participate in a 2-Phase-Commit protocol (Tip: XA interface...)

Tip 3: How to lookup something in JNDI?

There are two principle ways on how to bind to a remote EJB from within a Java application server. Unfortunately, both have some hiccups or run into bugs with the current version of the GlassFish application server...

Injecting an EJB Reference

This is the preferred approach for EJB 3.0 (which we are using), BUT it will run into a GlassFish bug at the end of a 2PC commit... (at least up to there it should work ;})

  1. Find out the IP address of your remote server; let's call it REMOTE-HOST
  2. The standard remote access port is 3700 (see tip 5 below)
  3. Import the EJB package:
    import javax.ejb.EJB;
    
  4. You can now 'inject' a remote object reference to a type RemoteObjectType using EJB 3 as follows: Add a new instance variable at the start of your local EJB which has to access the remote server:
      @EJB(mappedName="corbaname:iiop:REMOTE-HOST:3700#RemoteObjectType"))
      RemoteObjectType remoteBank;
    
    The Java application server will now automatically look up this remote object and create a stub object to the remote server under the name remoteBank in your program. You can thereafter just normally use the remoteBank object according to its interface specification. Note: No manual new() or lookup() call is needed anymore.
    RemoteObjectType is one of the entity bean types available in DukesBank. As described in Tip 2, which entity bean type that is depends on your design choice. Important: RemoteObjectType must have a remote interface... (Home interface declared @Remote)
    Again: The problem is that we are running with this apparently into a bug with the application server which we are using so far; a distributed commit seems to hang... We are currently checking whether other open source application servers such a JonAS or JBoss behave better...
  5. You can combine this method with an explicit user-defined name for your EJB as described in Tip 5. The part after the '#' in the 'mappedName' above would then become the name that you have explicitly configured as JNDI name entry.

Remote JNDI Lookup

The second approach is to do this remote object lookup manually. There are some code snippets on the Internet which explain various variants of it. However, they all assume that you access a JEE container object from a standalone Java application. In our case however, we try to call from one GlassFish JEE server to another - and again we seem to run into some limitations of that current version...

  1. Find out the IP address of your remote server; let's call it REMOTE-HOST
  2. The standard remote access port is 3700 (see tip 5 below)
  3. Add a few imports for stuff we will need in the java source file
    import java.util.Properties;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    
  4. At the source-code location, where you need access to a remote EJB, insert this code that looks-up the remote JNDI of the second server for the instance of RemoteObjectType:
    try
    {
        Properties p = new Properties();
        p.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
        p.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
        p.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
        p.setProperty("org.omg.CORBA.ORBInitialHost", REMOTE-HOST);
        p.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
    
        InitialContext ctx = new InitialContext(p);
        RemoteObjectType remoteBank = (RemoteObjectType) ctx.lookup(RemoteObjectType);
    }
    catch ( required exceptions... ) { ... }
    

    After that, you should be able to use remoteBank as normal. However: When we tried it on our own GlassFish installation ,we always got returned a lookup from the local JNDI, as if the properties for the ORB call were ignored... I tend to count this also as a GlassFish bug, but have not found a corresponding bug description yet... if anyone has success with this method (2), please drop us an email ;)

  5. You might want to combine this method with the naming of the object in Tip 5...

Help with EJB programming using GlassFish in general...

See also the official FAQ for the GlassFish JEE container that we are using...
But note that it never really talks about JEE - to - JEE communication, but always assumes standalone Java program to JEE server...

Tip 4: Ports...

Two JEE application servers can communicate via remote procedure call over IIOP (Inter ORB Protocol); bot the JNDI lookups on remote servers and the invocations of methods on remote servers use this IIOP protocol, which means that one port serves both cases. The standard IIOP for GlassFish port is 3700.

If you try things on you own computer, be sure that this port is not blocked...

Tip 5: How to give an EJB a readable name via JNDI

In Netbeans, open you project and navigate to the Sources of the 'request' module; open the configuration tab and edit the ejb-jar.xml file:

It will look something like this:

<sun-ejb-jar>
  <enterprise-beans/>
</sun-ejb-jar>

Replace the empty

 part with this:

<enterprise-beans>
    <ejb>
      <ejb-name>TxControllerBean</ejb-name>
      <jndi-name>My Super New Name</jndi-name>
    </ejb>
</enterprise-beans>

Tip 6: 2PC for Distributed Transfer Transactions

Make sure that your two containers can run a 2-Phase-Commit protocol over the involved data sources. The Derby instances that come with our installation are by default not configured to accept 2PC via XA... You need to configure them in the application server correctly (correct type and correct driver!).

Tip 7: Same JEE user name (application level) on both machines

Make sure you have configured the very same java application user name in each JEE application that should talk to each other - with the same password! So in our case, for example, following the notes from tutorials in week 2 etc, there should be a user 200 with the same password configured in both application servers that are communicating with each other.

Also make sure that there is no OS-level security enabled for the IIOP connection. That is actually the default, so should not be changed! IIOP security should be kept disabled.