Mule Application Architecture
This page covers the structural features you can build into Mule applications.
About Mule Applications
At the simplest level, Mule applications accept one message at a time, processing received messages in the order they are received. Such processing can lead to a variety of results. Sometimes, the Mule application returns an altered or replacement message to the source of the original message. Additionally or instead, the application can send the message in its original or altered form to one or more third parties. In still other cases, Mule can decline to process the message if it has not met specific criteria.
Sophisticated Mule applications go far beyond this sort of linear message processing. Advanced mechanisms can process different messages in very different ways. Furthermore, you can construct applications that utilize:
- various queue-and-thread arrangements to maximize throughput
- transactionality or clustered nodes to maximize reliability
- object stores to ensure data persistence
These represent only a fraction of the features you can implement through Mule applications.
In the following sections, we'll discuss flow architecture using the concept of building blocks within Mule Studio. Building blocks correspond to XML elements in the XML configuration file, but for the purposes of modeling flows and explaining concepts, we'll use building blocks and Studio graphical representations here.
Flow Building Blocks
Studio building blocks fall into several functional categories, some of which are processing blocks that comprise several building blocks themselves.
Not all building blocks can occupy all positions within a flow. Often, the position of a building block in relation to the rest of the flow (or in relation to the building blocks in its immediate vicinity) greatly influences the behavior of the building block and how it must be configured.
The following sub-sections detail the various types of building blocks (and processing blocks) that can populate a Mule Flow.
The first building block in most flows is a message source, which receives messages from one or more external sources, thus triggering a flow instance. Each time it receives another message, the message source triggers another flow instance.
Typically an Inbound Endpoint serves as a message source, although an Anypoint Connector can perform this role as well.
Sometimes the message source immediately places the incoming message into a queue. This allows the message source to close the receiver thread it used to accept the message, and immediately open another thread to accept another incoming message. The message just placed into the queue waits until it reaches the head of the queue and can be processed through the rest of the flow. Since the message is processed sequentially by two distinct threads (with an intervening wait inside the queue), start-to-finish transaction processing is not possible.
Sometimes, a message source can accept incoming messages from multiple transport channels. For instance, you can embed an HTTP endpoint and a Servlet endpoint into the same message source. Or you can create a message source to receive both IMAP and POP3 mail. Either embedded endpoint (i.e., transport channel) can trigger a flow instance as soon as it receives an incoming message.
Under certain conditions, flows do not need to be triggered by message sources. For instance, a Flow Reference Component can trigger a private, child flow. Similarly, the Async Scope can trigger a child flow that executes asynchronously, (i.e., in parallel with the parent flow).
Typically, message processors are pre-packaged units of functionality that process messages in various ways. Except for message sources, all the building blocks in a flow qualify as message processors. Message processors offer the following advantages:
- generally, they don’t have to be custom-coded
- multiple message processors can be combined into various structures that provide the exact functionality you need for your application
You can assemble message processors into application (i.e., flow) sequences in two distinct ways:
- by arranging icons on the Studio canvas
- by inserting XML code into the application configuration file
Message processors fall into a number of convenient categories, as the following table indicates:
They fall into two sub-categories (Inbound and Outbound), and provide a means for Mule applications to communicate with the outside world.
They enhance, in a wide variety of ways, the functionality of other message processors or functional groups of message processors known as Processing Blocks.
They allow you to enhance a flow by attaching functionality such as logging, display output, and even child flows. Alternatively, they facilitate Software as a Service (SaaS) integration by providing language-specific "shells" that make custom-coded business logic available to a Mule application.
They prepare a message to be processed through a Mule flow by enhancing or altering the message header or message payload.
Singly and in combination, they determine whether a message can proceed through an application flow.
They specify how messages get routed among the various Message Processors within a flow. They can also process messages (i.e., aggregate, split, or resequence) before routing them to other message processors.
They specify various procedures for handling exceptions under various circumstances.
They facilitate integration of Mule applications with Web-based, 3rd-party APIs, such as Salesforce and Mongo DB.
This special category currently contains just one member: the Custom Business Event building block, which you place between other building blocks to record Key Performance Indicator (KPI) information, which you monitor through the Mule Console.
After you have arranged the various building blocks in your flow into proper sequence, you may need to configure these message processors using one or both of the available options:
- selecting from drop-down lists of available options or completing text fields in the Studio graphical interface
- entering attribute values within the XML configuration code. (A nifty, predictive “auto-complete” feature eases this task greatly).
Message Processing Blocks
Mule provides several ways to combine multiple message processors into functional processing blocks.
For instance, the composite source scope allows you to embed into a single message source two or more inbound endpoints, each one listening to a different transport channel. Whenever one of these listeners receives an incoming message, it triggers a flow instance and starts the message through the message processing sequence.
Other building blocks known as scopes provide multiple ways to combine message processors into convenient functional groups that can:
- make your XML code much easier to read
- implement parallel processing
- create reusable sequences of building blocks
As previously mentioned, endpoints implement transport channels that facilitate the insertion or extraction of data from flows. Endpoints serve a diverse variety of roles, depending on how they are configured. For example, they can, as previously mentioned, serve as inbound or outbound conduits. They can implement one-way or request-response exchange patterns. And, in certain situations, you can embed other types of message processors, such as transformers or filters, into endpoints.
When placed at the start of a flow, either alone, or embedded with other endpoints in a composite source component, an endpoint is always referred to as an inbound endpoint, because it accepts messages from external sources and passes them to the rest of the flow, thereby triggering a new flow instance.
Not all flows require an inbound endpoint. For instance, a child flow can be triggered by a flow reference which sends data to the child flow without using an inbound endpoint.
Not all endpoints can serve as inbound endpoints. For instance, the SMTP endpoint and the Anypoint Service Registry endpoint can both serve only as an outbound endpoint.
At the most basic level, outbound endpoints pass data out of a flow. Often they occupy the final message processor position in a flow, so when they pass data out of the flow, the flow instance is considered complete.
However, an outbound endpoint can also appear in the middle of a flow, passing data to a database as the rest of the flow continues, for instance.
Not all endpoints can serve as outbound endpoints. For instance the POP3 and IMAP can only serve as inbound endpoints.
Outbound endpoints can also be configured for a request-response exchange pattern, as detailed in the following section.
When inbound endpoints such as HTTP or VM are configured for a request-response pattern, they effectively become hybrid inbound-outbound endpoints. Even if other outbound endpoints exist to conduct data out of the flow, the inbound endpoint configured for a request-response exchange pattern also conducts data out of the flow by returning a response to the original sender of the message.
When outbound endpoints are configured for request-response exchange patterns, they can exchange data with resources outside the flow or with a string of message processors entirely within the same Mule application, as depicted by the following schematic:
Not all endpoints can be configured for the request-response exchange pattern, and of those that can, request-response is the default exchange pattern for only some of them. To complicate matters further, certain cases exist (such as the JDBC Endpoint) where request-response is available, but only when the endpoint is configured as an outbound endpoint.
When none of the endpoints in a main flow is configured to the request-response exchange pattern, the flow follows a one-way exchange pattern in which it receives incoming messages, but is not expected to provide any response to the original sender. However, the flow may send data to other parties such as a log file, a database, an email server, or a Web-based API.
A processing strategy determines how Mule executes the sequence of message processors in your application. For example, when the message source is configured for the request-response exchange pattern, Mule sets the processing strategy to synchronous, which means that the entire flow gets executed on a single processing thread, thus ensuring that the entire sequence of message processors executes, and the client receives a response, as expected.
By contrast, when the flow is configured for a one-way, non-transactional exchange pattern (i.e., no response to the original message sender is required, and it isn’t necessary to verify that all steps in the flow have been completed), Mule sets the processing strategy to queued asynchronous, which has the potential to raise flow throughput. Under this processing strategy, the inbound endpoint places the incoming message into the queue as soon as it is received, then closes the receiver thread. When the message reaches the top of the queue, it resumes processing, but this time on a different thread. By implication, this sort of processing does not qualify as transactional end-to-end, because the transfer from one thread to the next means that the processing can not be rolled back if an exception is thrown.
For further details, see Flow Processing Strategies.
An exception strategy determines how Mule responds if and when an error occurs during the course of message processing. In the simplest case, the error is simply logged to a file.
You can configure a custom exception strategy to respond in a variety of ways to a variety of conditions. For example, if an exception is thrown after a message has been transformed, you can set Mule to commit the message as it existed after being transformed, but immediately before the error occurred, so that the message cannot inadvertently be processed twice.
Studio provides four pre-packaged error handling strategies to handle exceptions thrown at various points during the message processing sequence. For details, see Error Handling.
Mule flows are extremely flexible, so you can combine building blocks in many ways, often to achieve the same result. For many use cases, however, certain message processors tend to fall into loosely ordered patterns. For example, suppose you wanted to create an application that receives product catalog requests from a Web page then sends a PDF of the catalog back to the client who submitted the request. In addition, you want this flow to record the client’s customer information to a log file and record the transaction. Your flow might look something like this:
Note that you could embed the filter and the transformers inside the inbound endpoint, but placing them in the main flow sequence makes the sequence of events easier to “read” on the Studio Visual Editor canvas and in the XML-based application configuration file.
Because flows consist of sequences of Studio building blocks, you cannot place any building block in any position within a flow. Additionally, the proximity or absence of certain building blocks within a sequence can determine whether a given building block can be placed at a certain point within a flow. Finally, depending where it resides in a flow, a given building block, especially an endpoint, can expose an significantly different set of attributes for configuration.
If you choose to develop using the visual editor in Mule Studio, Studio keeps track of all these contingencies, and it will not let you place a building block icon where it is not allowed.
Although it is impossible to cover all the possible sequences of building blocks that can produce workable flows, a typical flow might utilize the following sequence:
- A message source consisting of one or more inbound endpoints triggers the flow each time it receives a message.
- A filter, which may be embedded in the message source or follow it in the main flow, may identify invalid messages and decline to pass them to the rest of the flow for processing.
- A transformer can convert the incoming message into a data format consumable by the other message processors in the flow. Like a filter, a transformer can be embedded within the message source or reside within the main flow.
- A message enricher can add certain vital information to a message. For instance, if a message arrives with an address attached, the message enricher might use the postal code to look up the associated telephone area code, then append this information to the message header for marketing purposes.
- After the message has been “prepared” for processing, it is generally sent to some pre-packed or custom business logic (usually called a component) so that it can be processed in a manner appropriate for its particular content. Sometimes, external databases or APIs such as Salesforce are leveraged through building blocks known as anypoint connectors.
- The final stages of a flow can vary considerably; some or all of the following can occur:
- A response is returned to the original sender of the message.
- The results of the business processing are logged to a database or sent to some other third party.
Throughout the flow, you can do the following:
- send messages to queues (even more than one type on the same flow)
- specify threading models
- call child flows of various types