How to Extend Mule 4 Runtime using SDK


Mule 4 is packed with enhancements and new features. It comes with a new Mule SDK to extend the Mule Runtime for creating custom Connectors and Modules. Even though the goal of SDK is similar to DevKit used in Mule 3, it differs in how custom Connectors and Modules are created using new Mule SDK. In this post, we will see how to create a custom Module using Mule SDK and use it in our project.

1. What is Mule 4 SDK?

Mule 4 comes with a whole new Mule SDK, which is a tool to extend and enhance the functionalities of Mule Runtime. It allows creating custom Modules and Connectors. These Modules and Connectors then can be used in Mule Applications.

2. Prepare for Customization

2.1 Prerequisites

You must have these components installed -

  • Java Development Kit 8 (JDK 8)

  • Apache Maven 3.3.9 or higher

Mule Target Versions:

  • Mule ESB 4

  • Anypoint Studio 7

The Maven Archetype to create custom Mule Modules is available on Maven Central.

3. Creating our First Module

New Module can be created by using Maven Plugin or Maven Archetype.

3.1 Using Maven Plugin

Maven Plugin mule-extensions-archetype-maven-plugin has all the steps with help descriptions. Run below on command line -

mvn org.mule.extensions:mule-extensions-archetype-maven-plugin:generate

It asks few question before it generates the module project. Here is a sample of that -

* Enter the name of the extension (empty for default):
SayHi
* Enter the extension's groupId (empty for default):
com.javastreets
* Enter the extension's artifactId (empty for default):
mule-modules-sayhi
* Enter the extension's version (empty for default):
0.0.1-SNAPSHOT
* Enter the extension's main package (empty for default):
com.javastreets.mule.extension.sayhi

3.2 Using Maven Archetype

Run below command on console to use Maven Archetype to generate the module.

Prefer using plugin (3.1) approach instead of direct archetype.
mvn archetype:generate
  -DarchetypeCatalog=http://repository.mulesoft.org/releases/
  -DarchetypeGroupId=org.mule.extensions
  -DarchetypeArtifactId=mule-extensions-archetype
  -DarchetypeVersion=1.1.0
  -DgroupId=com.javastreets
  -DartifactId=mule-modules-sayhi
  -Dversion=0.0.1-SNAPSHOT
  -Dpackage=com.javastreets.mule.extension.sayhi
  -DextensionName=SayHi (1) (2)
1 Extension name is not camel cased for generated class names. See MULE-14600.
2 extensionNameNoSpaces is computed based on extensionName. It is not required to specify but at the time of writing this post, this command was resulting in an unexpected warning message related to extensionNameNoSpaces. You can ignore that for now. I have filed a Jira issue MULE-14599 for this.

3.3 Understanding the POM

The generated POM file will look like below -

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javastreets</groupId>              (1)
    <artifactId>mule-modules-sayhi</artifactId>     (2)
    <version>0.0.1-SNAPSHOT</version>               (3)
    <packaging>mule-extension</packaging>           (4)
    <name>Mule-modules-sayhi Extension</name>

    <parent>
        <groupId>org.mule.extensions</groupId>
        <artifactId>mule-modules-parent</artifactId>
        <version>1.1.6</version>                    (5)
    </parent>

</project>
1 Extension’s Maven group Id
2 Extension’s Maven artifact Id
3 Extension’s Maven artifact version
4 Extension’s packaging type
5 SDK Extension API Version

3.4 Choosing SDK Extension API Version

Mule modules parent versions are usually mapped with Mule 4 minor versions.

It is important to choose the correct SDK Extensions API version since it will define the minimum version of Mule Runtime supported by your extension.
Table 1. Mule SDK and Runtime Version mapping
SDK Parent Version Mule Runtime Version

1.1

4.1

1.2

4.2

1.3

4.3

1.4

4.4

…​1.n

…​4.n

For most of the use cases, you should use 1.1.* that introduced PollingSource feature.

3.5 Troubleshooting

The generated project may fail to compile due to following error -

Unresolveable build extension: Plugin org.mule.runtime.plugins:mule-extensions-maven-plugin:1.1.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.mule.runtime.plugins:mule-extensions-maven-plugin:jar:1.1.6 @
[ERROR] Unknown packaging: mule-extension @ line 7, column 16

Resolution: This happens when maven is not configured to use mulesoft’s plugin repository. To resolve this issue, add following pluginRepository entry to generated pom.xml -

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- other pom.xml declarations stay here -->

    <pluginRepositories>
        <pluginRepository>
            <id>mulesoft-releases</id>
            <name>mulesoft release repository</name>
            <layout>default</layout>
            <url>https://repository.mulesoft.org/releases/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

4. Understanding Structure

mule-modules-sayhi
├── README.md
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── javastreets
    │   │           └── mule
    │   │               └── extension
    │   │                   └── sayhi
    │   │                       └── internal
    │   │                           ├── SayHiConfiguration.java (1)
    │   │                           ├── SayHiConnection.java (2)
    │   │                           ├── SayHiConnectionProvider.java (3)
    │   │                           ├── SayHiExtension.java (4)
    │   │                           └── SayHiOperations.java (5)
    │   └── resources
    └── test
        ├── java
        │   └── com
        │       └── javastreets
        │           └── mule
        │               └── extension
        │                   └── sayhi
        │                       └── SayHiOperationsTestCase.java (6)
        └── resources
            └── test-mule-config.xml (7)

4.1 Extension Class

SayHiExtension is the Main entry point class and is marked with @Extension annotation. It defines the Connector attributes such as its name, XML prefix and namespace, category and other Connector attributes.

@Xml(prefix = "sayhi")
@Extension(name = "SayHi")
@Configurations(SayHiConfiguration.class)
public class SayHiExtension {

}

It is possible to have more than one configuration for an extension. They can be specified as an array value - @Configurations({SayHiConfiguration.class, SayHelloConfiguration.class}).

4.2 Configuration Class

SayHiConfiguration is a common configuration provider for our new module. Any common attributes, parameters can be included in this class. This class is added to Extension class using @Configurations annotation.

It is possible to have more than one Configuration for an Extension. In that case, there can be ONLY one Configuration with default name 'config'. All other configurations must a unique name.
Listing 4.2.A Configuration with default Name
@Operations(SayHiOperations.class) (1)
@ConnectionProviders(SayHiConnectionProvider.class) (2)
public class SayHiConfiguration {

  @Parameter
  private String configId;

  public String getConfigId(){
    return configId;
  }
}
Listing 4.2.B Configuration with explicit name
@Operations(SayHelloOperations.class) (1)
@ConnectionProviders(SayHiConnectionProvider.class) (2)
@Configuration(name="config-hello")
public class SayHelloConfiguration {

  @Parameter
  private String configId;

  public String getConfigId(){
    return configId;
  }
}
1 Configuration class defines the operations available with it.
2 If there is any connection provider for this configuration, then it should be added here.

4.3 Connection Provider

This is implemented in two classes SayHiConnection and SayHiConnectionProvider.

SayHiConnection is a Connection Object Instance managed by Connection Provider. This class should have any methods such as invalidate(), and attributes that makes sense for an instance of a Connection, once established.

Listing 4.3.A Connection Instance Object
public final class SayHiConnection {

  private final String id;

  public SayHiConnection(String id) {
    this.id = id;
  }

  public String getId() {
    return id;
  }

  public void invalidate() {
    // do something to invalidate this connection!
  }
}

SayHiConnectionProvider implements PoolingConnectionProvider interface to provide methods such as connect(), disconnect(), and validate() to manage the Connection instance SayHiConnection.

Module can support multiple Connection Providers. They are added on Configuration class using @ConnectionProviders({SayHiConnectionProvider.class,SayHelloConnectionProvider.class}).

4.4 Operations

SayHiOperations is a regular java class, when added on Configurations class using @Operations, becomes the operations provider class. Every public method in this class becomes the operation supported by this module.

Modules may have some operations that do not depend on any Configurations. These are Global Operations.

Below is an example of a public method on SayHiOpererations class -

@MediaType(value = ANY, strict = false)
public String sayHi(String person) {
  return buildHelloMessage(person);
}

Operations can have three types of outputs -

  • Void: As the name indicates, this operation will not return anything. This operation will not modify the message and next component will receive the same message.

  • Any Object: When operation returns something, then it becomes the payload. For example, public String sayHi(String person) operation returns String which will be the payload to next component.

Message after this operation will not have any attributes.
  • Result Object: Result is a special object that can be returned by an operation. This helps to set any attributes, properties, and payload of the message returned by an operation.

5. Test, Build, and Install

When the module is generated, it also includes a test mule-config.xml file. It implements test flows that use Operations from this module.

Here is how the test-mule-config.xml looks like -

<mule xmlns="http://www.mulesoft.org/schema/mule/core"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:sayhi="http://www.mulesoft.org/schema/mule/sayhi"
      xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
          http://www.mulesoft.org/schema/mule/sayhi http://www.mulesoft.org/schema/mule/sayhi/current/mule-sayhi.xsd">

    <sayhi:config name="config" configId="configId"> (1)
        <sayhi:connection requiredParameter="aValue" /> (3)
    </sayhi:config>

    <flow name="sayHiFlow">
        <sayhi:say-hi person="Manik Magar"/> (6)
    </flow>

	<flow name="retrieveInfoFlow">
        <sayhi:retrieve-info config-ref="config"/> (6)
    </flow>

</mule>

To Run test cases, build and install this new module into local maven repository, just run below maven command -

mvn clean install

Once successfully installed, maven repository will have a json and a jar for our new module.

├── mule-modules-sayhi-0.0.1-SNAPSHOT-extension-model-4.0.0.json
├── mule-modules-sayhi-0.0.1-SNAPSHOT-mule-plugin.jar
└── mule-modules-sayhi-0.0.1-SNAPSHOT.pom

6. Use and Share Module in Project

Now, the new module is built and installed in the local repository. To use this module in Mule 4 project, add below dependency to project pom -

<dependency>
  <groupId>com.javastreets</groupId>
  <artifactId>mule-modules-sayhi</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <classifier>mule-plugin</classifier>
</dependency>
Observe the presence of tag <classifier>mule-plugin</classifier>. This must be specified for Anypoint Studio 7 to recognize new module.

Once the dependency is added to project pom, Module will appear in the Mule Palette.

Adding Mule Custom Module to Anypoint Studio

Then we can add module operations to mule config -

<sayhi:config name="SayHi_Config" doc:name="SayHi Config" configId="MyConfig">
	<sayhi:connection requiredParameter="This is required" />
</sayhi:config>

<flow name="flow-test-zip">
	<sayhi:say-hi doc:name="Say hi" person="Manik Magar"/>
	<sayhi:retrieve-info doc:name="Retrieve info" config-ref="SayHi_Config"/>
</flow>

To share this module with others, we just need to push this to central maven repository. Then it can be used by just adding a dependency in other projects, without requiring any plugin installations.

7. Differences with DevKit

Mule 3 used Developer Kit (DevKit) to create custom Connectors. DevKit also generated lots of code when creating custom connectors, including the plugin for Anypoint Studio. To use Mule 3 Custom Connector in Studio, plugin had to be installed in the studio.

Mule SDK is the only option to extend Mule 4 Runtime and DevKit is not available in Mule 4.

An Essential difference between Mule SDK and DevKit is, Mule SDK is not a code generator. It is rather a plain extension mechanism.

Mule SDK is more powerful than DevKit. Compared to DevKit, Mule SDK also adds support for features like Transactions, Request-Response message sources, Dynamic configurations, Routers, Non Blocking operations, Classloading isolation, and much more.

8. Conclusion

Mule 4 Runtime is not only powerful but also easy to extend. In this post, we saw how easily we can extend the Runtime and create custom modules. These modules are not only clean but also easy to use and share.

Mule 4 has definitely evolved, simplified and became more powerful.

9. References and further reading

on twitter to get updates on new posts.

Stay updated!

On this blog, I post articles about different technologies like Java, MuleSoft, and much more.

You can get updates for new Posts in your email by subscribing to JavaStreets feed here -


Lives on Java Planet, Walks on Java Streets, Read/Writes in Java, JCP member, Jakarta EE enthusiast, MuleSoft Integration Architect, MuleSoft Community Ambassador, Open Source Contributor and Supporter, also writes at Unit Testers, A Family man!