Pages

Showing posts with label service locator. Show all posts
Showing posts with label service locator. Show all posts

Friday, August 22, 2014

Developing a dynamic JEE service client with CDI (part 2)

In the previous blog entry I described how to develop an JEE service client that performs lazy lookups and is injectable to satisfy a service dependency. In this article I want to describe how to extend this service client to allow client-side service call interception.

Before I dive into the details of the interception, I want to outline the reasons why client-side call interception might be useful.

Background

In our current project we aspired a RESTful component-based architecture. For each of the components it should be possible to integrate them in a service oriented architecture via WebService, deploy them in a JEE environment accessing it as JNDI-locateable services or access them via a RESTful lightweight interface. Each component should be deployable standalone and should be operational as long as their lower-level component dependencies are satisfied. To be RESTful, our architecture followed the seven principles of REST, described in the famous thesis of Roy Fielding.

With JEE we could easily add caching behavior on the service side of a service consumer-provider relationship by adding an interceptor that serves a call with data from a cache and therefore reducing processing resource usage on the service side.

On the consumer side there is no such mechanism as to transparently intercept a service call before it is actually sent to the service. Such a client-side call interception could be of use for a range of use-cases
  • caching, to reduce network resource usage
  • error handling and fault tolerance
  • logging
  • security
 The following description uses the service client I described in a previous blog post.

Adding Interceptor support

In order to add call interceptors to the service client, we have to extend the invocation handler that delegates the service method invocation to the actual service by adding a stack of interceptors that are invoked consecutively.

When a JEE interceptors is invoked an InvocationContext is passed to the interceptor. The interceptor may decide to fully intercept the request and not proceeding the invocation further. This is behavior is needed for caching or security concern. Alternatively, interceptors may execute some additional operations before or after proceeding with the invocation which is useful for logging or error handling.

The InvocationContext is an interface introduced by JEE6. I used my own implementation of this interface where the getter methods defined by the interface simply return the values that are passed to the InvocationHandler of the dynamic proxy (see the ProxyServiceInvocationHandler of the previous blog post), the getTimer() method returns null, as I don't really need it. The main functionality of the InvocationContext however resides in the proceed() method. I used a stack (Deque) to maintain a list of registered interceptors of which each is checked whether it may intercept the method invocation or not.

The check is done in the method isInterceptedBy and does check the class of the interceptor instance as well as the method whether they both are annotated with the same the InterceptorBinding annotation. I deviated a bit from the JEE6 standard as I allowed an interceptor without an explicit interceptor binding to intercept any method invocation, but that is up to you.
The main method of my InvocationContext implementation are shown in the next listing

class ProxyInvocationContext implements InvocationContext {

  ...

  @Override
  public Object proceed() 
    throws IllegalAccessException, 
           IllegalArgumentException, 
           InvocationTargetException {
    if (!interceptorInvocationStack.isEmpty()) {
      final Object interceptor = interceptorInvocationStack.removeFirst();
      if (isInterceptedBy(interceptor)) {
        final Method aroundInvoke = interceptorMethods.get(interceptor);
        return aroundInvoke.invoke(interceptor, this);
      }
    }
    return this.method.invoke(target, this.parameters);
  }
  
  private boolean isInterceptedBy(final Object interceptor) {
    boolean hasNoBinding = true;
    for (final Annotation an : interceptor.getClass().getAnnotations()) {
      if (an.annotationType().getAnnotation(InterceptorBinding.class) != null) {
        hasNoBinding = false;
        if (getMethod().getAnnotation(an.annotationType()) != null) {
          return true;
        }
      }
    }
    return hasNoBinding;
  }
}

Instantiating Interceptors in CDI Context using DeltaSpike

Now we want to create interceptors and put them into the interceptor stack. The JEE 6 standard already defines interceptors so we could simply re-use this specification. JEE6 compliant interceptors may be used in a CDI lifecycle, that means lifecycle methods annotated with @PostConstruct or @PreDestroy are executed as well as injection of dependencies.
With the implementation of the InvocationContext described above, we need a collection of interceptor instances. In our project I used a configuration file (similar to the beans.xml where you have to define which interceptors should be loaded) where I defined the interceptor classes that should be loaded.

Creating an instance of a class by the fully qualified name of the class is trivial using reflection (i.e. Class.forName("...").newInstance()). But when you have a CDI container you want to let the container do the creation and further process the lifecycle of the the instance including dependency injection.

JEE6 itself does not provide the means for that but it defines an SPI. The Apache DeltaSpike project offers an implementation for that SPI (btw. it is developed by the same guys behind CDI in JEE6 itself). DeltaSpike allows to interact directly with the CDI container.

The following code snippet assumes, that you have already loaded the interceptor class and verified it is annotated with the @Interceptor annotation. It first checks, if a CDI environment is active, if not, the interceptor is instantiated the traditional way. If it is active, a BeanManager reference is obtained, an injection target is created using the interceptor class. This is needed to create the instance and inject dependencies to the instance. With the injection target, an interceptor Bean is created using the BeanBuilder of DeltaSpike. The Bean is a Contextual instance that is required by the manager to create a creational context. Having this context we can create a managed instance using the create method. DeltaSpikes contribution to the snippet is the BeanManagerProvider , the BeanBuilder and the DelegatingContextualLifecycle.

private <I> I createInterceptor(final Class<I> interceptorClass) 
  throws InstantiationException, IllegalAccessException {
  
  final I interceptor;
  
  if (BeanManagerProvider.isActive()) {
    final BeanManager manager = BeanManagerProvider.getInstance().getBeanManager();
    final InjectionTarget<I> target = manager.createInjectionTarget(
                                            manager.createAnnotatedType(interceptorClass));
            
    final Bean<I> interceptorBean = 
      new BeanBuilder<I>(manager)
          .beanClass(interceptorClass)
          .beanLifecycle(new DelegatingContextualLifecycle<I>(target))
          .create();
    interceptor = interceptorBean.create(
                     manager.createCreationalContext(interceptorBean));

  } else {
    interceptor = interceptorClass.newInstance();
  }
  return interceptor;
}

Conclusion

In this article I described how the Dynamic Service Client can be extended in order to provide client-side service call interception and how Interceptors (or Beans in general) can be instantiated in a CDI context using Apache DeltaSpike.

Wednesday, July 23, 2014

Developing a dynamic JEE service client with CDI (part 1)

With JEE6 CDI was introduced in and standardized for the Java Enterprise world. The main scope for the CDI extension was for enterprise services as it simplified various mechanisms in the JEE world such as EJB lookup or invocation interception. Unfortunately the new features fall a bit short on the consumer side of services implemented with CDI, in particular the lookup or service locator pattern, and client side invocation interception.
In this first article I want to describe a dynamic service client that performs lazy service dependency resolution (lookup) and that can be injected into a CDI injection point.
It is a good base for being extended to use sophisticated configuration or error handling mechanisms.

Defining a Dynamic Service Locator

In JEE6 its quite easy to perform a JNDI lookup for an EJB using the @EJB annotation. Unfortunately this is done during construction of the service consumers. When you have a multi-module project where each module should be deployable independently from the others, deployment will fail if the dependencies defined by the @EJB annotation could not be satisfied, that is, the EJB lookup fails.
The key to this problem is a lazy lookup, that is done first time the dependency is actually needed. But that is not supported by the @EJB annotation.
In our current project we solved the problem by implementing a dynamic service proxy that implements the interface of the service and performs the lookup using a JNDI lookup or another strategy on the first actual service call.

Creating a Proxy

Creating a dynamic proxy is relatively simple, you need a custom implementation of an InvocationHandler that performs the actual method invocation and need to specify the interfaces the dynamic proxy should implement. A factory method is used to create such a proxy instance. The the following code example shows such a factory method:
public abstract class DynamicServiceClient {

  public static <T> T newInstance(final Class T serviceInterface) {
    return (T) java.lang.reflect.Proxy.newProxyInstance(
      getClassLoader(),
      new Class[] { serviceInterface }, 
      new ProxyServiceInvocationHandler T(config));
    }
 
  private static ClassLoader getClassLoader(){
     ...
  }
}

Invocation Handler

The invocation handler delegates all service call to an instance of the actual service. The service is kept as an instance field of the invocation handler that is initialized upon the first service call using a Service Locator. The invoke method of the Invocation Handler delegates the call to the service instance.

class ProxyServiceInvocationHandler<T> 
  implements InvocationHandler {
 /**
  * The service reference that is lazily initialized
  */
  private T service; 

 /**
  * The service locator that performs the actual lookup
  */
  private final ServiceLocator<T> locator;

    ...

  @Override
  public Object invoke(final Object proxy, final Method method, final Object[] args) 
    throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    //do the lookup if not already done
    if (this.service == null) {
      this.service = this.locator.locate();
    }
    //do the actual service call and return the result
    return method.invoke(this.service, args);
  }
}

Service Locator

The service locator that is used in the the above listing performs the actual lookup. In our project I used an implementation that allowed to define a location strategy in a configuration, with the JNDI lookup being implemented in one of the strategies. The following example however shows a simple implementation that performs a straightforward JNDI lookup using a lookupName.

public class ServiceLocator<T>{
 /**
  * the name for the JNDI lookup
  */
  private String lookupName;

    ...

  public T locate() {
    final Context context = new InitialContext();
    T service = (T)context.lookup(this.lookupName);
    return service;
  }
}

Service Injection

In order to use the dynamic service shown above and inject it via CDI, I used a producer method that creates instances of the dynamic service and a qualifier to distinguish the dynamic service client from the actual service implementation that might be available in the CDI container as well.
The creation of the instance itself is done by the static factory method shown in the first listing. The producer extends the DynamicServiceClient I described earlier and uses its static factory method. In order to keep the producer class simple, we need to extend some methods to the DynamicServiceClient.

The extended DynamicServiceClient that is shown in the following listing contains the logic for the actual service proxy instantiation and an abstract method returning the interface class of the service to be instantiated that has to be implemented by the producer.

public abstract class DynamicServiceClient<T>{
  /**
   * Instance of the service client
   */
  private T serviceInstance;

  /**
   * The method has to return the interface of the service 
   */
  protected abstract Class<T> getServiceInterface();

  /**
   * Creates a new instance of the service client. 
   */
  protected T getInstance() {
   if (serviceInstance == null) {
       serviceInstance = newInstance(getServiceInterface());
   }
   return serviceInstance;
 }

  /**
   * The factory method to create a new service instance
   */
  public static <T> T newInstance(final Class serviceInterface) {
    return (T) Proxy.newProxyInstance(
        getClassLoader(),
        new Class[] { serviceInterface }, 
        new ProxyServiceInvocationHandler());
    }
  }

  private static ClassLoader getClassLoader(){
     ...
  }
}

To qualify an injection point and the producer method to create and inject instances of the service client that implement the service interface and not instances of the actual service, I used a qualifier as shown in the next listing.

@Qualifier
@Retention(RUNTIME)
@Target({ METHOD, FIELD, PARAMETER })
public @interface ServiceClient {}

Now we're ready to define a producer using the DynamicServiceClient as base class. The producer is relatively simple as it only contains two simple methods.


public class MyServiceClientProducer 
  extends DynamicServiceClient<MyBusinessService> {

  @Produces @ServiceClient 
  public MyBusinessService getInstance() {
    return super.getInstance();
  }

  protected Class<MyBusinessService> getServiceInterface() {
    return MyBusinessService.class;
  }
}
To inject the dynamic service client into an injection point we simply have to define the Service interface class and use the qualifier. That's it.

public class MyServiceConsumer {

  @Inject @ServiceClient
  private MyBusinessService service;

  ... 
}

Instead of
public class MyServiceConsumer {

  @EJB(lookup="...")
  private MyBusinessService service;

  ... 
}

Conclusion

In this article I described how to implement a dynamic service locator that can be used in a CDI container. The service locator performs a lookup upon the first call of a service method and therefore provides a mechanism for fault tolerant dependency resolving and further a foundation for implementing client-side service call interception - which I will a describe in a future post.