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. |
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. |
@Operations(SayHiOperations.class) (1)
@ConnectionProviders(SayHiConnectionProvider.class) (2)
public class SayHiConfiguration {
@Parameter
private String configId;
public String getConfigId(){
return configId;
}
}
@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.
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 returnsString
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.
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
-
Getting Started with Mule SDK
-
mule-modules-sayhi on Github
-
See this comment thread for some troubleshooting tips, Thanks to Serhy.
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!