blogger templates blogger widgets
This is part of a list of blog posts.
To browse the contents go to

Bind and lookup serialized data - tomcat service provider

The most obvious approach to storing an object in a directory is to store the serialized representation of an object. The only requirement is that the object's class implement the Serializable interface.

When an object is serialized, its state becomes transformed into a stream of bytes. The service provider takes the stream of bytes and stores it in the directory. When a client looks up the object, the service provider reconstructs it from the stored data.

Let's try creating a binding at root context in our servlet.

protected void doGet(HttpServletRequest request,
 HttpServletResponse response) throws ServletException, IOException {
try {
 Context initCxt = new InitialContext();
 initCxt.bind("foo", new String("bar")); //String is a class that implements Serializable
 System.out.println(initCxt.lookup("foo"));

} catch (NamingException e) {
 e.printStackTrace();
}
}

Output:
bar

Let's try creating a sub-context also.

protected void doGet(HttpServletRequest request,
 HttpServletResponse response) throws ServletException, IOException {
try {
 Context initCxt = new InitialContext();
 initCxt.createSubcontext("private:");
 initCxt.createSubcontext("private:objects");
 initCxt.rebind("private:objects/foo", "bar");
 System.out.println(initCxt.lookup("private:objects/foo"));

} catch (NamingException e) {
 e.printStackTrace();
}
}

Output:
bar

Hurray!!!!!

Let's try doing a custom object


public class MyBean {
 private String foo = "Default Foo";
 private int bar = 0;
 public String getFoo() {
  return (this.foo);
 }
 public void setFoo(String foo) {
  this.foo = foo;
 }
 public int getBar() {
  return (this.bar);
 }
 public void setBar(int bar) {
  this.bar = bar;
 }
 @Override
 public String toString() {
  return "MyBean [foo=" + foo + ", bar=" + bar + "]";
 }
}

protected void doGet(HttpServletRequest request,
  HttpServletResponse response) throws ServletException, IOException {
 System.out.println("doGet");
 try {
    Context initCxt =  new InitialContext();
    MyBean myb = new MyBean();
    myb.setBar(123);
    initCxt.bind("mybean", myb);
    MyBean obj = (MyBean) initCxt.lookup("mybean");
    System.out.println(obj);

 } catch (NamingException e) {
  e.printStackTrace();
 }
} 

Output:
MyBean [foo=Default Foo, bar=123]

Hurray!!! It wasn't even serializable but still tomcat's intialContext implementation let us store it.

Let's try doing the same under a sub-tree (sub-context).

initContext = new InitialContext(env);
Context ctx = (Context) initContext.lookup("java:comp/env");
ctx.rebind("java:comp/env/foo", "bar");
System.out.println(initContext.lookup("java:comp/env/foo"));

This will never work. You will be welcomed by this exception
javax.naming.OperationNotSupportedException: Context is read only

Why does this happen?

Why doesn't tomcat's InitalContext implementation let us modify it's context?

The J2EE spec answers why we get this exception.

The container must ensure that the application component instances have only read access to their naming context. The container must throw the javax.naming.OperationNotSupportedException from all the methods of the javax.naming.Context interface that modify the environment naming context and its subcontexts.

If you think about it, it will make sense. JNDI was brought into containers to make objects available before the application starts. If we are creating and binding it, right from our programs then why JNDI?, we could have simply instantiated "foo" like any other object.
Also because the Tomcat JNDI registry is primarily used for configuration information, the ability to add/update entries could potentially cause trouble.

So, the tomcat's jndi implementation lets users to create a new bindings only from the root context and not from existing sub-contexts(or trees) like java:comp/env which are protected.

Only place I could think of where JNDI context creation/modification could be put to use is Junit Tests.

Here is a java program,

public class MainClass {
 public static void main(String[] args) {
  Context initContext = null;
  try {
   Hashtable env = new Hashtable();
   env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
   env.put(Context.URL_PKG_PREFIXES, "org.apache.naming");
   initContext = new InitialContext(env);

   initContext.createSubcontext("java:");
   initContext.createSubcontext("java:comp");
   initContext.createSubcontext("java:comp/env");
   initContext.rebind("java:comp/env/foo", "bar");
   System.out.println(initContext.lookup("java:comp/env/foo")); //output: bar 
  }catch(NamingException e){
   e.printStackTrace(System.out);
  }
 }
}

Note that I had to include, catalina.jar and tomcat-juli.jar from tomcat(installation path)/bin.

No comments:

Post a Comment