| <?xml version="1.0" encoding="ISO-8859-1"?> |
| |
| <document> |
| <properties> |
| <title>Extending...</title> |
| </properties> |
| <body> |
| <section name="Apache Synapse ESB - Extending..."> |
| <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 |
| 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> |
| <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 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 |
| 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> |
| <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 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 |
| 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.mediators.ListMediator interface listed below, or extend from |
| the org.apache.synapse.mediators.AbstractListMediator. |
| </p> |
| <h4> |
| <a |
| 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> |
| <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/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> |
| </section> |
| <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 & 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/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/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> |
| </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 |
| 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> |
| </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> |
| <pre xml:space="preserve"> |
| 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); |
| </pre> |
| <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> |
| <pre xml:space="preserve">synapse.observers=test.LoggingObserverImpl, test.SimpleObserverImpl</pre> |
| </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> |