Saturday, October 06, 2007

Why do i get NameNotFoundException while doing a JNDI lookup?

Many a times when you are doing a lookup in the JNDI tree, you see javax.naming.NameNotFoundException. A simple code that does the lookup will look something like:


Context ctx = new InitialContext();
Object obj = ctx.lookup("somepath/somename");


This code just looks up the JNDI tree to get an object bound by the name "somepath/somename". Looks simple. However, chances are that you might even see this exception:


javax.naming.NameNotFoundException: somepath not bound
at org.jnp.server.NamingServer.getBinding(NamingServer.java:529)
at org.jnp.server.NamingServer.getBinding(NamingServer.java:537)
at org.jnp.server.NamingServer.getObject(NamingServer.java:543)
at org.jnp.server.NamingServer.lookup(NamingServer.java:267)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
at sun.rmi.transport.Transport$1.run(Transport.java:153)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)
at java.lang.Thread.run(Thread.java:595)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)
at org.jnp.server.NamingServer_Stub.lookup(Unknown Source)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:625)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:587)
at javax.naming.InitialContext.lookup(InitialContext.java:351)


Look closely at the stacktrace. It shows that while looking up the JNDI tree it could not find the jndi name "somepath" (this name may vary). The reason is simple, the JNDI tree does not have any object bound by this name.

To quote the javadocs of this exception "This exception is thrown when a component of the name cannot be resolved because it is not bound."

So how do i know, what's the name to which my object is bound? Each application server, usually provides a JNDI view which can be used to see the contents of the JNDI tree. If you know what object you are looking for (ex: the name of the bean), then you can traverse this JNDI tree to see what name it is bound to. The JNDI view is specific to every application server.

To give an example, JBoss provides its JDNI tree view, through the JMX console. Here are the steps, one has to follow to check the JNDI tree contents on JBoss:

- Go to http://< server>:< port>/jmx-console (Ex: http://localhost:8080/jmx-console)
- Search for service=JNDIView on the jmx-console page
- Click on that link
- On the page that comes up click on the Invoke button beside the list() method
- The page that comes up will show the contents of the JNDI tree.

Here's an sample of how the output looks like(just a small part of the entire output):


java: Namespace

+- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory)
+- DefaultDS (class: org.jboss.resource.adapter.jdbc.WrapperDataSource)
+- SecurityProxyFactory (class: org.jboss.security.SubjectSecurityProxyFactory)
+- DefaultJMSProvider (class: org.jboss.jms.jndi.JNDIProviderAdapter)
+- comp (class: javax.naming.Context)
+- JmsXA (class: org.jboss.resource.adapter.jms.JmsConnectionFactoryImpl)
+- ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory)
+- jaas (class: javax.naming.Context)
| +- dukesbank (class: org.jboss.security.plugins.SecurityDomainContext)
| +- HsqlDbRealm (class: org.jboss.security.plugins.SecurityDomainContext)
| +- jbossmq (class: org.jboss.security.plugins.SecurityDomainContext)
| +- JmsXARealm (class: org.jboss.security.plugins.SecurityDomainContext)


Global JNDI Namespace

+- ebankTxController (proxy: $Proxy79 implements interface com.sun.ebank.ejb.tx.TxControllerHome,interface javax.ejb.Handle)
+- ebankAccountController (proxy: $Proxy75 implements interface com.sun.ebank.ejb.account.AccountControllerHome,interface javax.ejb.Handle)
+- TopicConnectionFactory (class: org.jboss.naming.LinkRefPair)
+- jmx (class: org.jnp.interfaces.NamingContext)
| +- invoker (class: org.jnp.interfaces.NamingContext)
| | +- RMIAdaptor (proxy: $Proxy48 implements interface org.jboss.jmx.adaptor.rmi.RMIAdaptor,interface org.jboss.jmx.adaptor.rmi.RMIAdaptorExt)
| +- rmi (class: org.jnp.interfaces.NamingContext)
| | +- RMIAdaptor[link -> jmx/invoker/RMIAdaptor] (class: javax.naming.LinkRef)
+- HTTPXAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory)
+- ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory)
+- ebankCustomer (proxy: $Proxy67 implements interface com.sun.ebank.ejb.customer.LocalCustomerHome)
+- UserTransactionSessionFactory (proxy: $Proxy14 implements interface org.jboss.tm.usertx.interfaces.UserTransactionSessionFactory)
+- ebankCustomerController (proxy: $Proxy77 implements interface com.sun.ebank.ejb.customer.CustomerControllerHome,interface javax.ejb.Handle)
+- HTTPConnectionFactory (class: org.jboss.mq.SpyConnectionFactory)
+- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory)
+- TransactionSynchronizationRegistry (class: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple)
+- ebankAccount (proxy: $Proxy68 implements interface com.sun.ebank.ejb.account.LocalAccountHome)
+- UserTransaction (class: org.jboss.tm.usertx.client.ClientUserTransaction)
+- UILXAConnectionFactory[link -> XAConnectionFactory] (class: javax.naming.LinkRef)
+- UIL2XAConnectionFactory[link -> XAConnectionFactory] (class: javax.naming.LinkRef)
+- queue (class: org.jnp.interfaces.NamingContext)
| +- A (class: org.jboss.mq.SpyQueue)
| +- testQueue (class: org.jboss.mq.SpyQueue)
| +- ex (class: org.jboss.mq.SpyQueue)
| +- DLQ (class: org.jboss.mq.SpyQueue)
| +- D (class: org.jboss.mq.SpyQueue)
| +- C (class: org.jboss.mq.SpyQueue)
| +- B (class: org.jboss.mq.SpyQueue)


Let's see what this tells us. Let's consider the Global JNDI Namespace first. It contains (among other things) the following:

+- ebankTxController (proxy: $Proxy79 implements interface com.sun.ebank.ejb.tx.TxControllerHome,interface javax.ejb.Handle)


This tells me that an object which implements com.sun.ebank.ejb.tx.TxControllerHome and javax.ejb.Handle interfaces is bound to the JNDI tree by the jndi-name "ebankTxController". So if at all i have to lookup this object, my lookup code would be something like:


Context ctx = new InitialContext();
ctx.lookup("ebankTxController");


Similarly in the same Global JDNI Namespace, we see :


+- queue (class: org.jnp.interfaces.NamingContext)
| +- A (class: org.jboss.mq.SpyQueue)



Make note of the nesting of the names here. This tells me that an object of type org.jboss.mq.SpyQueue is bound by the name "A under the path queue". So your lookup for this object should look like:


Context ctx = new InitialContext();
ctx.lookup("queue/A");


Now let's move on to the java: namespace in the JNDI tree view above. The difference between a Global JNDI namespace and the java: namespace is that, the object bound in the java: namespace can be looked-up ONLY by clients within the SAME JVM. Whereas, in case of Global JNDI namespace, the objects bound in this namespace can be looked-up by clients, even if they are not in the same JVM as the server. One would ask, how does this matter? Consider a standalone java program(client) which tries to lookup some object on the server (running in its own JVM). Whenever a standalone client is started (using the java command), a new JVM is instantiated. As a result, the server (which is started in its own JVM) and the client are running on different JVMs. Effectively, the client will NOT be able to lookup objects bound in the java: namespace of the server. However, the client can lookup the objects present in the Global JNDI namespace of the server.

So, why are we discussing these details, in a topic which was meant to explain the NameNotFoundException? Let's consider the java: namespace output above. There's a


+- DefaultDS (class: org.jboss.resource.adapter.jdbc.WrapperDataSource)


This tells me that there's an object bound to the name DefaultDS in the java: namespace. So my lookup code would be:


Context ctx = new InitialContext();
ctx.lookup("java:/DefaultDS");


As explained above, this code is going to return you the object, if this piece of code runs in the same JVM as the server. However, if this piece of code is run from a client in different JVM (maybe a standalone client), then it's going to run into NameNotFoundException. The reason i explained the java: and the Global JNDI namespace is that, sometimes people are surprised that even though the JNDI view shows that the object is bound in the java: namespace(with the same name as the one they pass to the lookup method), they still run into NameNotFoundException. The probable reason might be, the client is in a different JVM.

Wednesday, April 18, 2007

Webservice client using dynamic proxy

In one of my previous posts, i explained how to create a WebService and access it from a simple client. If you look at the client code which accesses the webservice, you will find that the client is using the stubs that were created at deploy time. Such clients which use "static stubs" for accessing webservices are known as "Static Stub Clients". In such approach, the clients will have to have the stubs in their classpath.

Another approach of accessing the webservices is through Dynamic Proxies where the proxies are generated at runtime. I will be showing a simple client which uses dynamic proxies to access an webservice. I wont be explaining the steps to deploy the webservice (which i have already done in my other post). This example assumes that the webservice is already deployed on the server.

The client code will be accessing the HelloWorld service and invoking the sayHelloTo method on that service (Refer my other post to see how the service has been deployed onto the server)

Here's the code for the client:


package org.myapp.service.client;

import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.ServiceFactory;

import org.myapp.service.HelloWorldService;

/**
* Simple webservice client which uses dynamic proxy
*
* @author Jaikiran Pai
*/
public class DynamicProxyClient {

public static void main(String args[]) {

try {

// ServiceFactory instance
ServiceFactory serviceFactory = ServiceFactory.newInstance();
System.out.println("Got the service factory");
String wsdlURLString = "http://localhost:8080/axis/services/HelloWorld?wsdl";
URL wsdlURL = new URL(wsdlURLString);
String serviceName = "HelloWorldServiceService";
String nameSpaceURI = "http://jaikiran.com";
String portName = "HelloWorld";
// get hold of the service by passing the URL of the wsdl and the
// service name
Service service = serviceFactory.createService(wsdlURL, new QName(
nameSpaceURI, serviceName));
System.out.println("Got the service: " + service);
// create the service proxy
HelloWorldService serviceProxy = (HelloWorldService) service
.getPort(new QName(nameSpaceURI, portName),
HelloWorldService.class);
System.out.println("Got the service proxy: " + serviceProxy);
System.out.println("Invoking method on service proxy........");
System.out.println(serviceProxy.sayHelloTo("Dynamic user"));

} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}



1) Our first step would be to create a ServiceFactory instance, using which we can get access to a deployed service.


ServiceFactory serviceFactory = ServiceFactory.newInstance();


2) Once the ServiceFactory has been created, we will be getting hold of the service which is deployed on the server. To do this, we require
a) The url of the wsdl of the deployed service. In this example it will be http://localhost:8080/axis/services/HelloWorld?wsdl

b) The namespace uri. In this example it will be http://jaikiran.com (You can get this uri from the wsdl file)

c) The name of the service which you want to access. In this example it will be HelloWorldServiceService



String wsdlURLString = "http://localhost:8080/axis/services/HelloWorld?wsdl";
URL wsdlURL = new URL(wsdlURLString);
String serviceName = "HelloWorldServiceService";
String nameSpaceURI = "http://jaikiran.com";

// get hold of the service by passing the URL of the wsdl and the
// service name
Service service = serviceFactory.createService(wsdlURL, new QName(
nameSpaceURI, serviceName));



3) At this point you have got access to the service. But in order to invoke an method on the service, you will have to create a proxy (dynamic proxy) from this service. The Service class, has an API getPort, which creates the proxy. In order to create the proxy, we will have to pass the portName of the service (again, this can be obtained in the wsdl file), the namespace uri and the class type of the service. In this example the service interface is org.myapp.service.HelloWorldService, so we will be passing this as the class as follows:


String portName = "HelloWorld";
// create the service proxy
HelloWorldService serviceProxy = (HelloWorldService) service
.getPort(new QName(nameSpaceURI, portName),
org.myapp.service.HelloWorldService.class);


4) At this point we have got the service proxy which is of type org.myapp.service.HelloWorldService. We can now invoke our sayHelloTo method on this proxy:


System.out.println(serviceProxy.sayHelloTo("Dynamic user"));


Simple, isnt it? You have successfully invoked the webservice through a standalone client using dynamic proxy.

Thursday, January 04, 2007

How to read a properties file in a web application

The code to do this is pretty simple. But going by the number of people who keep asking this question, i thought i would post the code over here. Let's consider that you have a war file named SampleApp.war which has a properties file named myApp.properties at it's root :



SampleApp.war
|
|-------- myApp.properties
|
|-------- WEB-INF
|
|---- classes
|
|----- org
|------ myApp
|------- MyPropertiesReader.class





Let's assume that you want to read the property named "abc" present in the properties file:

----------------
myApp.properties:
----------------

abc=some value
xyz=some other value


Let's consider that the class org.myApp.MyPropertiesReader present in your application wants to read the property. Here's the code for the same:



package org.myapp;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
* Simple class meant to read a properties file
*
* @author Jaikiran Pai
*
*/
public class MyPropertiesReader {

/**
* Default Constructor
*
*/
public MyPropertiesReader() {

}

/**
* Some Method
*
* @throws IOException
*
*/
public void doSomeOperation() throws IOException {
// Get the inputStream
InputStream inputStream = this.getClass().getClassLoader()
.getResourceAsStream("myApp.properties");

Properties properties = new Properties();

System.out.println("InputStream is: " + inputStream);

// load the inputStream using the Properties
properties.load(inputStream);
// get the value of the property
String propValue = properties.getProperty("abc");

System.out.println("Property value is: " + propValue);
}

}




Pretty straight-forward. Now suppose the properties file is not at the root of the application, but inside a folder (let's name it config) in the web application, something like:




SampleApp.war
|
|-------- config
| |------- myApp.properties
|
|
|-------- WEB-INF
|
|---- classes
|
|----- org
|------ myApp
|------- MyPropertiesReader.class




There will just be one line change in the above code:




public void doSomeOperation() throws IOException {
//Get the inputStream-->This time we have specified the folder name too.
InputStream inputStream = this.getClass().getClassLoader()
.getResourceAsStream("config/myApp.properties");

Properties properties = new Properties();

System.out.println("InputStream is: " + inputStream);

//load the inputStream using the Properties
properties.load(inputStream);
//get the value of the property
String propValue = properties.getProperty("abc");

System.out.println("Property value is: " + propValue);
}



That's all that is required to get it working.