Tuscany phase-based interceptor ordering

The problem

As of today, we can add multiple interceptors to the invocation chain, but
we cannot control their ordering. When more policies are supported, I see a
need to provide some simple ordering mechnisim for interceptors. There are a few examples:

1) binding/implementation invokers have to be the last one in the invocation chain.
2) for a service wire, service-level policy handlers (such as propategate/suspend transaction) must be called before implementation-level
handlers (such as managed/noManagedTransaction, security run-as).
3) if I add a encryption/decryption policy handler, it needs to be invoked after the data transformation interceptor on the client side, and before the
data transformation interceptor on the service side.
4) pass-by-value interceptor (if required) should be invoked before the implementation-invoker.

SCA invocation may have three stages: reference, service and implementation.
For example, a typical invocation chain for the reference side can be:

  • reference: (SourceComponent) --> DataTransformation --> Suspend/PropagateTransaction --> ReferenceBindingInvoker --> ...
  • service: (ServiceBindingListener) --> DataTransformation --> PropagateTransaction
  • implementation: ManagedTransaction --> ImplementationInvoker --> (TargetComponent)

The proposal

We introduce a phase concept which groups a collection of interceptors to a
relative position in the invocation chain for each stage. There are a list
of system defined phases (such as reference.invoker or
implementation.invoker) and it can be extended by Tuscany extensions.

Each phase is uniquely identied by the name. Each phase can define its
relative ordering using the 'before' and/or 'after' attributes. When an
interceptor is added to the InvocationChain, we can specify a phase name.
The Tuscany runtime will sort the phases by the partial order. SCA
invocations will be dispatched in the order of phases. There is no ordering
between interceptors in the same phase.

To define a phase, we use the following simple syntax in the service provider file named as "META-INF/services/org.apache.tuscany.sca.invocation.Phase".

name=PhaseName, stage=stageName, before=PhaseName4 PhaseName5, after=PhaseName3

  • name: The name of the phase
  • stage: The stage of the phase, it can be one of the values: reference, service, or implemention
  • before: A list of phase names separated by spaces to denote this phase should be placed before
  • after: A list of phase names separated by spaces to denote this phase should be placed after

A special phase name '*' can be used for 'before' and 'after' attribute to represent all phases.

For example,

name=reference.invoker, stage=reference, after=*
name=reference.databinding, stage=reference, before=reference.invoker
name=reference.transaction, stage=reference, after=reference.databinding

The SPIs

public interface Phase {
    // The fisrt phase for outgoing invocations via a reference
    String REFERENCE = "component.reference";

    // data transformation and validation
    String REFERENCE_INTERFACE = "reference.interface";

    // reference policy handling
    String REFERENCE_POLICY = "reference.policy";

    // reference binding invoker
    String REFERENCE_BINDING = "reference.binding";

    // The first phase for incoming invocations via a service
    String SERVICE_BINDING = "service.binding";

    // service policy handling
    String SERVICE_POLICY = "service.policy";

    // data validation and transformation
    String SERVICE_INTERFACE = "service.interface";

    // TODO: not sure if we need to have this face
    String SERVICE = "component.service";

    // implementation policy handling
    String IMPLEMENTATION_POLICY = "implementation.policy";

    // implementation invoker
    String IMPLEMENTATION = "component.implementation";

}
public interface InvocationChain {
    /**
     * Add an interceptor to the given phase
     * @param phase
     * @param interceptor
     */
    void addInterceptor(String phase, Interceptor interceptor);
...
}
  • No labels