So here I was, cleanly splitting out the service EJB and web front of an application. We even went so far as to have the two components run in separate JBoss instances, on separate machines. But… they had to communicate to each other through a JNDI lookup. That’s where we ran into a ditch, fought with Java and JBoss settings for a few days and came out victorious. Let me help you stay out of these trenches and show how to configure this.
First let me describe the setup of the machines we used. We have two machines in our hosting environment, one of which is accessible from the outside world, let’s call this one Whiskey. Whiskey is part of two networks, one goes out to the real world, the other stays on our internal network. The other machine, Sierra, can only be reached from the internal network. Whiskey talks to this machine through its internal interface.
Whiskey is supposed to run our Web-application and delegate service calls to Sierra. No big surprises there. Both machines run JBoss 4.3 on Red Hat Linux. Sierra registers an EJB bean in its JNDI registry and accepts service calls through RMI. All Whiskey has to do is lookup the EJB in Sierra’s JNDI and make calls to the returned object. Sounds easy right?
The first try included googling for the words ‘connect jndi jboss’. You get all sorts of hits on how to connect to things in a JNDI registry, but not on how to incorporate one server’s JNDI into another. If you keep googling and change your keywords to ‘integrate jndi jboss’, you get a little closer, but the words you are looking for are ‘federate jndi jboss’. This will eventually lead to something called the ExternalContext.
The org.jboss.naming.ExternalContext MBean makes it possible to integrate the JNDI directory of one server into another. Since it is itself registered under a JNDI name, every lookup beneath that node is delegated to the other server. For example, if you bind the ExternalContext under /external, then /external/my-service-bean will lookup /my-service-bean in the remote JNDI. In pictures, it comes down to this:
Let’s get down to business and see how we can configure this. There are several ways to get an MBean fired up in JBoss, but since this one should be around all the time (at least at our setup), we put it in the conf/jboss-service.xml file of the Whiskey server. The definition looks somewhat like this:
<!-- Declare the MBean, make sure its name is unique within JBoss --> <mbean code="org.jboss.naming.ExternalContext" name="jboss.jndi:service=ExternalContext,server=Sierra"> <!-- This denotes the JNDI name under which the remote tree is federated --> <attribute name="JndiName">external</attribute> <!-- Enter the environment settings for the Context --> <attribute name="Properties"> java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=jnp://<sierra's IP>:1099 </attribute> <!-- Set the type of InitialContext, can also be LDAP or other Contexts --> <attribute name="InitialContext">javax.naming.InitialContext</attribute> <!-- Declare whether this name is accessible from remote clients calling Whiskey's JNDI --> <attribute name="RemoteAccess">false</attribute> </mbean>
Okay, so now we have a federated JNDI tree and can access JNDI entries which were bound in Sierra from Whiskey. Cool, but our application does not point to /external/my-service-bean, it points to /my-service-bean and I don’t want to recompile it or otherwise change it. No worries, this can be resolved by creating a JNDI alias. By creating a file my-service.xml in the /deploy folder of the Whiskey server, we can dynamically create these aliases:
<?xml version="1.0" encoding="UTF-8"?> <server> <mbean code="org.jboss.naming.NamingAlias" name="jboss.mq:service=NamingAlias,fromName=my-service-bean"> <attribute name="FromName">my-service-bean</attribute> <attribute name="ToName">external/my-service-bean</attribute> </mbean> </server>
If the filename ends in -service.xml, JBoss will automatically pick it up and create the alias. When you delete the file, JBoss will also remove the alias automatically.
If you want to read more about the ExternalContext MBean, head over to the JBoss Manual.