<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE html
   PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta content="text/html; charset=iso-8859-1" http-equiv="content-type"/>
    <title>
      Extending Synapse
    </title>
    <style type="text/css" xml:space="preserve">
    .command {
        border: 1px dashed #3c78b5;
        text-align: left;
        background-color: #f0f0f0;
        padding: 3px;
        font-size: 11px;
        font-family: Courier;
        margin: 10px;
        line-height: 13px;
    }
    .consoleOutput {
        border: 1px dashed #3c78b5;
        font-size: 11px;
        font-family: Courier;
        margin: 10px;
        line-height: 13px;
        background-color: #f0f0f0;
        border-bottom: 1px dashed #3c78b5;
        padding: 3px;
        border-style: solid;
    }
    .info {
        border-style: solid;
        border-width: 1px;
        border-color: #090;
        background-color: #dfd;
        text-align:left;
        margin-top: 5px;
        margin-bottom: 5px;
    }
    li {
        font-family: Verdana, arial, sans-serif;
        font-size: 11px;
        line-height: 16px;
        color: #000000;
        font-weight: normal;
    }
    p {
        font-family: Verdana, arial, sans-serif;
        font-size: 11px;
        line-height: 16px;
        color: #000000;
        font-weight: normal;
    }
    pre {
        padding: 0px;
        margin-top: 5px;
        margin-left: 15px;
        margin-bottom: 5px;
        margin-right: 5px;
        text-align: left;
        background-color: #f0f0f0;
        padding: 3px;
        border: 1px dashed #3c78b5;
        font-size: 11px;
        font-family: Courier;
        margin: 10px;
        line-height: 13px;
    }
    h1 {
        font-size: 24px;
        line-height: normal;
        font-weight: bold;
        background-color: #f0f0f0;
        color: #003366;
        border-bottom: 1px solid #3c78b5;
        padding: 2px;
        margin: 36px 0px 4px 0px;
    }
    h2 {
        font-size: 18px;
        line-height: normal;
        font-weight: bold;
        background-color: #f0f0f0;
        border-bottom: 1px solid #3c78b5;
        padding: 2px;
        margin: 27px 0px 4px 0px;
    }
    h3 {
        font-size: 14px;
        line-height: normal;
        font-weight: bold;
        background-color: #f0f0f0;
        padding: 2px;
        margin: 21px 0px 4px 0px;
    }
    h4 {
        font-size: 12px;
        line-height: normal;
        font-weight: bold;
        background-color: #f0f0f0;
        padding: 2px;
        margin: 18px 0px 4px 0px;
    }</style>
  </head>
  <body>
    <h1>
      Extending Synapse<br/>
    </h1>
    <h2>
      Writing custom Mediator implementations
    </h2>
    <p>
      The primary interface of the Synapse API is the MessageContext interface
      defined below. This essentially defines the per-message context passed
      through the chain of mediators, for each and every message received and
      processed by Synapse. Each message instance is wrapped within a
      MessageContext instance, and the message context is set with the
      references to the SynapseConfiguration and SynapseEnvironments. The
      SynapseConfiguration holds the global configuration model that defines
      mediation rules, local registry entries and other and configuration, while
      the environment gives access to the underlying SOAP implementation used -
      Axis2. A typical mediator would need to manipulate the MessageContext by
      referring to the SynapseConfiguration. However it is strongly recommended
      that the SynapseConfiguration is not updated by mediator instances as it
      is shared by all messages, and may be updated by Synapse administration or
      configuration modules. Mediator instances may store local message
      properties into the MessageContext for later retrieval by successive
      mediators.<br/>
    </p>
    <h4>
      <a
      href="http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/MessageContext.java?view=markup">MessageContext
      Interface</a>
    </h4>
    <p/>
<pre xml:space="preserve">package org.apache.synapse;

import ...

public interface MessageContext {

    /**
     * Get a reference to the current SynapseConfiguration
     *
     * @return the current synapse configuration
     */
    public SynapseConfiguration getConfiguration();

    /**
     * Set or replace the Synapse Configuration instance to be used. May be used to
     * programatically change the configuration at runtime etc.
     *
     * @param cfg The new synapse configuration instance
     */
    public void setConfiguration(SynapseConfiguration cfg);

    /**
     * Returns a reference to the host Synapse Environment
     * @return the Synapse Environment
     */
    public SynapseEnvironment getEnvironment();

    /**
     * Sets the SynapseEnvironment reference to this context
     * @param se the reference to the Synapse Environment
     */
    public void setEnvironment(SynapseEnvironment se);

    /**
     * Get the value of a custom (local) property set on the message instance
     * @param key key to look up property
     * @return value for the given key
     */
    public Object getProperty(String key);

    /**
     * Set a custom (local) property with the given name on the message instance
     * @param key key to be used
     * @param value value to be saved
     */
    public void setProperty(String key, Object value);

    /**
     * Returns the Set of keys over the properties on this message context
     * @return a Set of keys over message properties
     */
    public Set getPropertyKeySet();

    /**
     * Get the SOAP envelope of this message
     * @return the SOAP envelope of the message
     */
    public SOAPEnvelope getEnvelope();

    /**
     * Sets the given envelope as the current SOAPEnvelope for this message
     * @param envelope the envelope to be set
     * @throws org.apache.axis2.AxisFault on exception
     */
    public void setEnvelope(SOAPEnvelope envelope) throws AxisFault;

    /**
     * SOAP message related getters and setters
     */
    public ....get/set()...

}</pre>
    <p>
      The MessageContext interface is based on the Axis2 <a>MessageContext</a>
      interface, and uses the Axis2 <a>EndpointReference</a> and
      SOAPEnvelope classes/interfaces. The purpose of this interface is to
      capture a message as it flows through the system. As you will see the
      message payload is represented using the SOAP infoset. Binary messages can
      be embedded in the Envelope using MTOM or SwA attachments using the AXIOM
      object model.
    </p>
    <h4>
      <a
      href="http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/Mediator.java?view=markup">Mediator
      interface</a>
    </h4>
    <p>
      The second key interface for mediator writers is the Mediator interface:
    </p>
<pre xml:space="preserve">package org.apache.synapse;

import org.apache.synapse.MessageContext;

/**
 * All Synapse mediators must implement this Mediator interface. As a message passes
 * through the synapse system, each mediator's mediate() method is invoked in the
 * sequence/order defined in the SynapseConfiguration.
 */
public interface <span style="font-weight: bold;">Mediator </span>{

    /**
     * Invokes the mediator passing the current message for mediation. Each
     * mediator performs its mediation action, and returns true if mediation
     * should continue, or false if further mediation should be aborted.
     *
     * @param synCtx the current message for mediation
     * @return true if further mediation should continue
     */
    public boolean mediate(MessageContext synCtx);

    /**
     * This is used for debugging purposes and exposes the type of the current
     * mediator for logging and debugging purposes
     * @return a String representation of the mediator type
     */
    public String getType();
}</pre>
    <p>
      A mediator can read and/or modify the <a>SynapseMessage</a> in
      any suitable manner - adjusting the routing headers or changing the
      message body. If the mediate() method returns false, it signals to the
      Synapse processing model to stop further processing of the message. For
      example, if the mediator is a security agent it may decide that this
      message is dangerous and should not be processed further. This is
      generally the exception as mediators are usually designed to co-operate to
      process the message onwards.
    </p>
    <h3>
      Leaf and Node Mediators, List mediators and Filter mediators
    </h3>
    <p>
      Mediators may be Node mediators (i.e. these that can contain child
      mediators) or Leaf mediators (mediators that does not hold any other child
      mediators). A Node mediator  must implement the
      org.apache.synapse.api.ListMediator interface listed below, or extend from
      the org.apache.synapse.mediators.AbstractListMediator.
    </p>
    <h4>
      <a
      href="http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/ListMediator.java?view=markup">The
      ListMediator interface</a>
    </h4>
<pre xml:space="preserve">package org.apache.synapse.mediators;

import java.util.List;

/**
* The List mediator executes a given sequence/list of child mediators
*/
public interface ListMediator extends Mediator {
    /**
    * Appends the specified mediator to the end of this mediator's (children) list
    * @param m the mediator to be added
    * @return true (as per the general contract of the Collection.add method)
    */
    public boolean addChild(Mediator m);

    /**
    * Appends all of the mediators in the specified collection to the end of this mediator's (children)
    * list, in the order that they are returned by the specified collection's iterator
    * @param c the list of mediators to be added
    * @return true if this list changed as a result of the call
    */
    public boolean addAll(List c);

    /**
    * Returns the mediator at the specified position
    * @param pos index of mediator to return
    * @return the mediator at the specified position in this list
    */
    public Mediator getChild(int pos);

    /**
    * Removes the first occurrence in this list of the specified mediator
    * @param m mediator to be removed from this list, if present
    * @return true if this list contained the specified mediator
    */
    public boolean removeChild(Mediator m);

    /**
    * Removes the mediator at the specified position in this list
    * @param pos the index of the mediator to remove
    * @return the mediator previously at the specified position
    */
    public Mediator removeChild(int pos);

    /**
    * Return the list of mediators of this List mediator instance
    * @return the child/sub mediator list
    */
    public List getList();
}</pre>
    <p>
      A ListMediator implementation should call super.mediate(synCtx) to process
      its sub mediator sequence. A FilterMediator is a ListMediator which
      executes its sequence of sub mediators on successful outcome of a test
      condition. The Mediator instance which performs filtering should implement
      the FilterMediator interface.
    </p>
    <h4>
      <a
      href="http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/FilterMediator.java?view=markup">FilterMediator
      interface</a>
    </h4>
<pre xml:space="preserve">package org.apache.synapse.mediators;

import org.apache.synapse.MessageContext;

/**
 * The filter mediator is a list mediator, which executes the given (sub) list of mediators
 * if the specified condition is satisfied
 *
 * @see FilterMediator#test(org.apache.synapse.MessageContext)
 */
public interface <span style="font-weight: bold;">FilterMediator </span>extends ListMediator {

    /**
     * Should return true if the sub/child mediators should execute. i.e. if the filter
     * condition is satisfied
     * @param synCtx
     * @return true if the configured filter condition evaluates to true
     */
    public boolean test(MessageContext synCtx);
}</pre>
    <h2>
      Writing custom Configuration implementations for mediators
    </h2>
    <p>
      You may write your own custom configurator for the Mediator implementation
      you write without relying on the Class mediator or Spring extension for
      its initialization. You could thus write a MediatorFactory implementation
      which defines how to digest a custom XML configuration element to be used
      to create and configure the custom mediator instance. A MediatorSerializer
      implementation defines how a configuration should be serialized back into
      an XML configuration. The custom MediatorFactory &amp; MediatorSerializer
      implementations and the mediator class/es must be bundled in a JAR file
      conforming to the J2SE Service Provider model (See the description for
      Extensions below for more details and examples) and placed into the
      SYNAPSE_HOME/lib folder, so that the Synapse runtime could find and load
      the definition. Essentially this means that a custom JAR file must bundle
      your class implementing the Mediator interface, and the MediatorFactory
      implementation class and contain two text files named
      "org.apache.synapse.config.xml.MediatorFactory" and
      "org.apache.synapse.config.xml.MediatorSerializer" which will contain the
      fully qualified name(s) of your MediatorFactory and MediatorSerializer
      implementation classes. You should also place any dependency JARs into the
      same lib folder so that the correct classpath references could be made.
      The MediatorFactory interface listing is given below, which you should
      implement, and its getTagQName() method must define the fully qualified
      element of interest for custom configuration. The Synapse initialization
      will call back to this MediatorFactory instance through the
      createMediator(OMElement elem) method passing in this XML element, so that
      an instance of the mediator could be created utilizing the custom XML
      specification and returned. See the ValidateMediator and the
      ValidateMediatorFactory classes under modules/extensions in the Synapse
      source distribution for examples.
    </p>
    <h4>
      <a
      href="http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/config/xml/MediatorFactory.java?view=markup">The
      MediatorFactory interface</a>
    </h4>
<pre xml:space="preserve">package org.apache.synapse.config.xml;

import ...

/**
 * A mediator factory capable of creating an instance of a mediator through a given
 * XML should implement this interface
 */
public interface MediatorFactory {
    /**
     * Creates an instance of the mediator using the OMElement
     * @param elem
     * @return the created mediator
     */
    public Mediator createMediator(OMElement elem);

    /**
     * The QName of this mediator element in the XML config
     * @return QName of the mediator element
     */
    public QName getTagQName();
}</pre>
    <p/>
    <h4>
      <a
      href="http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/config/xml/MediatorSerializer.java?view=markup">The
      MediatorSerializer interface</a>
    </h4>
<pre xml:space="preserve">package org.apache.synapse.config.xml;

import ...

/**
 * Interface which should be implemented by mediator serializers. Does the
 * reverse of the MediatorFactory
 */
public interface MediatorSerializer {

    /**
     * Return the XML representation of this mediator
     * @param m mediator to be serialized
     * @param parent the OMElement to which the serialization should be attached
     * @return the serialized mediator XML
     */
    public OMElement serializeMediator(OMElement parent, Mediator m);

    /**
     * Return the class name of the mediator which can be serialized
     * @return the class name
     */
    public String getMediatorClassName();
}</pre>
    <h2>
      Configuring mediators
    </h2>
    <p>
      Mediators could access the Synapse registry to load resources and
      configure the local behaviour. Refer to the Spring mediator and Script
      mediator implementations for examples on how this could be achieved.
    </p>
    <h4>
      Loading of Extensions by the Synapse runtime
    </h4>
    <p>
      Synapse loads available extensions from the runtime classpath using the <a
      href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider">J2SE
      Service Provider model</a>. This essentially iterates over the
      available JAR files, for  a META-INF/services directory within each file,
      and looks for a text file with the name
      org.apache.synapse.config.xml.MediatorFactory which contains a list of
      fully qualified classname that implement the above interface, listing each
      class in a separate line. e.g. The built-in synapse-extensions.jar
      contains the following structure
    </p>
<pre xml:space="preserve">synapse-extensions.jar
    /META-INF/services
        org.apache.synapse.config.xml.MediatorFactory
        org.apache.synapse.config.xml.MediatorSerializer
    /... the implementation classes as usual...</pre>
  </body>
</html>