Folks

I have restructured and improved yomsp2. I have added it as scratch/prototype2. I hope we are getting near something we can move to head. Please comment. Revision  344984.

Notes on Prototype2
===============
Prototype 2 implements a number of features that have been discussed on the mailing list.

The first thing is to talk through a simple synapse.xml file, and then explain how it works.

The start of the synapse xml is just the owning tag:
<synapse xmlns="http://ws.apache.org/ns/synapse">

The simple XML has three stages, and they are used for both requests and responses:

* logall - log every request and response
    <stage name="logall" rule-type="all">
* service-specific - this stage is used to mediate specific services
    <stage name="service-specific" rule-type="xpath">
* sender - this is a default stage which sends on requests and sends back responses
    <stage name="sender" rule-type="all">
   
If we look at the logall stage first. This uses a "builtin" mediator. This may or may not be a good idea, but it seemed "handy" to have a few
builtin mediators to do common things. At the moment there are just two:
    1) log - uses log4j to log the request and common headers.
    2) sender - sends requests on to their To address and response back to the originator (via ReplyTo or the two-way transport).
   
<stage name="logall" rule-type="all">
        <rule>
            <mediator type="builtin" name="log" />
        </rule>
    </stage>

You can have multiple mediators under <rule> and they are executed in order. This makes it easier to do a number of things if a single rule matches (basically it removes the need for the ListMediator we had earlier).

The next stage is an xpath matching stage:
    <stage name="service-specific" rule-type="xpath">
   
    It just has one rule, which is searching for getQuote requests:
        <rule xpath="//sq:getQuote" xmlns:sq="urn:xmethods-delayed-quotes">

    
    Note that you can define namespaces that will be used in the xpath _expression_ on the tag.
   
    When this matches, it calls a simple mediator to redirect the request.
            <mediator type="spring" name="redirect" bean="redirect">
                <beans>
                    <bean id="redirect" class="sampleMediators.SpringRedirect">
                        <property name="uri" value=" http://FREO:8080/axis/services/E4XStock"/>
                    </bean>
                </beans>
            </mediator>

    This mediator demonstrates the "spring" type of mediators. The <mediator> is expected to have a <beans> child which defines a spring assembly.
    In the spring assembly somewhere should be a bean which implements mediator. The bean is identified by the attribute bean="redirect".
   
    This mediator has a simple implementation:
------------------------------------------
package sampleMediators;

import org.apache.axis2.addressing.EndpointReference;
import org.apache.synapse.api.Mediator;
import org.apache.synapse.api.SOAPMessageContext;

public class SpringRedirect implements Mediator {
    private String uri = null;
    public void setUri(String uri) {
        this.uri = uri;
    }
    public boolean mediate(SOAPMessageContext mc) {
       
        System.out.println("Redirect.mediate : "+uri);
        mc.setTo(new EndpointReference(uri));
        return true;
    }
}
------------------------------------------

The mediator simply changes the To address to one specified by the spring assembly config.

The next stage is the sender stage, which just sends on all requests.

    <stage name="sender" rule-type="all">
        <rule>
            <mediator type="builtin" name="sender"/>
        </rule>
    </stage>

So when a stockquote message comes through this config, first it is logged, then redirected, and then sent on. The response message comes through the same stages (in this particular config), and it is logged. The redirect doesn't match, so then it is simply sent back to the originator.

Here is the synapse.xml

<synapse xmlns="http://ws.apache.org/ns/synapse">
    <stage name="logall" rule-type="all">
        <rule>
            <mediator type="builtin" name="log" />
        </rule>
    </stage>
    <stage name="service-specific" rule-type="xpath">
        <rule xpath="//sq:getQuote" xmlns:sq="urn:xmethods-delayed-quotes">
            <mediator type="spring" name="redirect" bean="redirect">
                <beans>
                    <bean id="redirect" class="sampleMediators.SpringRedirect">
                        <!--property name="uri" value=" http://64.124.140.30:9090/soap"/-->
                        <property name="uri" value="http://FREO:8080/axis/services/E4XStock"/ >
                    </bean>
                </beans>
            </mediator>
        </rule>
    </stage>
    <stage name="sender" rule-type="all">
        <rule>
            <mediator type="builtin" name="sender"/>
        </rule>
    </stage>
</synapse>


Implementation

First an overview on the packages.

org.apache.synapse
In here are the constants, the engine and the synapse.xml parser (EngineConfigurator) and the Exception class.

org.apache.synapse.api
The APIs that a mediator writer would use:
* Mediator, SOAPMessageContext - the core mediator interface
* ConfigurationAware, MediatorConfiguration - to get at the config for a mediator (via ConfigurationAware)
* SynapseEnvironment, EnvironmentAware - for mediators to inject messages back into Synapse

org.apache.synapse.spi
* RuleEngine - interface to add a new rule engine to synapse
* MediatorConfigurator - interface to add a new mediatorType to the engine (basically parses <mediator> element of a given type)

org.apache.synapse.ruleEngines
* The default rule engines - all (executes all rules), xpath (matches xpath expressions), regex (matches regular expressions)

org.apache.synapse.axis2
* implementation of Synapse on top of Axis2
* MessageReceivers dispatchers etc..

sampleMediators.*
* A couple of sample mediators

A message comes in to Axis2. Thru the Axis2 config, all messages are directed to the SynapseMessageReceiver.
The SynapseMR uses the engine's properties to find a single instance of the SynapseEnvironment. If it doesn't exist, it creates the Environment and stores it in the properties. This is the stage at which synapse.xml is processed and the ruleengines and mediators configured.
Then it uses the injectMessage method to inject the message into Synapse processing.

The injectMessage finds the SynapseEngine and calls SynapseEngine.process . This is the main stage handler, which works the message through each stage.
Each Stage is an instance of a ruleEngine. Each rule engine simply has a method "process" which is run on the message. This may execute one or more rules.

There are three rule engines so far (Regex not currently implemented so really two). They each implement a meta rule which is that - currently - they work thru each rule in order. We will optimise this later.

The rules will be discovered using commons-discovery. At the moment the different types are found using a class RuleEngineTypes.

When a rule "hits" we execute each mediator defined underneath it in turn (unless we get a false back). The mediators are executed using a method on the environment - which is probably the wrong place, but it gives a good place to "call back" to Axis2 at this point. The executeMediator method uses Axis2 as a way of dispatching against mediators - so we can utilise the Axis2 phase model (as yet not done).

There are a number of mediation types:
* Service - a deployed Axis2 service // not yet implemented in this prototype
* Spring - a spring beans assembly
* Class - a simple classloader
* Builtin - some simple preconfigured mediations: log and sender (note the builtin impl is a bit of a hack at the moment!)
* E4X - a script mediation // not yet implemented in this prototype

Again these will be pluggable. They are almost pluggable but they use a class called MediatorTypes to indicate which ones. The executeMediator is also a bit hard-coded right now.

Each type uses deployed services to invoke the mediator code. Mediators implement the Mediator interface, and may also implement ConfigurationAware and EnvironmentAware.
When the mediator code is first parsed, the <mediator> tag and children are passed to the correct implementation of MediatorConfigurator. This can parse the XML into some config specific for the mediator type. For example, the SpringMediatorConfigurator parses the <beans> and creates a spring context, which can then be very efficiently used to create the actual bean when a request comes in. The mediatorConfigurator also squirrels away the <mediator> xml, so the mediator can always look at that if it wants to.

There is lots more but this should be a good introduction to the code. After I receive comments I will put this into the Wiki as a introduction (with some diagrams, sequence diags etc).

Regards, Paul

Reply via email to