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

<!--
  ~  Licensed to the Apache Software Foundation (ASF) under one
  ~  or more contributor license agreements.  See the NOTICE file
  ~  distributed with this work for additional information
  ~  regarding copyright ownership.  The ASF licenses this file
  ~  to you under the Apache License, Version 2.0 (the
  ~  "License"); you may not use this file except in compliance
  ~  with the License.  You may obtain a copy of the License at
  ~
  ~   http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~  Unless required by applicable law or agreed to in writing,
  ~  software distributed under the License is distributed on an
  ~   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~  KIND, either express or implied.  See the License for the
  ~  specific language governing permissions and limitations
  ~  under the License.
  -->

<document>
	<properties>
		<title>Apache Synapse - Extending Synapse</title>
	</properties>
	<body>
			<div id="contentBox">
				   <section name="Apache Synapse ESB - Extending Synapse">
					<p>
						Apache Synapse provides a number of extension points so that
						users can plug-in custom developed code to extend the
						functionality of the ESB. While the built-in mediators are sufficient to implement
						most integration scenarios, sometimes it is very helpful to be able to deploy some custom code into the
						service bus and make the solution simpler. Most Synapse APIs are in Java and
						therefore the users looking to extend Synapse are expected to have a
						decent knowledge and experience in Java programming.
					</p>
					</section>
					<section name="Writing custom Mediator implementations">
				
					<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
						SynapseEnvironment objects. The
						<a href="../apidocs/org/apache/synapse/config/SynapseConfiguration.html">SynapseConfiguration</a>

						object holds the global configuration model that defines
						mediation rules, local registry entries and other and configuration, while
						the
						<a href="../apidocs/org/apache/synapse/core/SynapseEnvironment.html">SynapseEnvironment</a>

						object 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 class="externalLink"
							href="http://svn.apache.org/viewvc/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/MessageContext.java?view=markup">MessageContext
							Interface
						</a>
					</h4>
					<div class="xmlConf">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
     * programmatically 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()...

}</div>
					<p>
						The MessageContext interface is based on the Axis2
						MessageContext 	interface, and uses the Axis2 EndpointReference 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 class="externalLink"
							href="http://svn.apache.org/viewvc/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>
					<div class="xmlConf">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();
}</div>
					<p>
						A mediator can read and/or modify the message encapsulated in
						the MessageContext 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 rocess the message
						onwards.
					</p>
					</section>
					
					<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.mediators.ListMediator interface listed below,
						or extend from the
						org.apache.synapse.mediators.AbstractListMediator.
					</p>
					<h4>
						<a class="externalLink"
							href="http://svn.apache.org/viewvc/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/ListMediator.java?view=markup">The
							ListMediator interface
						</a>
					</h4>
					<div class="xmlConf">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();
}</div>
					<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 class="externalLink"
							href="http://svn.apache.org/viewvc/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/FilterMediator.java?view=markup">FilterMediator
							interface
						</a>
					</h4>
					<div class="xmlConf">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);
}</div>
				</div>
				<section name="Writing custom Configuration implementations for mediators">
					<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
						&quot;org.apache.synapse.config.xml.MediatorFactory&quot; and
						&quot;org.apache.synapse.config.xml.MediatorSerializer&quot; 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 class="externalLink"
							href="http://svn.apache.org/viewvc/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/config/xml/MediatorFactory.java?view=markup">The
							MediatorFactory interface
						</a>
					</h4>
					<div class="xmlConf">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();
}</div>
					<h4>
						<a class="externalLink"
							href="http://svn.apache.org/viewvc/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/config/xml/MediatorSerializer.java?view=markup">The
							MediatorSerializer interface
						</a>
					</h4>
					<div class="xmlConf">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();
}</div>
				</section>
				<section name="Configuring mediators">
					<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 class="externalLink"
							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>
					<div class="xmlConf">synapse-extensions.jar
    /META-INF/services
        org.apache.synapse.config.xml.MediatorFactory
        org.apache.synapse.config.xml.MediatorSerializer
    /... the implementation classes as usual...</div>
				</section>
				
				
				<section name="Writing Synapse Observers">
					<p>
						A Synapse observer is developed by either implementing the
						org.apache.synapse.config.SynapseObserver interface or by
						extending the org.apache.synapse.config.AbstractSynapseObserver
						class. A Synapse observer is notified by the Synapse configuration
						when new elements are added to the configuration and
						when existing elements are removed from the configuration. The
						following event handlers are available to the Synapse observer implementations.
					</p>
					<div class="xmlConf"> public void sequenceAdded(Mediator sequence);
 public void sequenceRemoved(Mediator sequence);
 public void entryAdded(Entry entry);
 public void entryRemoved(Entry entry);
 public void endpointAdded(Endpoint endpoint);
 public void endpointRemoved(Endpoint endpoint);
 public void proxyServiceAdded(ProxyService proxy);
 public void proxyServiceRemoved(ProxyService proxy);
 public void startupAdded(Startup startup);
 public void startupRemoved(Startup startup);
 public void eventSourceAdded(SynapseEventSource eventSource);
 public void eventSourceRemoved(SynapseEventSource eventSource);</div>
					<p>
						The AbstractSynapseObserver provides default implementations to
						all these event handlers. It simply logs any received events.
					</p>
					<p>
						In situations where the custom code has access to the
						SynapseConfiguration class observers can be directly registered
						with the SynapseConfiguration by using
						the registerObserver(SynapseObserver o) method. Otherwise
						SynapseObserver implementations
						can be defined in the synapse.properties file which resides in the
						SYNAPSE_HOME/lib directory. The following example shows how two observers are
						registered with the Synapse configuration using the
						synapse.properties file.
					</p>
					<div class="xmlConf">synapse.observers=test.LoggingObserverImpl, test.SimpleObserverImpl</div>
				</section>
				
        <section name="Scheduled Tasks">
            <p>
                A scheduled task is a custom developed piece of Java code that
                is scheduled in the ESB to execute periodically. A scheduled task
                must implement the org.apache.synapse.task.Task
                interface. This interface has a single 'execute' method. Once scheduled the
                execute method is called by Synapse periodically.
            </p>
            <p>
                Synapse also comes with a built-in task implementation known as
                the	MessageInjector. This task can be used to inject messages into
                the service bus	periodically. Refer	sample 300 to see how to use the
                MessageInjector task.
            </p>
         </section>
	</body>
</document>