Hi,
I recently worked on getting a JDBC connection pool/DataSource working on
Tomcat 4.0b7. I was interested in trying out the OracleConnectionCacheImpl
which Oracle provides in their JDBC drivers.
I eventually found out that the only way to make an instance of this class
available from JNDI was to create my own Factory class for it. It seemed
to me like there should be a simpler way to do something like this so I
created a factory class (BeanFactory) which can instantiate any class which
conforms to the JavaBeans spec (i.e. most classes...).
What would I have to do to contribute this class so it ships as a standard
part of Tomcat? The class has worked out well for my purposes but I am not
sure if the ClassLoader portion of the code is doing the right thing, I copied
it from one of the other factory classes in org.apache.naming.factory.
Using this class, I am able to make the Oracle DataSource implementation
available to all my servlets using the following xml fragment in server.xml
<DefaultContext>
<Resource name="jdbc/myDataSource" auth="SERVLET"
type="oracle.jdbc.pool.OracleConnectionCacheImpl"/>
<ResourceParams name="jdbc/myDataSource">
<parameter>
<name>factory</name>
<value>org.apache.naming.factory.BeanFactory</value>
</parameter>
<parameter><name>driverType</name><value>thin</value></parameter>
<parameter><name>serverName</name><value>hue</value></parameter>
<parameter><name>networkProtocol</name><value>tcp</value></parameter>
<parameter><name>databaseName</name><value>XXXX</value></parameter>
<parameter><name>portNumber</name><value>NNNN</value></parameter>
<parameter><name>user</name><value>XXXX</value></parameter>
<parameter><name>password</name><value>XXXX</value></parameter>
<parameter><name>maxLimit</name><value>5</value></parameter>
</ResourceParams>
</DefaultContext>
Similarly, you could make ANY JavaBean available from jndi using this factory.
I have attached my implementation to this message if anybody is interested in
getting it incorporated into Tomcat.
Thanks,
- Aner
package org.apache.naming.factory;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.Name;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.RefAddr;
import javax.naming.spi.ObjectFactory;
import org.apache.naming.ResourceRef;
import java.beans.Introspector;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
/**
* Object factory for any Object conforming to the JavaBean spec.
*/
public class BeanFactory
implements ObjectFactory {
// ----------------------------------------------------------- Constructors
// -------------------------------------------------------------- Constants
// ----------------------------------------------------- Instance Variables
// --------------------------------------------------------- Public Methods
// -------------------------------------------------- ObjectFactory Methods
/**
* Create a new Bean instance.
*
* @param obj The reference object describing the Bean
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment)
throws NamingException {
System.out.println("BeanFactory.getObjectInstance()");
if (obj instanceof ResourceRef) {
try {
Reference ref = (Reference) obj;
String beanClassName = ref.getClassName();
Class beanClass = null;
ClassLoader tcl =
Thread.currentThread().getContextClassLoader();
if (tcl != null) {
try {
beanClass =
tcl.loadClass(beanClassName);
} catch(ClassNotFoundException e) {
}
} else {
try {
beanClass =
Class.forName(beanClassName);
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
if(beanClass == null)
throw new NamingException("Class not found: "
+ beanClassName);
BeanInfo bi = Introspector.getBeanInfo(beanClass);
PropertyDescriptor[] pda = bi.getPropertyDescriptors();
Object bean = beanClass.newInstance();
Enumeration e = ref.getAll();
while(e.hasMoreElements()) {
RefAddr ra = (RefAddr) e.nextElement();
String propName = ra.getType();
if(propName.equals(Constants.FACTORY) ||
propName.equals("scope") ||
propName.equals("auth"))
continue;
String value = (String)ra.getContent();
Object[] valueArray = new Object[1];
int i = 0;
for(i=0;i<pda.length;i++) {
if(pda[i].getName().equals(propName)) {
Class propType =
pda[i].getPropertyType();
if(propType.equals(String.class))
valueArray[0] = value;
else
if(propType.equals(Character.class) || propType.equals(char.class))
valueArray[0] = new
Character(value.charAt(0));
else
if(propType.equals(Byte.class) || propType.equals(byte.class))
valueArray[0] = new
Byte(value);
else
if(propType.equals(Short.class) || propType.equals(short.class))
valueArray[0] = new
Short(value);
else
if(propType.equals(Integer.class) || propType.equals(int.class))
valueArray[0] = new
Integer(value);
else
if(propType.equals(Long.class) || propType.equals(long.class))
valueArray[0] = new
Long(value);
else
if(propType.equals(Float.class) || propType.equals(float.class))
valueArray[0] = new
Float(value);
else
if(propType.equals(Double.class) || propType.equals(double.class))
valueArray[0] = new
Double(value);
else
throw new
NamingException(
"String
conversion for property type '"+
propType.getName() + "' not available");
Method setProp =
pda[i].getWriteMethod();
if(setProp != null)
setProp.invoke(bean,
valueArray);
else
throw new
NamingException(
"Write not
allowed for property: "+propName);
break;
}
}
if(i==pda.length)
throw new NamingException("No set
method found for property: "+propName);
}
return bean;
} catch (java.beans.IntrospectionException ie) {
throw new NamingException(ie.getMessage());
} catch (java.lang.IllegalAccessException iae) {
throw new NamingException(iae.getMessage());
} catch (java.lang.InstantiationException ie2) {
throw new NamingException(ie2.getMessage());
} catch (java.lang.reflect.InvocationTargetException ite) {
throw new NamingException(ite.getMessage());
}
} else {
return null;
}
}
}