Nav
You are viewing an older version of this section. Click here to navigate to the latest version.

Creating Transports

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 (connectors) in Anypoint Exchange. If you need to send messages on a protocol other than those provided, you can create a new transport.

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:

  1. Inbound-only: Components can only subscribe to events. They cannot dispatch events.

  2. Outbound-only: Components can only dispatch events. They cannot subscribe to events.

  3. 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.

creating-transports-providers

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 MuleEvent.transformMessage() to transform the message.

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.

org.mule.api.transport.MessageDispatcherFactory

This is a factory class used to create MessageDispatcher instances. An implementation of this class is needed if the transport supports outbound communication.

org.mule.api.transport.MuleMessageFactory

The message factory is used to provide a consistent way of creating MuleMessage instances from the transport’s message format.

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.

Methods to Implement

Method name Description Required

poll()

Is executed repeatedly at a configured frequency. This method should execute the logic necessary to read the data and return it. The data returned is the payload of the new message. Returning null causes no event to be fired.

Yes

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 getMessages(). Each object processed is managed in its own transaction.

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 sendEvent method is called when the endpoint is running synchronously, and any response returned ultimately is passed back to the caller. This method is executed in the same thread as the request thread.

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 FileMessageDispatcher checks that the directories it uses are available and readable. The MessageDispatcher should remain in a 'stopped' state even after the doConnect() method is called.

Yes

doDisconnect()

Disconnects and tidies up any resources that were allocated by the doConnect() method. This method should return the MessageDispatcher into a disconnected state so that it can be connected again using the doConnect() method

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:


          
       
1
2
3
4
5
//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.

Coding Standards

Following are coding standards to use when creating transports.

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