Hi,
In this example we will see how to bind custom objects in the JNDI tree of “JBoss AS7.1.1 Final” and What kind of JNDI name we should choose in order to make the Remote client to be able to access (lookup) those JNDI entries.
Point-1). JBoss AS7.1.1.Final provides a Jar file for the Client side in order to perform remote lookup’s of JMS and EJB components “jboss-as-7.1.1.Final/bin/client/jboss-client.jar”. This jar should be used with standalone clients only, not with deployments are that deployed to an AS7 instance.
Point-2). If we want to make the JNDI name accessible for a remote client then the JNDI name must have “exported” keywork in the following pattern: “java:jboss/exported/YOUR_JNDI_NAME”
Point-3). On the client side we will need to use a new Protocol “remote://” as following:
. String JBOSS_CONTEXT="org.jboss.naming.remote.client.InitialContextFactory";; Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, JBOSS_CONTEXT); props.put(Context.PROVIDER_URL, "remote://localhost:4447"); props.put(Context.SECURITY_PRINCIPAL, "testuser"); props.put(Context.SECURITY_CREDENTIALS, "testpassword"); context = new InitialContext(props); .
Point-4). We will use the “jboss-cli.sh” script to configure the custom JNDI bindings on JBoss AS7.1.1.Final
Point-5): [ IMPORTANT ] Security is the main focus now so before running “JBoss AS7.1.1.Final” we will need to create a new Application User by running “${JBOSS_HOME}/bin/add-user.sh” script as following so that Remote User will be able to access the JNDI :
[userone@localhost bin]$ ./add-user.sh What type of user do you wish to add? a) Management User (mgmt-users.properties) b) Application User (application-users.properties) (a): b Enter the details of the new user to add. Realm (ApplicationRealm) : ApplicationRealm Username : testuser Password : testpassword Re-enter Password : testpassword What roles do you want this user to belong to? (Please enter a comma separated list, or leave blank for none) : testrole About to add user 'testuser' for realm 'ApplicationRealm' Is this correct yes/no? yes Added user 'testuser' to file '/home/userone/jboss-as-7.1.1.Final/standalone/configuration/application-users.properties' Added user 'testuser' to file '/home/userone/jboss-as-7.1.1.Final/domain/configuration/application-users.properties' Added user 'testuser' with roles testrole to file '/home/userone/jboss-as-7.1.1.Final/standalone/configuration/application-roles.properties' Added user 'testuser' with roles testrole to file '/home/userone/jboss-as-7.1.1.Final/domain/configuration/application-roles.properties' . .
Source Code (Git Repo) Source Code for this Demo Can be downloaded from GIT Repository:
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/Binding_Custom_Object_IN_JBossAS711Final
Start JBoss AS7.1.1.Final like following:
$ ./standalone.sh -c standalone-full.xml
Binding Simple Objects in the JNDI Tree.
Step-1). Open a terminal (command prompt) then nevigate inside your “/home/userone/JBoss_All/jboss-as-7.1.1.Final/bin” directory and then run the following command in order to start and connect the JBoss CLI utility with the running JBoss instance:
$ ./jboss-cli.sh -c --controller=localhost:9999 OR [userone@localhost bin]$ ./jboss-cli.sh -c OR [userone@localhost bin]$ ./jboss-cli.sh -c --controller=localhost:9999 --gui .
Step-2). Now in order to bind a simple Integer Data type value in the JNDI tree just run the following command:
. /subsystem=naming/binding=java:jboss/exported/test/:add(binding-type=simple,value=100,type=int) .
If you dont want to use the command line utility to achieve the above then you can edit the naming subsystem of your “standalone-full.xml” file as following:
<subsystem xmlns="urn:jboss:domain:naming:1.1"> <bindings> <simple name="java:jboss/exported/test" value="100" type="int"/> </bindings> </subsystem>
Binding Complex/Custom Objects in the JNDI Tree.
Step-1). Suppose you have created a class like “TestBean.java” and you want to bind an instance of this class in the JNDI tree of your JBoss, then we will need to compile this class and we will need to make sure that this class is present inside the JBoss Classpath (using the JBoss Modules concept we can do that). Just write the following kind of class “TestBean.java”
package test.jndi.demo; public class TestBean implements java.io.Serializable { private String name; private String value; public TestBean(String name,String value) { this.name=name; this.value=value; System.out.println("[TestBean] TestBean initialized."); } public String getName() { return name; } public String getValue() { return value; } }
Step-2). Now in order to bind a Complex Data type value in the JNDI tree we will need to create a class which implements the “javax.naming.spi.ObjectFactory” interface and the getObjectInstance(…,…,..) method of this class should return the object which we want to bind in the JNDI tree of JBoss as following:
package test.jndi.demo; import java.util.Enumeration; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; public class MyCustomObjectFactory implements ObjectFactory { public MyCustomObjectFactory() { System.out.println("[MyCustomObjectFactory] MyCustomObjectFactory initialized."); } public Object getObjectInstance(Object obj, Name name, Context nameCtx,Hashtable environment) throws Exception { TestBean bean = new TestBean("City","Pune (India)"); return bean; } }
Step-3). Now compile the above two classes “TestBean.java” and “MyCustomObjectFactory.java” and then make a Jar file which should contain these classes. Suppose your JAR file name is “testJndiBinding.jar”
Step-4). Now we will need to make a JBoss module containing the above Jar “testJndiBinding.jar”. In order to create JBoss Module simply create a directory “test/jndi/demo/main” inside JBoss modules directory like:
mkdir “/home/userone/JBoss_All/jboss-as-7.1.1.Final/modules/test/jndi/demo/main”
Step-5). Now place your “testJndiBinding.jar” file inside “jboss-as-7.1.1.Final/modules/test/jndi/demo/main” directory and then create a file with name “module.xml” inside “jboss-as-7.1.1.Final/modules/test/jndi/demo/main” as following:
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="test.jndi.demo"> <resources> <resource-root path="testJndiBinding.jar"/> </resources> <dependencies> <module name="javax.api"/> </dependencies> </module>
Step-6). Restart your JBoss so that the Module can be utilized.
Step-7). Now in order to bind the “TestBean.class” object in the JNDI tree of JBoss AS7.1.1.Final we will need to run the following CLI command:
. /subsystem=naming/binding=java:jboss/exported/test2/:add(binding-type=object-factory,module=test.jndi.demo,class=test.jndi.demo.MyCustomObjectFactory) .
If you dont want to use the command line utility to achieve the above then you can edit the naming subsystem of your “standalone-full.xml” file as following:
<subsystem xmlns="urn:jboss:domain:naming:1.1"> <bindings> <simple name="java:jboss/exported/test" value="100" type="int"/> <object-factory name="java:jboss/exported/test2" module="test.jndi.demo" class="test.jndi.demo.MyCustomObjectFactory"/> </bindings> </subsystem>
Creating Aliases of the JNDI Names.
Step-7). If you want to create various alias Lookup names for your JNDI names then you can do the following….. (Suppose you want to create various alias names for your JNDI name “java:jboss/exported/test2”)
. /subsystem=naming/binding=java:jboss/exported/test3/:add(binding-type=lookup,lookup=java:jboss/exported/test2) /subsystem=naming/binding=java:jboss/exported/test4/:add(binding-type=lookup,lookup=java:jboss/exported/test2) /subsystem=naming/binding=java:jboss/exported/test5/:add(binding-type=lookup,lookup=java:jboss/exported/test2) /subsystem=naming/binding=java:jboss/exported/test6/:add(binding-type=lookup,lookup=java:jboss/exported/test2) /subsystem=naming/binding=java:jboss/exported/test7/:add(binding-type=lookup,lookup=java:jboss/exported/test2) .
If you dont want to use the command line utility to achieve the above then you can edit the naming subsystem of your “standalone-full.xml” file as following:
<subsystem xmlns="urn:jboss:domain:naming:1.1"> <bindings> <!-- Binding primitive Data types in the JNDI Tree --> <simple name="java:jboss/exported/test" value="1000" type="int"/> <!-- Binding Custom Objects in the JNDI Tree --> <object-factory name="java:jboss/exported/test2" module="test.jndi.demo" class="test.jndi.demo.MyCustomObjectFactory"/> <!-- Following is used for Aliasing JNDI names --> <lookup name="java:jboss/exported/test3" lookup="java:jboss/exported/test2"/> <lookup name="java:jboss/exported/test4" lookup="java:jboss/exported/test2"/> <lookup name="java:jboss/exported/test5" lookup="java:jboss/exported/test2"/> <lookup name="java:jboss/exported/test6" lookup="java:jboss/exported/test2"/> <lookup name="java:jboss/exported/test7" lookup="java:jboss/exported/test2"/> </bindings> </subsystem>
Testing the Remote JNDI Lookup
Now as we have already binded various objects in the in the JNDI tree of JBoss, so now we will write simple Standalone Java code in order to perform the Remote JNDI Lookup.
Write the following code somewhere in your file system “BindJndiDemo.java”
import java.io.*; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; public class BindJndiDemo { public final static String JNDI_FACTORY="org.jboss.naming.remote.client.InitialContextFactory"; public static void main(String[] args) throws Exception { if (args.length != 1) { System.out.println("Usage: java BindJndiDemo URL"); System.out.println("Example: java BindJndiDemo remote://localhost:4447"); return; } InitialContext ic = getInitialContext(args[0]); BindJndiDemo demo = new BindJndiDemo(); System.out.println("nnt *** Following shows Looking up a Primitive Datatype located in the JNDI ***"); Object primitiveLookup=ic.lookup("test"); System.out.println("tic.lookup("test") primitiveLookup = "+primitiveLookup); System.out.println("nnt *** Following shows Looking up a Custom Bean/Object located in the JNDI ***"); test.jndi.demo.TestBean testBean=(test.jndi.demo.TestBean)ic.lookup("test2"); System.out.println("t(test.jndi.demo.TestBean)ic.lookup("test2") testBean = "+testBean); System.out.println("tname="+testBean.getName()+"tvalue="+testBean.getValue()); System.out.println("nnt *** Following shows the JNDI Name Aliasing ***"); Object obj=ic.lookup("test3"); System.out.println("tAliasing Demo ic.lookup("test3") = "+obj); obj=ic.lookup("test4"); System.out.println("tAliasing Demo ic.lookup("test4") = "+obj); obj=ic.lookup("test5"); System.out.println("tAliasing Demo ic.lookup("test5") = "+obj); } private static InitialContext getInitialContext(String url) throws NamingException { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY); env.put(Context.PROVIDER_URL, url); //*************** UserName & Password for the Initial Context for JNDI lookup ************************* env.put(Context.SECURITY_PRINCIPAL, "testuser"); env.put(Context.SECURITY_CREDENTIALS, "testpassword"); InitialContext ic=new InitialContext(env); System.out.println("nnt Got InitialContext ic: "+ic); return ic; } }
Now before compiling and running the above program just make sure that the “jboss-as-7.1.1.Final/bin/client/jboss-client.jar” is added in your CLASSPATH as following:
[userone@localhost Binding_Custom_Object_IN_JBossAS711Final]$ echo $PATH /home/userone/MyJdks/jdk1.6.0_21/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/userone/.local/bin:/home/userone/bin [userone@localhost Binding_Custom_Object_IN_JBossAS711Final]$ echo $CLASSPATH /home/userone/JBoss_All/jboss-as-7.1.1.Final/bin/client/jboss-client.jar:.: [userone@localhost Binding_Custom_Object_IN_JBossAS711Final]$ java BindJndiDemo remote://localhost:4447 Apr 29, 2012 12:38:43 AM org.xnio.Xnio <clinit> INFO: XNIO Version 3.0.3.GA Apr 29, 2012 12:38:43 AM org.xnio.nio.NioXnio <clinit> INFO: XNIO NIO Implementation Version 3.0.3.GA Apr 29, 2012 12:38:43 AM org.jboss.remoting3.EndpointImpl <clinit> INFO: JBoss Remoting version 3.2.3.GA Got InitialContext ic: javax.naming.InitialContext@671ff436 *** Following shows Looking up a Primitive Datatype located in the JNDI *** ic.lookup("test") primitiveLookup = 100 *** Following shows Looking up a Custom Bean/Object located in the JNDI *** (test.jndi.demo.TestBean)ic.lookup("test2") testBean = test.jndi.demo.TestBean@12b754b2 name=City value=Pune (India) *** Following shows the JNDI Name Aliasing *** Aliasing Demo ic.lookup("test3") = test.jndi.demo.TestBean@63b0bdc8 Aliasing Demo ic.lookup("test4") = test.jndi.demo.TestBean@359eda2c Aliasing Demo ic.lookup("test5") = test.jndi.demo.TestBean@4c349471 . .
.
.
Thanks 🙂
Middleware Magic Team
May 16th, 2012 on 3:12 am
Thanks for posting this tutorial and some of the other AS7 walkthroughs. I’ve been trying to run BindJndiDemo.java and I’m having trouble getting the InitialContext:
It’s in method getInitialContext:
private static InitialContext getInitialContext(String url) throws NamingException {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
env.put(Context.PROVIDER_URL, url);
//*************** UserName & Password for the Initial Context for JNDI lookup *************************
env.put(Context.SECURITY_PRINCIPAL, “testuser”);
env.put(Context.SECURITY_CREDENTIALS, “testpassword”);
System.out.println(“About to try creating InitialContext…”);
InitialContext ic = new InitialContext(env);
System.out.println(“nnt Got InitialContext ic: ” + ic);
return ic;
}
Here’s the output:
About to try creating InitialContext…
log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
Exception in thread “main” javax.naming.NamingException: Failed to create remoting connection [Root exception is java.lang.RuntimeException: Operation failed with status WAITING]
at org.jboss.naming.remote.client.ClientUtil.namingException(ClientUtil.java:36)
at org.jboss.naming.remote.client.InitialContextFactory.getInitialContext(InitialContextFactory.java:121)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.(InitialContext.java:197)
at as7jndi.BindJndiDemo.getInitialContext(BindJndiDemo.java:50)
at as7jndi.BindJndiDemo.main(BindJndiDemo.java:20)
Caused by: java.lang.RuntimeException: Operation failed with status WAITING
at org.jboss.naming.remote.protocol.IoFutureHelper.get(IoFutureHelper.java:89)
at org.jboss.naming.remote.client.NamingStoreCache.getRemoteNamingStore(NamingStoreCache.java:56)
at org.jboss.naming.remote.client.InitialContextFactory.getOrCreateCachedNamingStore(InitialContextFactory.java:166)
at org.jboss.naming.remote.client.InitialContextFactory.getOrCreateNamingStore(InitialContextFactory.java:139)
at org.jboss.naming.remote.client.InitialContextFactory.getInitialContext(InitialContextFactory.java:104)
… 6 more
What’s the usual culprit when you get a NamingException/Operation failed with status WAITING? It seems like I’m never able to make a connection with my application server. Any idea?
Thanks.
May 19th, 2012 on 8:34 pm
Hi madchedar0,
The exception which you are getting will occur if your server is not reachable from the BOX where you are running your client.
Example Scenario When you will get this exception
Scenario-1). If you are running your Server to listen on “localhost” but from client side you might be trying to connect to the server using the IP-Address. Or Vice-Versa
Scenario-2). You might have changed the Default Remoting Port 4447 of your Server or the Port might be Blocked.
.
.
Keep Posting 🙂
Thanks
MiddlewareMagic Team
July 20th, 2012 on 3:35 pm
Hi,
I am getting something different issue.
Please resolve with your best of knowledge
Client.java — jboss-client.jar in classpath
———–
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, “org.jboss.naming.remote.client.InitialContextFactory”);
//env.put(“java.naming.factory.url.pkgs”, “org.jboss.naming:org.jnp.interfaces”);
env.put(Context.PROVIDER_URL, “remote://localhost:4457”);
env.put(Context.SECURITY_PRINCIPAL, “test”);
env.put(Context.SECURITY_CREDENTIALS, “test123”);
ObjectFactory o;
InitialContext ic = new InitialContext(env);
Object ref = ic.lookup(“cf”);
System.out.println(” ref ” + ref);
ConnectionFactory cf = (ConnectionFactory) ref;
System.out.println(“ConnectionFactory ” + cf);
QueueConnection createQueueConnection = ((QueueConnectionFactory) cf).createQueueConnection();
System.out.println(” createQueueConnection ” + createQueueConnection);
Queue queue = (Queue) ic.lookup(“queue/test”);
System.out.println(” queue ” + queue);
domain.xml
———-
When i run the client program i get this error in my server log
15:32:10,581 INFO [org.jboss.as.naming] (Remoting “master:server-one” task-2) JBAS011806: Channel end notification received, closing channel Channel ID 5b851be2 (inbound) of Remoting connection 018f57d2 to /127.0.0.1:2548
client exception
—————–
javax.naming.NameNotFoundException: cf — service jboss.naming.context.java.jboss.exported.cf
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:97)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:178)
at org.jboss.naming.remote.protocol.v1.Protocol$1.handleServerMessage(Protocol.java:127)
at org.jboss.naming.remote.protocol.v1.RemoteNamingServerV1$MessageReciever$1.run(RemoteNamingServerV1.java:73)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
July 20th, 2012 on 3:38 pm
domain.xml – naming entry
————————-
May 23rd, 2013 on 7:06 am
How can I use the above example to perform remote JNDI lookup by having a class that is part of .war deployed to JBoss AS 7.1.1.
Thanks,
nookala