| |
"Getting All Your Beans from One Bag"
Vol. 5, Issue 10, p. 56
Listing 1
micah/util/UID.java
import java.util.*;
import java.lang.reflect.*;
import javax.ejb.*;
import javax.naming.*;
/**
* A general purpose EJB factory. If you wanted to
* use the abstract factory design pattern here, you could
* have this class implement a generic interface to provide
* a higher degree of abstraction. That level of abstraction
* was not really needed for this example.
*/
public class EJBFactory {
private JNDIFinder _jndiFinder = null;
/** This constructor sets the JNDIFinder to use. The JNDIFinder class is
* a wrapper around JNDI functionality such as object lookups.
*/
public EJBFactory(JNDIFinder finder) {
setJNDIFinder(finder);
}
/** Method to get the home interface for an EJB with
* the specified JNDI name. The method it uses for lookup
* is through a helper JNDIFinder object.
*
* @param jndiName The name of the EJB object to get
* @return An Object that is the home interface
* @throws javax.naming.NameNotFoundException if the
* name does not exists in JNDI. Also throws
* javax.naming.NamingException if there is
* a problem in looking up the name.
*
*/
public Object getHomeInterface(String jndiName) throws
javax.naming.NameNotFoundException,
javax.naming.NamingException
{
Object obj = null;
obj = _jndiFinder.lookup(jndiName);
return obj;
}
/** Method to create an enterprise bean. Right now the
* Vector of params is getting reflected to determine their
* class type.
* This might be an expensive operation and so we might
* want to use something more efficient in the future to
* speed things up. The important thing to remember is
* that ORDER IS IMPORTANT for these parameters. Otherwise
* if you have a create method that takes multiple parame-
* ters of the same type, then you will get the method
* invocation wrong.
*
* @param jndiName The JNDI name of the EJB
* @param params A vector containing the arguments to
* the create method.
* @return An EJBObject that references the remote inter
* face for the specified EJB runtime instance. It is safe
* to down cast this reference to a specific remote inter
* face type.
* @throws InvocationTargetException or IllegalAccessExcep-
* tion if the method has trouble invoking the create
* method. See the java.lang.reflect.Method class for
* details on these exceptions. Also throws javax.naming.*
* exceptions if there is a lookup failure of the home
* interface of the specified EJB. A RemoteException is
* thrown per standard EJB rules. Throw a generic excep-
* tion so that any subclasses (e.g. wrappers) can throw
* their own exceptions.
*/
public EJBObject createBean( String jndiName, Object
[]params)
throws InvocationTargetException,
IllegalAccessException,
NoSuchMethodException,
java.rmi.RemoteException,
javax.naming.NamingException,
javax.naming.NameNotFoundException,
Exception {
EJBObject bean = null;
// Get the home interface and its associated Class
// object. We need the Class object for reflection...
//
Object homeInterface = getHomeInterface(jndiName);
Class beanClass = homeInterface.getClass();
// Need a class array for the method lookup...
//
Class[] signature = getSignature(params);
// Look up the method--throw exception if method not
// there.
// All create methods in the home interface are named
// "create" so search for the create method with the
// appropriate signature
//
Method createMethod = beanClass.getDeclaredMethod("cre-
ate", signature);
// This is the key. Here homeInterface is a reference
// to a REAL remote object -- i.e. the skeleton class
// on the server. The invocation is done on this spe-
// cific instance of the remote object created by the
// EJB container on the server.
//
bean = (EJBObject) createMethod.invoke(homeInterface,
params);
return bean;
}
/** Method to construct an array of Class objects repre-
* senting a method signature
*
* @param parameters A vector whose elements will be
* reflected or their specified Classes.
* @return A Class array
*
*/
private Class[] getSignature(Object [] parameters) {
Class sig[] = new Class[parameters.length];
for(int i =0; i<sig.length; i++) {
sig[i] = parameters[i].getClass();
}
return sig;
}
/** Method to set the internal JDNIFinder variable */
private void setJNDIFinder(JNDIFinder finder) {
jndiFinder = finder;
}
}
Listing 2
package com.myapp.util;
import java.util.*;
import javax.naming.*;
/*
* Class to wrap the EJBFactory to handle the number of exceptions
* that the factory throws. By wrapping the factory, it is easier to use
* its functionality in application code.
*/
public class FactoryWrapper extends EJBFactory {
/* Method to create an enterprise bean. */
public EJBObject createBean( String jndiName, Object []params)
throws AppException
{
EJBObject bean = null;
try {
bean = super.createBean(jndiName, params);
} catch (InvocationTargetException e) {
throw new AppException(e.getMessage());
} catch (NoSuchMethodException e) {
throw new AppException(e.getMessage());
} catch (IllegalAccessException e) {
throw new AppException(e.getMessage());
} catch (javax.naming.NameNotFoundException e) {
throw new AppException(e.getMessage());
} catch (javax.naming.NamingException e) {
throw new AppException(e.getMessage());
} catch (java.rmi.RemoteException e) {
throw new AppException(e.getMessage());
} catch (Exception e) {
throw new AppException(e.getMessage());
}
return bean;
}
}
Listing 3
/* Code example to create a bean using a create method
* that has a signature of create(String). This example
* uses the FactoryWrapper class from Code Example 2.
*
* The JNDIFinder class mentioned is a simple wrapper
* around a JNDI context. The code is not given here
* for the sake of brevity.
*/
...
try {
FactoryWrapper factory = new FactoryWrapper();
// The finder variable is created outside of this scope
//
factory.setJNDIFinder(finder);
String username = "Foo";
String jndiName = "com/foo/entity/myAppBean";
Object [] createArgs = { username };
myAppBean bean = (myAppBean) factory.createBean(jndiName,
createArgs);
bean.doWhatever();
} catch (ApplicationException e) {
// ... Error handling code ...
//
}
...
|
|