Mule : Architecture Guide
This page last changed on Jul 26, 2006 by alan.cassar.
Many of Mule's features are documented here using the same terms as the popular Enterprise Integration Patterns book. The book describes the problems Mule is aiming to solve and documents many of the patterns used in th Mule framework. EIP documentation in this guide and other Mule guides will be in the form of -
IntroductionThis document aims to give insight to the architecture of Mule. Mule's ultimate goal is to provide a unified method of interacting with data from disparate sources without encumbering the developer with the details about how the data is sent or received or the protocols involved. The result is an ESB (Enterprise Service Bus) server that is highly-scalable, light-weight, fast and simple to pick up and start using. The architecture of Mule was designed with the ESB model in mind and its primary focus is to simply and speed up the process of developing distributed service networks. However, as the name suggests the ESB model is usually associated with large integration projects where there is an array of disparate enterprise applications. Mule makes Enterprise level service architectures possible for smaller projects where resources, development cost and TTM need to be kept to a minimum. Architecture OverviewThe primary goal is enable integration between applications using standards, open protocol and well-defined patterns. To achieve this goal, Mule defines a set of components that can be used to perform most of the hard work necessary to get disparate applications and services talking together.
ApplicationThe Application can be of any type, such as a webapp, back office system, application server or another Mule instance. ChannelCan be any method of communicating data between two points. Channels are used in Mule to wire UMO components together as well as to wire different Mule nodes together across a local network or the internet.
Message ReceiverA Message Receiver is used to read or receive data from the Application. In Mule a Receiver is just one element of a Transport provider and Mule provides many transports such as jms, soap, http, tcp, xmpp, smtp, file, etc. Much of the 'magic' in Mule is it's ability to communicate to disparate systems without your business logic (UMO components) ever needing to know about system location, format of the data, the delivery mechanism or protocols involved. Likewise when the UMO component has done its work it need not worry about where the data is going next or in what format the data is expected.
Inbound RouterInbound routers can be used to control how and which events are received by a component subscribing on a channel. Inbound routers can be used to filter, split aggregate and resequence events before they are received by the UMO component. There is more information on Message Routers further on in this guide. ConnectorThe connector understands how to send and receive data over a particular channel. A Message receiver is coupled with a connector to register interest in data coming from a source understood by the connector. TransformersTransformers are used to transform message or event payloads to and from different types. Mule does not define a standard message format (though Mule may support standard business process definition message types in future) So the transformation provided out of the box is Type transformation such as Jms Message to Object and standard Xml transformers. Data transformation is very subjective to the application and Mule provides a simple yet powerful transformation framework. EndpointAn endpoint is really a configuration wrapper that binds a connector, endpoint URI, transformers, filters and transactional information to provide a Channel Adapter. The proivder also stores transactional information for the provider instance. See the Mule Endpointschapter that goes into more detail about endpoints.
Outbound RouterOutbound routers are used to publish messages/events to differnet providers depending on different aspects of events or other rules defined in configuration. There is more information on Message Routers further on in this guide. Mule ManagerCore to Mule is the MuleManager. It manages the configuration of all core services for the Model and the components it manages. Below is an overview of the core components that comprise a Mule manager. Cannot resolve external resource into attachment. The ModelThe model encapsulates and manages the runtime behaviour of a Mule Server instance. It is responsible for maintaining the UMOs instances and their configuration. The Modle has 3 control mechnisms to determine how Mule interacts with it's UMO components - Entry Point ResolverDefined by the org.mule.umo.model.UMOEntryPointResolver interface, an entry point resolver is used to determine what method to invoke on an UMO component when event is received for it's consumption. There is a DynamicEntryPointResolver that is used if no other is configured on the model (see the Configuration Guide for more information). The DynamicEntryPointResolver provides entry point resolution for common usage, the steps it takes are -
Of course there are many scenarios where the DynamicEntryPointResolver is suitable. For example, if you are migrating from another framework you may want to restrict (such as org.mule.model.CallableEntryPointResolver that only accepts components that extend org.mule.umo.lifecycle.Callable ) or change the way the entry point is resolved. To implement a custom Entry Point Resolver the org.mule.model.EntryPointResolver must be implemented. Lifecycle AdapterDefined by the org.mule.umo.lifecycle.UMOLifecycleAdapter interface, the lifecycle adapter is responsible for mapping the mule component lifecycle to the underlying component. The DefaultLifecycleAdapter simply delegates lifecycle events to the component where the component implements zero or more UMO lifecycle interfaces. Lifecycle adapters are configured using an implementation of org.mule.umo.lifecycle.UMOLifecycleAdapterFactory. The factory is declared in the configuration of the model. A default is provided DefaultLifecycleAdapterFactory. Component Pool FactoryThe Component Pool factory property of the model defines the fctory to use when creating a component pool for a given UMO Component. The pool is used to pool UMOComponents and this extension point allows developers to use their own pooling mechanism if needed. Mule ships with two Pooling implementations -
Developers wishing to roll thier own pooling implementation need to implement org.mule.umo.model.UMOPoolFactory, org.mule.until.ObjectPool and org.mule.util.ObjectFactory. Transport ProvidersA transport provider is a Mule plug-in that enables Mule components to send and receive information over a particular protocol, repository messaging or other technology. The following describes the architecture of a transport provider. Cannot resolve external resource into attachment. ConnectorsThe connector provides the implementation for connecting to the external system. The connector is resposible for sending data to the external receiver and managing listener on the connector to receive data from the external system. For example, the Http connector creates a Http Connection and sends the payload over the connection and will return a UMOEvent with the return status (if running synchronously). Receivers for the Http connector are simply objects that get notified when something is received on the Http server port. A connector has two objects responsible sending and receiving events -
Connectors are responsible for managing sessions for the underlying technology, i.e. the JmsConnector provides a Jms Session for the Connectors' Message Receiver and one also for the Message Dispatcher to publish or send events over Jms. Endpoints AddresssAn endpoint address defines any form of destination or source of data and is always expressed as URI. Examples of endpoints could be -
Endpoint addresses are always expressed as valid URIs with the protocol of the connector then resource specific information. Mule Transport providers have plugable endpooint builders that allow developers to customise the way an endpoint is read by Mule. Endpoint ResolutionThis section describes the process Mule uses to resolve an endpointUri. For this example we will use the following Uri 'jms://topic:myTopic?durable=true'. This a jms Uri to a durable topic.
Message ReceiversMessage receivers or message listeners are responsible for receiving data from the external system. It is the responsibility of the connector to manage the registering and unregistering of receivers. The complexity of the message receiver will vary depending on the external system being used. For example, the message receiver for the JMS provider simply implements the javax.jms.MessageListener and the JMS connector registers the listener with its JMS connection. However, the Http message receiver implements an Http server that listens on a specified port for incoming requests. Message AdaptersMessage adaptors are required to read disparate data objects in the format they are received from the external application in a common way. The UMOMessageAdapter interface specifies a small set of methods needed to read the payload and properties of any java object. Message Adaptors are specific to a connector; when a connector is written a Message Adapter is also needed to read or translate data from a particular data type used by the connector into either a byte array or string. TransactionsTransactions are managed at the Provider; Transactions are begun or commited when a Message Receiver receives a message or a Message Dispatcher sends the message. Central to Mule's transaction Management is the TransactionCoordinator, which is responsible maintaining transaction state. For more information about transactions in Mule see the Transaction Management chapter of the User Guide. In order for Mule to treat all transactions the same there is a small api that transacted enabled providers must define -
Container ContextsThe component resolver is the gateway to using an external container framework to manage the instanciation and configuration of UMO components or their dependent objects. Mule doesn't provide it's own component container as there is a wealth of very good IoC containers that are tried and tested. Instead Mule provides some default Component Resolvers for popular containers -
To use a component from an external container as your UMO component simply configure the desired ComponentResolver on the model and when defining the mule-descriptor in the config file , set the implementation attibute to the component key (or class in the case of picocontainer) in the container. If the configuration does not specify a Component Resolver the MuleComponentResolver is used. This implementation expects a class name to instanciate instead of a component key to resolve the component with. It behaves in the same way as real implementations except it does not support looking up components from a container. To implement a custom ComponentResolver two interfaces need to be implemented -
UMO ComponentsCentral to the architecture of Mule are single autonomous components that can interact without being bounded by the source, transport or delivery of data. These components are called UMO Components and can be arranged to work with one another in various ways. These components can be configured to accept data a number of different sources and can send data back to these sources. Cannot resolve external resource into attachment. Component LifecycleThe lifecycle adapter is used by the Model to fire lifecycle methods on your object (if any). Custom lifecycles can be introduced on a per-model basis allowing different models to management the lifecycle of their components in different ways. Mule defines a default lifecycle for the components it manages. The components can participate in none, any or all of these lifecycle events by implementing the required lifecycle interfaces. The lifecycle is as follows - Cannot resolve external resource into attachment.
These lifecycle interfaces also apply to Connectors, Agents and Interceptors. For example the LifecycleInterceptor implements the Startable, Stoppable and Disposable interfaces to manage it's lifecycle. TransformersTransformers are used to convert source data to an object type required by the UMO Component. Transformers can be configured on Endpoints that receive data to ensure that the expected object type is always received by an UMO Component. Transformers configured on an Outbound endpoint ensure that the endpoint receives the the correct object type before dispating the event. Multiple transformers can be chained together to allow for finer grained transformer implementations that are easier to reuse. To configure an Endpoint to use more than one transformer, just specify a space separated list of transformers in the config file (see the configuration guide) or programmatically chain the transformers together using the setTransformer() method on the transformer.
Entrypoint ResolversAlso (not shown on this digram) is the EntryPointResolver. This is used by the Model when the UMOComponent is registered to find the method to call on your object when an event is received for it. If a method is not found an exception will be thrown. The details of the EntryPoint resolver can be seen here. EventsMule is an event-based architecture, that is, actions within a Mule network are triggered by either events occurring in Mule or in external systems. Events always contain some sort of data, the payload, which will be used and/or manipulated by one or more components and a set of properties that are associated to the processing of the event. These properties are arbitrary and can be set at any time from when the event is created. The data in the event can be accessed in its original state or in its transformed state. The event will use the transformer associated with the Endpoint that received the event to transform its payload into a format that the receiving component understands. For more information about the event lifecycle see the Message Flow section below. Event ProcessingMule can send and receive events using 3 processing models -
You can control the synchronicity of event processing by setting the synchronous property on the endpoint (or programmatically on the event). synchronicity of the call can be proporgated accross the network where that transports being used support a reply channel. For example, a synchronous jms request will establish a temporary reply queue when a request is made and will wait for a response on that queue. The same applies to soket based transports. Asynchronous Event ProcessingAsynchronous event processing occurs when the inbound endpoint synchronous flag is set to false. Asynchronous inbound and outboundCannot resolve external resource into attachment. In this scenario the message is dispached to a queue and is consumed by a worker thread in a pool that actually does the execution work of you UMOComponent. The outbound endpoint is also asynchronous the resulting message will be dispached by a dispatcher thread. Asynchronous inbound, synchronous outboundCannot resolve external resource into attachment. In this scenario the message is dispached to a queue and is consumed by a worker thread in a pool that actually does the execution work of you UMOComponent. The outbound endpoint is synchronous so the dispatch happens in the same thread as component execution. This scenario is used by outbound transactions so that all dispatches from the component occur in the same thread. This behaviour is handled automatically by Mule. Synchronous ProcessingSynchronous inbound onlyCannot resolve external resource into attachment. An event is received and processed by your UMOComponent in the same thread and any result is returned from your UMO compoennt will be passed back to the receiver where if there is a response channel, i.e Socket outputstream a result will be sent. Synchronous inbound and outboundCannot resolve external resource into attachment. An event is received and processed in the same thread. The outbound dispatch also happens in the receiver thread. Here if the outbound endpoint transport being used supports a reply channel such as sockets or Jms a response from the dispatch will be intercepted (or the wait will timeout) and that response is passed back to the receiver where if there is a response channel, i.e Socket outputstream a result will be sent. Synchronous inbound and outbound with transactionCannot resolve external resource into attachment. Transactions can only (currently) be managed over synchronous endpoints. Thus if an endpoint has been configured for transactions it will automatically be synchronous. When dispatching and a transaction is in progress the dispatch will also happen in the current thread. Message RoutersMessage routers are used to control how events are sent and received by components in the system. Mule defines Inbound routers that apply to events as they are received and outbound routers that are invoked when an event is being dispatched.
Inbound RoutersInboun routers can be used to control and manipulate events received by a component. Typically, an inbound router can be used to filter incoming event, aggregate a set of incoming events or resequence events when they are received. You can chain inbound routers together, in tis scenario each router is matched before the event is dispatched to a mule component. Inbound routers are different to outbound routers in that the provider is already known so the purpose of the router is to control how messages are sent via the provider. You can specify a catch-all strategy which wil be invoked if any of the routers do not accept the current event. An Inbound Router can be configured on a mule-descriptor element in the mule-config.xml - <inbound-router> <catch-all-strategy className="org.mule.tck.testmodels.mule.TestCatchAllStrategy"/> <router className="org.mule.routing.inbound.SelectiveConsumer"> <filter expectedType="java.lang.String" className="org.mule.routing.filters.PayloadTypeFilter"/> </router> <router className="org.mule.routing.inbound.Aggregator"> </router> </inbound-router> If there are no special processing requirements for messages received by a component there is no need to configure an inbound router. Outbound RoutersOutbound routers are used to control which providers are used to send events once an UMO component has finished procesing. Message Routers are configured on UMOCompnent and allow the developer to define multiple routing constraints for any given Event. You can specify a catch-all strategy which wil be invoked if none of the routes accept the current event. An example of an Outbound Message Router is given below - <outbound-router> <catch-all-strategy className="org.mulerouting.ForwardingCatchAllStrategy" provider="catchAll"/> <router providers="TestApple-Out" className="org.mule.routing.outbound.FilteringOutboundRouter"> <filter expectedType="java.lang.String" className="org.mule.routing.filters.PayloadTypeFilter"/> </router> <router providers="waterMelonProvider" className="org.mule.routing.outbound.FilteringOutboundRouter"> <filter className="org.mule.routing.filters.logic.AndFilter"> <left-filter pattern="the quick brown (.*)" className="org.mule.routing.filters.RegExFilter"/> <right-filter pattern="(.*) brown (.*)" className="org.mule.routing.filters.RegExFilter"/> </filter> </router> </outbound-router> Catch All StrategyThe catch all strategy receives the event if none of the router accept the event. Custom strategies must implement org.mule.umo.routing.UMORoutingCatchAllStrategy which defines a method - public void catchMessage(UMOMessage message, UMOSession session, boolean synchronous) throws RoutingException; Note that this a void method, so that no return event can be passed back to the calling code. This is important when running synchonously as the synchronous chain of events is broken. It is considered an error condition when a catch-all strategy is invoked. RoutersIn the example, there are 2 routers defined, with the outbound-router element as the parent. This means that each router will be checked in order to see if the current event can be routed. It is not recommended to use transacted providers in router configurations. As routing of the event is determined at run-time, there are situations where an event within a transaction is routed to a non-transacted provider, thus ophaning the current transaction causing 'surprise' transaction timeouts. For transacted providers it is recommended that you configure one inbound and one outbound transacted provider for the event path. In situations where only one outbound provider is configured for an UMO component it is not necessary to define a Message router. For more information about using the routers that ship with Mule, see the Message Routers chapter of the User Guide. InterceptorsMule interceptors are useful for attaching common behaviour to multiple UMOs. The Interceptor or Command pattern is often referred to as practical AOP (Aspect Oriented Programming) as it allows the developer to intercept processing on an object and potentially alter the processing and outcome. Interceptors a very useful for attaching profiling, permission and security checks, etc, to a component in Mule. Mule has two types of interceptors -
The following shows a typical interceptor stack and the event flow. Cannot resolve external resource into attachment. Exception ManagementException strategies can be defined on UMOComponents, but sometimes it sufficient to have all components managed by the the model use the same exception strategy. By defining the Exception strategy on the model, it is not necesaary to define individual exception strategies (by default if no exception strategy is defined on a UMO Component the org.mule.impl.DefaultExceptionStrategy will be used). It is common to define your own exception strategy, to do so you must implement org.mule.umo.UMOExceptionStrategy. Mule Object HeirarchyThe elements of mule can be grouped into two types of objects;
The hierarchy of associations of these objects can be represented as a tree shown below. The objects are described in terms of the component name in the mule-config.xml and the class that represents the object. [1] mule-configuration (org.mule.umo.UMOManager) +- [?] mule-environment-properties (org.mule.MuleConfiguration) +- [*] environment-properties (org.mule.umo.UMOManager.setProperty(...)) +- [?] security-manager (org.mule.umo.security.UMOSecurityManager) +- [?] transaction-manager (javax.transaction.TransactionManager) +- [*] agent (org.mule.umo.UMOAgent) +- [+] connector (org.mule.umo.provider.UMOConnector) +- [*] endpoint-identifiers (java.lang.String) +- [*] transformer (org.mule.umo.UMOTransformer) +- [*] endpoints (org.mule.umo.endpoint.UMOEndpoint) +- [?] container-context (org.mule.umo.UMOContainerContext) +- [*] interceptor-stacks (org.mule.umo.UMOInterceptor) +- [1] model (org.mule.umo.model.UMOModel) +- [?] entry-point-resolver (org.mule.umo.model.UMOEntryPointResolver) +- [?] component-resolver (org.mule.umo.model.UMOComponent) +- [?] component-lifecycle-adapter-factory (org.mule.umo.model.LifecycleAdaperFactory) +- [?] component-pool-factory (org.muleumo.model.UMOPoolFactory) +- [?] exception-strategy (org.mule.umo.UMOExceptionStrategy) +- [+] mule-descriptor (org.mule.umo.UMODescriptor) +- [?] inbound-router (org.mule.umo.UMOInboundMessageRouter) +- [*] router (org.mule.umo.UMOInboundRouter) +- [*] properties (java.util.Map/Bean properties) +- [*] endpoint / global-endpoint (org.mule.umo.endpoint.UMOEndpoint) +- [?] filter (org.mule.umo.UMOFilter) +- [?] security-filter (org.mule.umo.security.UMOEndpointSecurityFilter) +- [?] transaction (org.mule.umo.transaction.UMOTransactionConfig) +- [?] properties (java.util.Map/Bean properties) +- [?] outbound-router (org.mule.umo.UMOOutboundMessageRouter) +- [*] router (org.mule.umo.UMOOutboundRouter) +- [*] properties (java.util.Map/Bean properties) +- [*] endpoint /global-endpoint (org.mule.umo.endpoint.UMOEndpoint) +- [?] filter (org.mule.umo.UMOFilter) +- [?] security-filter (org.mule.umo.security.UMOEndpointSecurityFilter) +- [?] properties (java.util.Map/Bean properties) +- [*] response-router (org.mule.umo.UMOResponseMessageRouter) +- [*] router (org.mule.umo.UMOInboundRouter) +- [*] properties (java.util.Map/Bean properties) +- [*] endpoint / global-endpoint (org.mule.umo.endpoint.UMOEndpoint) +- [?] properties (java.util.Map/Bean properties) +- [*] interceptor (org.mule.umo.UMOInterceptor) +- [1] exception-strategy (org.mule.umo.UMOExceptionStrategy) +- [*] properties (java.util.Map/Bean properties) |
![]() |
Document generated by Confluence on Oct 03, 2006 09:23 |