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.
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
SynapseConfiguration
object holds the global configuration model that defines
mediation rules, local registry entries and other and configuration, while
the
SynapseEnvironment
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.
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.
The second key interface for mediator writers is the Mediator interface:
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.
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.
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.
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.
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.
Synapse loads available extensions from the runtime classpath using the J2SE Service Provider model . 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
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.
The AbstractSynapseObserver provides default implementations to all these event handlers. It simply logs any received events.
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.
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.
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.