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

Binding and lookup - references - tomcat service provider


Sometimes it's not appropriate (or possible) to serialize an object. If the object provides a service on a network, for example, it doesn't make sense to store the state of the object itself. We're interested in the information necessary to find and communicate with the object.

An example is a connection to an external resource (one outside the scope of the Java Virtual Machine) such as a database or file. It clearly doesn't make sense to try to store the database or the file itself in the JNDI service. Instead, we want to store the information necessary to reconstruct the connection.

So, the programmer should store a reference to that object instead. JNDI's javax.naming.Reference class records address information about objects not directly bound to the naming service.
The reference to an object contains the following information:
  • The class name of the referenced object
  • A vector of javax.naming.RefAddr objects that represents the addresses
  • The name and location of the object factory to use during reconstruction


The javax.naming.RefAddr abstract class contains information indicating the ways in which you can contact the object (e.g., via a location in memory, a lookup on another machine, etc.) or recreate it with the same state. The class defines an association between content and type. The content (an object) stores information required to rebuild the object and the type (a string) identifies the purpose of the content.

RefAddr also overrides the java.lang.Object.equals() and java.lang.Object.hashcode() methods to ensure that two references are equal if the content and type are equal. RefAddr has two concrete subclasses:
javax.naming.StringRefAddr, which stores strings and
javax.naming.BinaryRefAddr, which stores an array of bytes.

Then, we must write a class that implements the JNDI service provider javax.naming.spi.ObjectFactory inteface.
Every time your web application calls lookup() on a context entry that is bound to this factory (assuming that the factory is configured with singleton="false"), the getObjectInstance() method is called, with the following arguments:
  • Object obj - The (possibly null) object containing location or reference information that can be used in creating an object. For Tomcat, this will always be an object of type javax.naming.Reference, which contains the class name of this factory class, as well as the configuration properties (from the for the web application) to use in creating objects to be returned.
  • Name name - The name to which this factory is bound relative to nameCtx, or null if no name is specified.
  • Context nameCtx - The context relative to which the name parameter is specified, or null if name is relative to the default initial context.
  • Hashtable environment - The (possibly null) environment that is used in creating this object. This is generally ignored in Tomcat object factories.

Let's try to do it programmatically by creating a binding at root context in our servlet (Note that tomcat's initContext doesn't let you modify existing subcontexts dynamically).

We write a bean class "MyBean".

import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;

public class MyBean implements Referenceable{

 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 + "]";
 }

 public Reference getReference() throws NamingException{
   String classname = MyBean.class.getName();
   StringRefAddr barref = new StringRefAddr("bar", Integer.toString(bar));
   StringRefAddr fooref = new StringRefAddr("foo", foo);
  
   String classfactoryname=MyBeanFactory.class.getName();
   Reference ref = new Reference(classname,classfactoryname,null);
   ref.add(barref);
   ref.add(fooref);
   return ref;
  }
}

We write the Factory class that helps to recreate "MyBean" objects from the Reference stored in context.

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;

import sample.bean.MyBean;

public class MyBeanFactory implements ObjectFactory {

  public Object getObjectInstance(Object obj,
   Name name, Context nameCtx, Hashtable environment)
   throws NamingException {
   System.out.println("MyBeanFactory.getObjectInstance()");
   // Acquire an instance of our specified bean class
   MyBean bean = new MyBean();

   // Customize the bean properties from our attributes
   Reference ref = (Reference) obj;
   Enumeration addrs = ref.getAll();
   while (addrs.hasMoreElements()) {
    RefAddr addr = (RefAddr) addrs.nextElement();
    String attrName = addr.getType();
    String value = (String) addr.getContent();
    if (attrName.equals("foo")) {
     bean.setFoo(value);
    } else if (attrName.equals("bar")) {
     try {
      bean.setBar(Integer.parseInt(value)+100); //changed 
     } catch (NumberFormatException e) {
      throw new NamingException("Invalid 'bar' value " + value);
     }
    }
   }

 // Return the customized instance
 return (bean);
  }
}

In the servlet,

protected void doGet(HttpServletRequest request,
  HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet");
try {
  Hashtable<String, String> env = new Hashtable<String, String>(1);
    env.put(Context.OBJECT_FACTORIES, "sample.bean.factory.MyBeanFactory");
    Context initCxt =  new InitialContext(env);
    initCxt.rebind("mybean", new MyBean());
    MyBean obj = (MyBean) initCxt.lookup("mybean");
    System.out.println(obj);
 } catch (NamingException e) {
  e.printStackTrace();
 }
}

Output:
doGet
MyBeanFactory.getObjectInstance()
MyBean [foo=Default Foo, bar=100]

No comments:

Post a Comment