Creating Transports
Mule Runtime Engine versions 3.5, 3.6, and 3.7 reached End of Life on or before January 25, 2020. For more information, contact your Customer Success Manager to determine how you can migrate to the latest Mule version. |
Transports are used to implement message channels and provide connectivity to an underlying data source or message channel in a consistent way. Mule provides transports for many different protocols, including File, FTP, HTTP, JMS, JDBC, Quartz, and many more. For a complete list, see Transports Reference. There are also community-created transports (also known as connectors) in Anypoint Exchange. If you need to send messages on a protocol other than those provided, you can create a new connector.
Overview
When creating a new transport, you must implement a set of Mule interfaces in the org.mule.transport package, and then extend the provided abstract classes. For a quick start, you can use the Maven transport archetype as a code template for your transports. If you want to update an existing transport, use the Creating Module Archetypes instead.
Mule transports can be one of the following types:
-
Inbound-only: Components can only subscribe to events. They cannot dispatch events.
-
Outbound-only: Components can only dispatch events. They cannot subscribe to events.
-
Inbound-outbound: Components can subscribe and dispatch events
Transport Interfaces
A transport consists of a set of interface implementations that expose the features for the underlying transport.
Interface | Role |
---|---|
Connector |
Used to manage Receivers, Dispatchers and Requesters and to store any configuration information. |
Message Receiver |
Implements the server part of the transport. For example, a TcpMessageReceiver creates a server socket to receive incoming requests. A MessageReceiver instance is created when this transport is used for inbound communication. |
Message Dispatcher |
Implements the client part of the transport. For example, a TcpMessageDispatcher opens a socket to send requests. A MessageDispatcher instance is created when this transport for outbound communication. |
Message Requester |
Is also used to receive incoming messages like the MessageReceiver but rather than subscribing to inbound events or polling a resource or message channel messages are only received on "request". Inbound endpoints on services always use a MessageReceiver rather than a MessageRequester but they can be used elsewhere programatically to request a single message from a message channel or resource. |
Message Factory |
Creates a MuleMessage instance from the incoming transport message. For example, the HTTP message factory creates a new MuleMessage by using the HTTP request’s input stream as payload and puts all request headers as properties to the MuleMessage. |
Transformers |
Transformers are used to convert data between the transport-specific data format and another format, such as from an HTTP response to a string. The dispatcher must call |
Endpoints |
The means of configuring the use of message channels or resource as part of service configuration. The endpoint defines which transport to use and includes settings like the host or queue name, the filter to use, and transaction info. Defining an endpoint on a service causes Mule to create the necessary transport connector for the protocol being used. |
When writing a transport, you must implement the following interfaces that define the contract between Mule and the underlying technology.
org.mule.api.transport.Connector
The connector is used by Mule to register listeners and create message dispatchers for the transport. Configuration parameters that should be shared by all Message Receivers, Dispatchers and Requesters are stored on the connector. Usually, only one connector instance is needed for multiple inbound and outbound endpoints as multiple Message Receivers, Dispatchers and Requesters can be associated with a connector. However, where the underlying transport API has the notion of a connection such as the JMS or JDBC API, there should be a one-to-one mapping between the Mule connector and the underlying connection.
org.mule.api.transport.MessageReceiver
The Message Receiver is used to receive incoming data from the underlying transport and package it as an event. The Message Receiver is essentially the server implementation of the transport (where the Message Dispatcher is a client implementation). For example, the HTTP Message Receiver is an HTTP server implementation that accepts HTTP requests. An implementation of this class is needed if the transport supports inbound communication.
org.mule.api.transport.MessageDispatcher
The Message Dispatcher is used to send messages, which is akin to making client calls with the underlying technology. For example, the CXF Message Dispatcher makes a web service call. An implementation of this class is needed if the transport supports outbound communication. The Message Dispatcher must call MuleEvent.transformMessage()
to invoke any necessary transformers before dispatching it.
org.mule.api.transport.MessageRequester
The Message Requester is used to request messages from a message channel or resource rather than subscribing to inbound events or polling a resource for messages. This is often used programatically but is not used for inbound endpoints configured on services. An implementation of this class is needed if the transport supports the requesting of messages from a message channel.
Implementation
Mule provides abstract implementations for all of the above interfaces. These implementations handle all the Mule specifics, leaving a few abstract methods where custom transport code should be implemented. Therefore, writing a custom transport is as easy as writing/embedding client and or server code specific to the underlying technology. The following sections describes the implementations available to you.
For a quick start, use the Maven Transport Archetype.
Connectors
The org.mule.transport.AbstractConnector implements all the default functionality required for Mule connectors, such as threading configuration and receiver/dispatcher management. For details about the standard connector properties, see Configuring a Transport.
You can set further properties on the connector that act as defaults. For example, you can set endpoint properties that are used by default unless you override them when configuring a specific endpoint.
Sometimes the connector is responsible for managing a connection resource of the transport where the underlying technology has the notion of a connection, such as in JMS or JDBC. These types of connectors have a one-to-one mapping between a Mule connector and the underlying connection. Therefore, if you want to have two or more physical JMS connections in a single Mule instance, a new connector should be created for each connection.
For other transports, there is only one connector of a particular protocol in a Mule instance that manages all endpoint connections. One such example would be socket-based transports such as TCP where each receiver manages its own ServerSocket and the connector manages multiple receivers.
Methods to Implement
Method Name | Description | Required |
---|---|---|
doInitialise() |
Is called once all bean properties have been set on the connector and can be used to validate and initialize the connector’s state. |
No |
doStart() |
If there is a single server instance or connection associated with the connector (such as AxisServer or a JMS or JDBC Connection), this method should put the resource in a started state. |
No |
doConnect() |
Makes a connection to the underlying resource if this is not handled at the receiver/dispatcher level. |
No |
doDisconnect() |
Close any connection made in doConnect(). |
No |
doStop() |
Should put any associated resources into a stopped state. Mule automatically calls the stop() method. |
No |
doDispose() |
Should clean up any open resources associated with the connector. |
No |
Message Receivers
Message Receivers behave differently for each transport, but Mule provides some standard implementations that can be used for polling resources and managing transactions for the resource. Usually there are two types of Message Receivers: Polling and Listener-based.
-
A Polling Receiver polls a resource such as the file system, database, and streams.
-
A Listener-based receiver registers itself as a listener to a transport. Examples would be JMS (javax.message.MessageListener) and Pop3 (javax.mail.MessageCountListener). These base types may be transacted.
The abstract implementations provided by Mule are described below.
Abstract Message Receiver
The AbstractMessageReceiver provides methods for routing events. When extending this class, you should set up the necessary code to register the object as a listener to the transport. This is usually a case of implementing a listener interface and registering itself.
Methods to Implement
Method name | Description | Required |
---|---|---|
doConnect() |
Should make a connection to the underlying transport, such as to connect to a socket or register a SOAP service. When there is no connection to be made, this method should be used to check that resources are available. For example, the FileMessageReceiver checks that the directories it uses are available and readable. The MessageReceiver should remain in a 'stopped' state even after the doConnect() method is called. This means that a connection has been made but no events are received until the start() method is called. Calling start() on the MessageReceiver calls doConnect() if the receiver hasn’t connected. |
Yes |
doDisconnect() |
Disconnects and tidies up any resources allocated using the doConnect() method. This method should return the MessageReceiver in a disconnected state so that it can be connected again using the doConnect() method. |
Yes |
doStart() |
Should perform any actions necessary to enable the receiver to start receiving events. This is different from the doConnect() method, which actually makes a connection to the transport but leaves the MessageReceiver in a stopped state. For polling-based MessageReceivers, the doStart() method simply starts the polling thread. For the Axis message receiver, the start method on the SOAPService is called. The action performed depends on the transport being used. Typically, a custom transport doesn’t need to override this method. |
No |
doStop() |
Should perform any actions necessary to stop the receiver from receiving events. |
No |
doDispose() |
Is called when the connector is being disposed and should clean up any resources. The doStop() and doDisconnect() methods are called implicitly when this method is called. |
No |
Polling Message Receiver
Some transports poll a resource periodically waiting for new data to arrive. The polling message receiver, which is based on AbstractPollingMessageReceiver, implements the code necessary to set up and destroy a listening thread and provides a single method poll()
that is invoked repeatedly at a given frequency. Setting up and destroying the listening thread should occur in the doStart() and doStop() methods respectively.
Transacted Polling Message Receiver
The TransactedPollingMessageReceiver can be used by transaction-enabled transports to manage polling and transactions for incoming requests. This receiver uses a transaction template to execute requests in transactions, and the transactions themselves are created according to the endpoint configuration for the receiver. Derived implementations of this class must be thread safe, as several threads can be started at once for an improved throughput.
Methods to Implement
You implement the following methods for the transacted polling message receiver in addition to those in the standard Message Receiver:
Method name | Description | Required |
---|---|---|
getMessages() |
Returns a list of objects that represent individual message payloads. The payload can be any type of object and is sent to Mule services wrapped in a MuleEvent object. |
Yes |
processMessage(Object) |
is called for each object in the list returned from |
Yes |
Thread Management
It’s common for receivers to spawn a thread per request. All receiver threads are allocated using the WorkManager on the receiver. The WorkManager is responsible for executing units of work in a thread. It has a thread pool that allows threads to be reused and ensures that only a prescribed number of threads are spawned.
The WorkManager is an implementation of org.mule.api.context.WorkManager, which is really just a wrapper of javax.resource.spi.work.WorkManager with some extra lifecycle methods. There is a getWorkManager()
method on the AbstractMessageReceiver that you can use to get a reference to the WorkManager for the receiver. Work items (such as the code to execute in a separate thread) must implement javax.resource.spi.work.Work
. This interface extends java.lang.Runnable
and thus has a run()
method that is invoked by the WorkManager.
When scheduling work with the WorkManager, you should call scheduleWork(…)
on the WorkManager rather than startWork(…)
.
Message Dispatchers
Whereas a message receiver is equivalent to a server for the transport in that it serves client requests, a message dispatcher is the client implementation of the transport. Message dispatchers are responsible for making client requests over the transport, such as writing to a socket or invoking a web service. The AbstractMessageDispatcher provides a good base implementation, leaving three methods for the custom MessageDispatcher to implement.
Methods to Implement
Method Name | Description | Required |
---|---|---|
doSend(MuleEvent) |
Sends the message payload over the transport. If there is a response from the transport, it should be returned from this method. The |
Yes |
doDispatch(MuleEvent) |
Invoked when the endpoint is asynchronous and should invoke the transport but not return any result. If a result is returned, it should be ignored, and if they underlying transport does have a notion of asynchronous processing, that should be invoked. This method is executed in a different thread from the request thread. |
Yes |
doConnect() |
Makes a connection to the underlying transport, such as connecting to a socket or registering a SOAP service. When there is no connection to be made, this method should be used to check that resources are available. For example, the |
Yes |
doDisconnect() |
Disconnects and tidies up any resources that were allocated by the |
Yes |
doDispose() |
Called when the Dispatcher is being disposed and should clean up any open resources. |
No |
Message Requesters
As with message receivers and dispatchers the implementation of a message requester for a transport, if it even applies, varies greatly. The abstract AbstractMessageRequester provides a base from which to extend and implement your own Message Requester and implemented methods for routing events. Although requesters can implement doConnect
and doDisconnect
methods given the nature of a requester this can also be done as part of the doRequest
implementation, it really depending on the underlying transport and if you need to maintain a connection open all the time or not to be able to make arbitrary requests.
Method Name | Description | Required |
---|---|---|
doRequest(long) |
Used to make arbitrary requests to a transport resource. If the timeout is 0, the method should block until a message on the endpoint is received. |
|
doConnect() |
Should make a connection to the underlying transport if required, such as to connect to a socket.. |
No |
doDisconnect() |
Disconnects and tidies up any resources allocated using the doConnect() method. This method should return the MessageReceiver in a disconnected state so that it can be connected again using the doConnect() method. |
No |
doInitialise() |
Called when the Requester is being initialized after all properties have been set. Any required initialization can be done here. |
No |
doStart() |
Called when the Requester is started. Any transport specific implementation that is required when the requestor is started should be implemented here. |
No |
doStop() |
Called when the Requester is stopped. Any transport specific implementation that is required when the requestor is stopped should be implemented here. |
No |
doDispose() |
Called when the Requester is being disposed and should clean up any open resources. |
No |
Threads and Dispatcher Caching
Custom transports do not need to worry about dispatcher threading. Unless threading is turned off, the Dispatcher methods listed above execute in their own thread. This is managed by the AbstractMessageDispatcher
.
When a request is made for a dispatcher, it is looked up from a dispatcher cache on the AbstractConnector
. The cache is keyed by the endpoint being dispatched to. If a Dispatcher is not found, one is created using the MessageDispatcherFactory
and then stored in the cache for later.
Message Factories
Message factories translate messages from the underlying transport format into a MuleMessage. Almost all messaging protocols have the notion of message payload and header properties. Message factories extract that payload and optionally copy all properties of the transport message into the MuleMessage. A MuleMessage created by a message factory can be queried for properties of the underlying transport message. For example:
//JMS message ID
String id = (String)message.getProperty("JMSMssageID");
//HTTP content length
int contentLength = message.getIntProperty("Content-Length");
Note that the property names use the same name that is used by the underlying transport; Content-Length
is a standard HTTP header name, and JMSMessageID
is the equivalent bean property name on the javax.jms.Message
interface.
A message factory should extend org.mule.transport.AbstractMuleMessageFactory, which implements much of the mundane methods needed by the org.mule.api.transport.MuleMessageFactory interface.
Methods to Implement
Method Name | Description | Required |
---|---|---|
extractPayload() |
Returns the message payload 'as is'. |
Yes |
addProperties() |
Copies all properties of the transport message into the DefaultMuleMessage instance that is passed as parameter. |
No |
addAttachments() |
Copies all attachments of the transport message into the DefaultMuleMessage instance that is passed as parameter |
No |
Service Descriptors
Each transport has a service descriptor that describes what classes are used to construct the transport. For complete information, see Transport Service Descriptors.
Package Structure
All Mule transports have a similar package structure. They follow the convention of:
org.mule.transport.<protocol>
Where protocol is the protocol identifier of the transport such as 'tcp' or 'soap'. Any transformers and filters for the transport are stored in either a 'transformers' or 'filters' package under the main package. Note that if a transport has more than one implementation for a given protocol, such as the Axis and CXF implementations of the SOAP protocol, the package name should be the protocol, such as soap
instead of axis
or cxf
.
Internationalization
Any exceptions messages used in your transport implementation should be stored in a resource bundle so that they can be internationalized. The message bundle is a standard Java properties file and must be located at:
META-INF/services/org/mule/i18n/<protocol>-messages.properties