Codehaus XFire

Documentation

Quicklinks

Developers

Sponsors

Invokers allow you to customise how a particular method is executed. This is particular useful if your underlying service objects are not plain javabeans and instead need to be created or looked up via a custom factory.

XFire does provide a number of bundled invokers to handle simple cases. One of these simple cases is when it is desirable to have a singleton for the service object. In this case, you would like to provide a single object instance that should be used for all service invocations. The provided BeanInvoker covers this functionality, and would be used as follows:

Service service = ....; //look up the service from XFire, or create it
service.setInvoker(new BeanInvoker(new MyCustomBean(someParams)));

The following example illustrates how an invoker can be used to allow xfire to expose remote stateless session beans as a webservice. Given the method to invoke, this invoker will create a stateless session bean instance to invoke the method on. The same technique can be used to enable service calls to any object that requires custom creation/lookup.

The invoker implementation is as follows:

public class EJBInvoker implements Invoker
{
  private EJBHome home;
  private Method createMethod;
  private static final Object[] EMPTY_OBJECT = new Object[0];

  public EJBInvoker(EJBHome home)
  {
    this.home = home;
    try
    {
      if(!home.getEJBMetaData().isSession() || !home.getEJBMetaData().isStatelessSession())
      {
        throw new IllegalArgumentException("home must be for a stateless session bean");
      }
      createMethod = home.getClass().getMethod("create", new Class[0]);
    }
    catch(Exception ex)
    {
      throw new IllegalArgumentException("Unable to initialize invoker: " + ex);
    }
  }

  public Object invoke(Method m, Object[] params, MessageContext context) throws XFireFault
  {
    try
    {
      Object session = createMethod.invoke(home, EMPTY_OBJECT);
      return m.invoke(session, params);
    }
    catch(Exception ex)
    {
      throw new XFireFault("Error invoking ejb method " + m.getName(), ex, XFireFault.RECEIVER);
    }
  }
}

Invokers, once defined, need to be registered with the service binding. Once a handle onto a Service object has been obtained, the example invoker above can be registered on the binding like this:

Service ejbService = ....; //look up the service from XFire, or create it
ejbService.setInvoker(new EJBInvoker(ejbHome));

If you are using an EJB3 container you can use the following invoker, which is just a simplified version of the above:

 public class EJB3Invoker implements Invoker {
	private Object ejb;

	public EJB3Invoker(String jndiName) throws NamingException 	{
		ejb = new InitialContext().lookup(jndiName);
	}

	public Object invoke(Method m, Object[] params, MessageContext context) throws XFireFault 	{
		try 		{
			return m.invoke(ejb, params);
		} 		catch (Exception ex) 		{
			throw new XFireFault("Error invoking ejb method " + m.getName(),
					ex, XFireFault.RECEIVER);
		}
	}
}

Executors

In addition to providing your own Invokers, you can also supply Executors for your service. Executors are a way to control scheduling for your service. XFire expects an executor to conform to this class definition, but there is no defined interface to implement:

public class Executor
{
  public void execute(Runnable r) { .. }
}

To supply your own executor for a service just do:

Service service = ....; //look up the service from XFire, or create it
service.setExecutor(new MyExecutor());