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 to be used. The
SynapseConfiguration holds the global configuration model that defines
message
mediation rules and common definitions to be used, while the
environment gives
access to the underlying SOAP implementation used.
A typical mediator would need to manipulate the MessageContext by
referring to the SynapseConfiguration. However it is strongly
recommended that
the SynapseConfiguration should not be 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 custom named properties into the
MessageContext
for later retrieval by successive mediators.
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()...
}
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 messages are represented using the SOAP infoset. Binary messages can be embedded in the Envelope using the MTOM support built into Axis2's AXIOM object model.
The second key interface for mediator writers is the Mediator interface:
package org.apache.synapse.api;
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 Mediator {
/**
* 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();
}
A mediator can read and/or modify the SynapseMessage 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.
package org.apache.synapse.api;
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 FilterMediator 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);
}
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();
}
package org.apache.synapse.config;
import ...
/**
* An Extension allows the Synapse configuration to be extended. The Spring
* configuration support is implemented as such an extension, so that the
* Synapse core will not be dependent on Spring classes. An extension
* <b>must</b> specify the following methods to set and get its name.
*/
public interface Extension {
public String getName();
public void setName(String name);
}
package org.apache.synapse.config.xml;
import ....
/**
* A extension factory that is capable of creating an instance of a
* named extension, through a given XML, should implement this interface
*/
public interface ExtensionFactory {
/**
* Creates an instance of a named extension using the OMElement
* @param elem
* @return the created named extension
*/
public Extension createExtension(OMElement elem);
/**
* The QName of the extension element in the XML config
* @return QName of the extension element
*/
public QName getTagQName();
}
extension_mediators.jarThe org.apache.synapse.config.xml.ExtensionFactory text file discussed above contains the line "org.apache.synapse.config.xml.SpringConfigExtensionFactory" but may contain multiple lines specifying a list of extensions contained within the specific JAR file.
/META-INF/services
org.apache.synapse.config.xml.ExtensionFactory
org.apache.synapse.config.xml.MediatorFactory
/... the implementation classes as usual...
package org.apache.synapse.config.xml;The getTagQName() returns the name space "http://ws.apache.org/ns/synapse/spring" and the element name as "config", and thus registers itself as the handler for a <spring:config .../> element where the namespace spring refers to "http://ws.apache.org/ns/synapse/spring". It should be noted that the XML configuration extensions must reside within the <definitions> elements of the Synapse XML configuration. Refer to the Synapse configuration language syntax for more information on the structure of the Synapse XML. If the Synapse configuration builder comes across an XML configuration element that has been registers (as shown above), it will then call into the implementation of the ExtensionFactory implementations' createExtension(OMElement elem) method with the XML element, and an instance of the Extension interface implementation in return. This extension implementation class getName() method is used to store it into the SynapseConfiguration, as a "property", and thus could be retrieved later via this same "name". Hence the implementations should be careful to use unique meaningful names for their implementations.
import ...
/**
* Creates a Spring configuration extension from XML configuration. A Spring
* configuration extension keeps Spring away from the core of synapse
*
* <spring:config name="string" src="file"/>
*/
public class SpringConfigExtensionFactory implements ExtensionFactory {
private static final Log log = LogFactory.getLog(SpringConfigExtensionFactory.class);
private static final QName SPRING_CFG_Q = new QName(Constants.SYNAPSE_NAMESPACE + "/spring", "config");
/**
* <spring:config name="string" src="file"/>
*
* @param elem the XML configuration element
* @return A named Spring Configuration
*/
public Extension createExtension(OMElement elem) {
SpringConfigExtension springCfgExt = null;
OMAttribute name = elem.getAttribute(new QName(Constants.NULL_NAMESPACE, "name"));
OMAttribute src = elem.getAttribute(new QName(Constants.NULL_NAMESPACE, "src"));
if (name == null) {
handleException("The 'name' attribute is required for a Spring configuration definition");
} else if (src == null) {
handleException("The 'src' attribute is required for a Spring configuration definition");
} else {
springCfgExt = new SpringConfigExtension(name.getAttributeValue(), src.getAttributeValue());
}
return springCfgExt;
}
private void handleException(String msg) {
log.error(msg);
throw new SynapseException(msg);
}
}
package org.apache.synapse.config;
import ...
/**
* This defines an extension to Synapse to process a Spring Configuration.
* This keeps the Spring dependency out from the Synapse core, and the
* dependent Jars from the core distribution.
*
* A Spring configuration is usually named, but this class allows an
* inlined configuration to be built up as well, where the Spring mediator
* defines an inline Spring configuration
*/
public class SpringConfigExtension implements Extension {
/**
* The name of this Spring configuration
*/
private String name = null;
/**
* This is the Spring ApplicationContext/BeanFactory
*/
private GenericApplicationContext appContext = null;
/**
* Create a Spring configuration from the given configuration
*
* @param configFile the configuration file to be used
*/
public SpringConfigExtension(String name, String configFile) {
setName(name);
appContext = new GenericApplicationContext();
XmlBeanDefinitionReader xbdr = new XmlBeanDefinitionReader(appContext);
xbdr.setValidating(false);
xbdr.loadBeanDefinitions(new FileSystemResource(configFile));
appContext.refresh();
}
public GenericApplicationContext getAppContext() {
return appContext;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public QName getTagQName() {
return SPRING_CFG_Q;
}
}