How to Create a Custom Connector in New Mule SDK 4.1.1
In this article, I'd like to walk you through how to develop your own connector using Mule SDK.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
MuleSoft's Anypoint Connectors helps to connect third-party APIs and service through the Mule flow. You can use the connector to send or receive a message from Mule flow to one or more external services over protocol or API. Mule flow designing is graphical, so you don't need to write a single line of code to connect external services when you are using Anypoint connectors. Today, MuleSoft has a large collection of different connectors to connect and integrate diverse systems including Salesforce, Database, different Google and AWS services, and many more.
You can develop your own connector using new Mule SDK platform, which is the replacement of earlier Mule devkit tool. In this article, I'd like to walk you through how to develop your own connector using Mule SDK.
Prerequisites
- Java JDK Version 8.x
- Anypoint Studio 7.x
- Apache Maven 3.3.9 or higher
Steps to Create a Connector
- Go to the directory where you want to create connector (studio-workspace) and execute a command to create project structure with sample test cases:
$ mvn org.mule.extensions:mule-extensions-archetype-maven-plugin:generate
- Complete the configuration through the console by answering a couple of questions:
- Enter the name of the extension (empty for default):
- Enter the extension's groupId (empty for default):
- Enter the extension's artifactId (empty for default):
- Enter the extension's version (empty for default):
- Enter the extension's main package (empty for default):
- Go to Anypoint studio, File > Open Project from File System, and select the project directory you have created in the last step.
- After you open this project in Anypoint studio, you will get the number of classes, annotated with mule SDK annotations as below:
- The connector is called as an extension in Mule 4, and it's class defined by the annotation @Extension. A @Configurations annotation is used to point the configuration class.
package org.mule.extension.internal; import org.mule.runtime.extension.api.annotation.Extension; import org.mule.runtime.extension.api.annotation.Configurations; import org.mule.runtime.extension.api.annotation.dsl.xml.Xml; /** * This is the main class of an extension, is the entry point from which configurations, connection providers, operations * and sources are going to be declared. */ @Xml(prefix = "my-name") @Extension(name = "My name") @Configurations(MynameConfiguration.class) public class MynameExtension { }
- Configuration class defines the parameters that we expect appears in configuration part of the connector. We can use @ConnectionProvider and @Operation annotation with this class to point out the connection providers and the operations connector has implemented.
package org.mule.extension.internal; import org.mule.runtime.extension.api.annotation.Operations; import org.mule.runtime.extension.api.annotation.connectivity.ConnectionProviders; import org.mule.runtime.extension.api.annotation.param.Parameter; /** * This class represents an extension configuration, values set in this class are commonly used across multiple * operations since they represent something core from the extension. */ @Operations(MynameOperations.class) @ConnectionProviders(MynameConnectionProvider.class) public class MynameConfiguration { @Parameter private String configId; public String getConfigId(){ return configId; } }
- The next important class is MynameConnectionProvider, which is annotated as @ConnectionProviders in configuration class.
- This class is used to manage and provide the connection with the targeted system.
- The connection provider must implement the one of the connection provider available in Mule. Here, we are implementing the PoolingConnectionProvider, other options are CachedConnectionProvider and ConnectionProvider.
- Parameter required to establish connection must be defined into the ConnectionProvider class.
- Also, you must override connect, disconnect, and validate methods to provide the functionality specific to this connection provider.
package org.mule.extension.internal; import org.mule.runtime.api.connection.ConnectionException; import org.mule.runtime.extension.api.annotation.param.Parameter; import org.mule.runtime.extension.api.annotation.param.Optional; import org.mule.runtime.api.connection.ConnectionValidationResult; import org.mule.runtime.api.connection.PoolingConnectionProvider; import org.mule.runtime.api.connection.ConnectionProvider; import org.mule.runtime.api.connection.CachedConnectionProvider; import org.mule.runtime.extension.api.annotation.param.display.DisplayName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class (as it's name implies) provides connection instances and the funcionality to disconnect and validate those * connections. * <p> * All connection related parameters (values required in order to create a connection) must be * declared in the connection providers. * <p> * This particular example is a {@link PoolingConnectionProvider} which declares that connections resolved by this provider * will be pooled and reused. There are other implementations like {@link CachedConnectionProvider} which lazily creates and * caches connections or simply {@link ConnectionProvider} if you want a new connection each time something requires one. */ public class MynameConnectionProvider implements PoolingConnectionProvider<MynameConnection> { private final Logger LOGGER = LoggerFactory.getLogger(MynameConnectionProvider.class); /** * A parameter that is always required to be configured. */ @Parameter private String requiredParameter; /** * A parameter that is not required to be configured by the user. */ @DisplayName("Friendly Name") @Parameter @Optional(defaultValue = "100") private int optionalParameter; @Override public MynameConnection connect() throws ConnectionException { return new MynameConnection(requiredParameter + ":" + optionalParameter); } @Override public void disconnect(MynameConnection connection) { try { connection.invalidate(); } catch (Exception e) { LOGGER.error("Error while disconnecting [" + connection.getId() + "]: " + e.getMessage(), e); } } @Override public ConnectionValidationResult validate(MynameConnection connection) { return ConnectionValidationResult.success(); } }
- The Connection class is used by connection providers to handle the connection. By having the single connection class and multiple connection providers, we can create multiple connection configurations for our Connector.
package org.mule.extension.internal; /** * This class represents an extension connection just as example (there is no real connection with anything here c:). */ public final class MynameConnection { private final String id; public MynameConnection(String id) { this.id = id; } public String getId() { return id; } public void invalidate() { // do something to invalidate this connection! } }
- And finally, we have operation class. We can define any number of operation classes and all public methods from this class will be treated as a connector operation. We can inject configurations and connection to particular operation using @Config and @Connection annotation in method arguments.
package org.mule.extension.internal; import static org.mule.runtime.extension.api.annotation.param.MediaType.ANY; import org.mule.runtime.extension.api.annotation.param.MediaType; import org.mule.runtime.extension.api.annotation.param.Config; import org.mule.runtime.extension.api.annotation.param.Connection; /** * This class is a container for operations, every public method in this class will be taken as an extension operation. */ public class MynameOperations { /** * Example of an operation that uses the configuration and a connection instance to perform some action. */ @MediaType(value = ANY, strict = false) public String retrieveInfo(@Config MynameConfiguration configuration, @Connection MynameConnection connection){ return "Using Configuration [" + configuration.getConfigId() + "] with Connection id [" + connection.getId() + "]"; } /** * Example of a simple operation that receives a string parameter and returns a new string message that will be set on the payload. */ @MediaType(value = ANY, strict = false) public String sayHi(String person) { return buildHelloMessage(person); } /** * Private Methods are not exposed as operations */ private String buildHelloMessage(String person) { return "Hello " + person + "!!!"; } }
- The connector is called as an extension in Mule 4, and it's class defined by the annotation @Extension. A @Configurations annotation is used to point the configuration class.
- We can install this connector into local maven repository using the command:
$mvn clean install
- You can use this connector in your Mule 4 application by adding the following dependency in pom.xml:
<dependency> <groupId>org.mule.extension</groupId> <artifactId>mule-basic-extension</artifactId> <version>1.0.0-SNAPSHOT</version> <classifier>mule-plugin</classifier> </dependency>
Am I missing something here? Let me know in the comments section and I'll add to it!
This is just start of the Mule SDK 4.x.x. In the upcoming article, I'd like to share how to add test cases and how to use this connector in Mule flow.
Thanks.
Opinions expressed by DZone contributors are their own.
Comments