# mulesoft Mule SDK - Full Documentation
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, classloading, isolation
---
# About Classloading Isolation
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The Mule 4 classloading schema isolates the runtime, apps and modules from each other. Each
specifies the packages (rather than the classes) to export as part of its API, making those specific
packages visible.
## Modules Classloading Isolation
Classloading is automatically filtered by package and not by class, meaning that modules need to
specify which packages to export and make visible to the Mule app.
To determine what packages to export, the SDK introspects each configuration, connection, and
component return and input types to get their packages. So you need to make sure that any classes
that you _do not_ want to export are kept out of exported packages. Exported classes should not
share a package with classes that you do not want to export.
The suggested package hierarchy (used internally for MuleSoft modules):
org.mule.module \\--> .api.\* \\--> .internal.\*
- `.api.*` contains all the classes that to be exported and seen by the Mule app: Return Types,
Subtypes, Input Types, and Connection interfaces.
- `.internal.*` contains all the classes used for specific behavior of the module: Annotated
classes, `Connection` and `Operation` implementations, and internal classes.
### Knowing the Exported Packages and Return Types.
MuleSoft recommends that **all** exported classes belong to the module.
To avoid library clashes that make a module incompatible with other modules, app dependencies, or
even runtimes, it is _highly recommended_ that you:
- _Never_ return or receive objects from classes that belong to a library that a module is using.
Consider the scenarios in the next sections.
#### First Scenario: Exporting the Same Packages
This scenario includes two modules with two very different operations. Both use the same library
(GSON) to parse JSON and _return_ an instance of a `JsonObject` class. One of them uses GSON version
`1.1`, and the other uses GSON version `2.3`. The `JsonObject` class lives in the same package in
both versions, but the different implementations of each version make the classes incompatible.
This example exposes the `JsonObject` class as the return type of the operation:
First Module Operation
```java
public JsonObject getEmployee(@Connection EmployeesServiceConnection connection, String id) {
return new JsonObject(connection.getById(id));
}
```
Second Module Operation
```java
public JsonObject getAllProducts(@Connection ProductsServiceConnection connection) {
return new JsonObject(connection.getProdsJson());
}
```
When you deploy a Mule app and try to use two modules that export the same packages, Mule will fail
because two modules cannot export the same package.
#### Second Scenario: Returning Two Instances of the Same Class in Different Versions
Building on the previous example, assume that the operations do not export the _GSON_ packages.
Instead, they return a `java.lang.Object`.
First Module Operation
```java
public Object getEmployee() {
// Here JsonObject is from GSON 1.1
return new JsonObject();
}
```
Second Module Operation
```java
public Object getAllProducts() {
// Here JsonObject is from GSON 2.3
return new JsonObject();
}
```
If you use both modules in an app, only one of the two versions will be loaded for the app because
both classes have exactly the same fully qualified name. So the fully qualified names will clash,
and the module that needs the _unloaded_ version of the package will behave differently and be prone
to errors such as `ClassCastException` or `NoSuchMethodException`.
### The @Export annotation
The `@Export` annotation can be used for extreme corner cases or complex cases in which a module
needs to export a class that is not automatically exported by the SDK.
The `@Export` annotation receives an array of classes to be exported.
> [!WARNING] You cannot export a class without exporting all the classes in the same package as the
> exported class.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: connector, certification, sdk, program guidelines
---
# About MuleSoft Connector Certification Program Guidelines
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
This document pertains to connector certification for Mule 4.
MuleSoft’s connector certification program guides you through the process of creating an
enterprise-grade connector that is ready for certification by MuleSoft. Once certified, the
connector is made available through Anypoint Exchange for discovery and use by customers and
developers.
## Before You Begin
Before embarking on the certification program, consider the following and make sure you can adhere
to these requirements:
- The connector must be kept current and secure, and it must get re-certified at least once a year.
- The connector must be built and distributed for the enterprise version of the MuleSoft Software or
MuleSoft Service.
- All transactions for the connector must take place between the customer and the partner, not
through MuleSoft.
- The connector must be a fully functional, production-ready, enterprise-grade application and
protocol connector. That is, it’s a connector that connects Mule with an external system.
- Code must be ready for deployment into a continuous integration environment. Code should be
compilable from the command line without the need to import private repositories. Credentials
should be provided separately and be capable of getting set at compile time. In addition, sandbox
credentials for your connector are required for certification.
- The connector must only use third-party libraries that are open source or owned by you. No
third-party, non-distributable libraries are accepted.
- If a similar connector already exists on Anypoint Exchange, you can still submit your connector if
it provides additional functionality that is superior to the existing connector.
## Providing Support
Partners or developers are required to provide full support for each of their connectors on Anypoint
Exchange. For support inquiries received by MuleSoft, MuleSoft provides a commercially reasonable
level of first-tier telephone, web-based and/or email support directly to customers. MuleSoft takes
and resolves any issues that are linked to commercial MuleSoft products. Any issues specific to the
partner connector are escalated to the partner.
- Partner responds to all support queries escalated from MuleSoft within one business day.
- Partner makes a best effort to resolve technical support issues for customers within five business
days.
For help addressing issues related to partner-certified connectors, partners can contact
`MSPartnerSupport@salesforce.com`.
## Pricing For Your Connector
Partners or developers have sole discretion to decide whether to make your connectors available for
free or for a fee. However, all connectors must be available at no cost within Anypoint Studio.
While not mandatory, we recommend providing customers a trial of your connector for design and
deployment.
For more information, see the [Custom Module License](#see_also) link below.
Category Details Connector is available for download and use for free to customers through Anypoint Exchange.
Paid connectors can be used in Mule apps at design time in Anypoint Studio. In deployment, the connector cannot run without a license. Customers need to purchase the connector directly from the partner and should manage the use of the paid connector using a generated license key provided by MuleSoft. The pricing of the connector is determined by the partner.
## License Terms
Add the following legal terms before your license terms in `LICENSE.md`:
**About MuleSoft Certified Connectors**
MuleSoft Certified Connectors are developed by MuleSoft’s partners and developer community. These
connectors have been reviewed and certified by MuleSoft. To purchase the Connector Name Connector,
if required, or to receive assistance or support for it, contact _Partner Name_ directly at _Contact
Information_. MuleSoft disclaims any support obligation for MuleSoft Certified Connectors.
By installing this connector, you consent to MuleSoft sharing your contact information with the
developer of this connector so that you can receive more information about it directly from the
developer.
_Your own license terms._
## Export Compliance
You may not use or otherwise export or re-export any MuleSoft Confidential Information or MuleSoft
Documentation received from MuleSoft or your materials (including but not limited to Partner
Documentation and Partner Connector) except as authorized by United States laws. In particular, but
without limitation, MuleSoft Confidential Information, MuleSoft Documentation and your materials may
not be exported or re-exported (a) into any U.S. embargoed countries or (b) to anyone on the U.S.
Treasury Department’s list of Specially Designated Nationals or the U.S. Department of Commerce
Denied Person’s List or Entity List. You represent and warrant that you are not located in any such
country or on any such list. You also agree that you will not use or re-export any MuleSoft
Confidential Information or MuleSoft Documentation and your materials for any purposes prohibited by
United States law, including, without limitation, the development, design, manufacture or production
of nuclear, chemical or biological weapons.
You are solely responsible for ensuring that your provision of your materials to users through
Anypoint Exchange comply with any and all regulations regarding export and import of technology in
relevant jurisdictions. (Capitalized terms shall have same definition as in the Certified Connector
Partner Agreement.)
## Development and Certification
Tell MuleSoft about the connector you want to develop, and get certified by contacting
[MuleSoft](mailto:isv@mulesoft.com). MuleSoft will contact you with further information.
## See Also
- [Technical Guidelines for Connector Certifications](https://docs.mulesoft.com/mule-sdk/latest/certification-guidelines-for-connectors)
- [Custom Module License](https://docs.mulesoft.com/mule-sdk/latest/license#custom-module-license)
- [MuleSoft Trailblazer Community](https://trailhead.salesforce.com/trailblazer-community/neighborhoods/mulesoft)
- [Contact MuleSoft](mailto:isv@mulesoft.com)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Accessing New Features from Legacy Modules
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The `ForwardCompatibilityHelper` interface enables modules using legacy
`org.mule.runtime.extension.api` types to access features normally exposed as implicit parameters,
such as distributed tracing, without breaking compatibility with earlier Mule runtime versions. For
new modules built entirely with `org.mule.sdk.api`, consume these features directly through implicit
parameters instead.
`ForwardCompatibilityHelper` is defined in the `org.mule.sdk:mule-sdk-compatibility-api` artifact,
in the `org.mule.sdk.compatibility.api.utils` package. This artifact supports both the legacy
`org.mule.runtime.extension.api` types and the new `org.mule.sdk.api` types, which allows
translations between them.
## Use the Compatibility Helper
Use `ForwardCompatibilityHelper` if:
- Your module uses legacy `org.mule.runtime.extension.api` types
- You want to add support for new features (like distributed tracing) without forcing users to
upgrade their Mule Runtime
- You need to bridge between legacy API types and new SDK API types
### Inject ForwardCompatibilityHelper
To use `ForwardCompatibilityHelper`, inject it as an `Optional` in your component:
```java
import org.mule.sdk.compatibility.api.utils.ForwardCompatibilityHelper;
import javax.inject.Inject;
import java.util.Optional;
public class MyOperations {
@Inject
private Optional forwardCompatibilityHelper;
public void myOperation(CorrelationInfo correlationInfo) {
if (forwardCompatibilityHelper.isPresent()) {
// Use the helper on Mule 4.5.0+
DistributedTraceContextManager traceManager =
forwardCompatibilityHelper.get().getDistributedTraceContextManager(correlationInfo);
// Use traceManager...
} else {
// Fallback for older runtimes where the helper is not available
}
}
}
```
The `Optional` field contains an instance on Mule 4.5.0 and later. On earlier Mule runtime versions,
the `Optional` field is empty.
## Available Methods
`ForwardCompatibilityHelper` provides the following methods to access the
`DistributedTraceContextManager` for distributed tracing:
Method Usage getDistributedTraceContextManager(CorrelationInfo correlationInfo)
For use in operations. Accepts the legacy org.mule.runtime.extension.api.runtime.parameter.CorrelationInfo parameter type.
getDistributedTraceContextManager(org.mule.sdk.api.runtime.parameter.CorrelationInfo correlationInfo)
For use in operations. Accepts the new SDK API CorrelationInfo parameter type.
getDistributedTraceContextManager(SourceCallbackContext sourceCallbackContext)
## See Also
- [Forward Compatibility Patterns](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-patterns)
- [Implicit Parameters](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-implicit-params)
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, metadata, datasense, input, output, keys, type
---
# Adding DataSense Support
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
DataSense is a Mule service that displays type metadata for the entities in a module.
Although this feature is optional, MuleSoft strongly recommends that you use DataSense in your
module so that it is easier for users of your module to use.
Note that this documentation assumes that you are familiar with the architecture of connectors and
with the concept of DataSense from the perspective of an end user.
## What is the Metadata of a Component?
Integration developers often spend a lot of time trying to determine the input and output types for
a given component (operation, sources, and so on) so they can transform the data at hand to connect
the output of one component to the input of another. This often requires use of API documentation
for each component to discover the parameters. This process is inefficient, fallible, and often
frustrating.
DataSense uses the metadata provided by these components to resolve all this information
automatically and present it to your end user in design time, which drastically increases the speed
of development.
Note that unlike [Value Providers](https://docs.mulesoft.com/mule-sdk/latest/value-providers), which are meant to narrow down the possible
values that a parameter of a known type can take, this feature is to discover dynamic types whose
universe of possible values is not to be discovered by this feature.
The term "types" refers to the `MetadataType` of an element. A `MetadataType` represents the kind
and structure of a given element, like `StringType` or `NumberType` for elements that are basic
string or numbers, `ArrayType` for collections, `ObjectType` for complex structures with nested
elements (like a POJO or a JSON object), and `AnyType` for elements whose type is actually unknown
and can be any of the other available types.
See [DataWeave Types](https://docs.mulesoft.com/dataweave/latest/dataweave-types).
### Static Metadata
Static metadata is metadata that is known at compile time and available from the types in the
connector’s JAR file. Simple Java types are part of this static metadata as are custom POJOs defined
by the developer in its model. What is relevant is that the structure is well known or can be
introspected without depending on other parameters.
### Dynamic Metadata
Dynamic metadata is metadata of a type with an unknown structure at compile time. It has to be
resolved based on the configuration of the connector at design time. This metadata has different
uses that span a range of cases. Uses span from cases where the type itself is known but its
structure depends on the service configuration (for example, where the system has an account with
fields that can be customized by the user, so its structure has to be discovered each time based on
the user’s credentials) to cases where everything is dynamic and the structure described heavily
depends on the configured parameters (for example, the described structure is the payload of a
service operation that also depends on the definition of the service based on the user sandbox).
To resolve dynamic metadata, the element has to be associated with a metadata resolver that knows
how to obtain the desired type structure based on the current component configuration. This is
explained in more detail in [MetaData Resolvers](#metadata_resolvers).
### Input Metadata
Input metadata is the type resolution for the parameters of a component. Each parameter can provide
either static or dynamic metadata that is isolated from the kind of metadata that other parameters
of the same component expose.
Only operations and sources can have parameters with dynamic metadata, while configurations and
connections always have static metadata.
### Output Metadata
The output of a component is bound to a static or dynamic resolution of its metadata. For example, a
`void` operation has static metadata indicating that the output of that operation is of `VoidType`,
while an operation that fetches a `User` profile from a remote service can dynamically describe the
structure of the `User` type.
As explained in [Structure](https://docs.mulesoft.com/mule-sdk/latest/module-structure), an operation can output a result that contains data
for the payload and the attributes of the resulting message. The structure of these attributes is
just as important as the structure of the payload. So, to improve the experience of your end user,
metadata for each of them can be described independently, but dynamic metadata for attributes is
always optional because some components might not produce attributes.
Note that certain return types are forced to describe their metadata dynamically. This requirement
is for consistency because it is necessary to consider the experience of the end user, and types
that are too generic interfere with the quality of the user experience.
## Implementation Overview
Implementing dynamic DataSense support starts with defining the type of metadata you want to provide
for a given element. Once that is defined, you can make use of a combination of annotations and
custom implementations of different metadata resolvers, such as
`@MetadataKeyId(BucketKeysResolver.class)`. What to use depends on your use case.
The next sections provide detailed information on implementing the cases described above.
### Metadata Keys Parameter
To describe a dynamic metadata structure, you need to know what type has to be represented. This
type reference is done by defining a `@MetadataKeyId` parameter in the operation that will hold the
ID of the type to be described.
This means, for example, that if your operation can save a generic record to Amazon S3, but you want
to provide a better design-time experience by describing each supported type structure (for example,
`Account` or `Organization`), then one of your operation parameters will be a type reference
containing either the id `Account` or the id `Organization`. This parameter will be used to describe
either the Account structure or the Organization structure for the record to be saved into the
bucket, depending on what the end user decides to use.
Having a `@MetadataKeyId` parameter is not always required because you might have only one structure
(and not multiple) to define that vary dynamically based on the configuration. For example, you
might have a `User` entity whose structure changes based on whether the connection credentials are
for an administrator or not.
The purpose of including a MetadataKey parameter is to use the value given to it to resolve the
metadata of output and inputs of the component for which the key is defined. This means that you
should not define a MetadataKey without any MetadataResolver for inputs, output, or Attributes. SDK
versions 1.3 and later fail to compile connectors that contain a Component that has a MetadataKey
parameter but does not have an Output Resolver or Input Resolvers.
### Metadata Resolvers
Whenever you want to obtain a dynamic element for DataSense, you implement a metadata resolver.
There are many different kinds of resolvers, each with its own responsibility and use cases
(explained later), but they all share these main concepts:
- Category Name: Name of the group that relates different metadata resolvers so they can work
together.
- Resolver Name: Name that uniquely identifies a given metadata resolver. Different resolvers can
belong to the same `category` but _must_ have different resolver names.
- Metadata Context: Provides access to all the configuration and connection elements used during the
metadata fetch invocation, along with a set of utility components, such as `TypeLoader` and
`TypeBuilder`. It is important to always use the implementations provided by the context when
creating a dynamic type.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Advanced Parameter Handling
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Features in the SDK can improve the quality of your module by adding UI and UX tuning, enabling
extension points so your module can interact with elements of other modules, and providing
implementation enhancements to avoid boilerplate code.
## UI and UX Tuning
- [Special Parameters](https://docs.mulesoft.com/mule-sdk/latest/special-parameters)
- [Customizing the Parameters UI](https://docs.mulesoft.com/mule-sdk/latest/parameter-layout)
- [Customizing the Parameters DSL](https://docs.mulesoft.com/mule-sdk/latest/parameters-dsl)
- [Exclusive Optional](https://docs.mulesoft.com/mule-sdk/latest/exclusive-optionals)
- [Value Providers](https://docs.mulesoft.com/mule-sdk/latest/value-providers)
## Extension Points and Modules Reuse
- [Importing Types From Other Modules](https://docs.mulesoft.com/mule-sdk/latest/imported-types)
- [Using Generic Parameters For Extended Behavior](https://docs.mulesoft.com/mule-sdk/latest/subtypes-mapping)
- [Stereotypes As A Way Of Referencing Elements By Kind](https://docs.mulesoft.com/mule-sdk/latest/stereotypes)
## Implementation Enhancers
- [NullSafe](https://docs.mulesoft.com/mule-sdk/latest/null-safe)
- [Mule Services Injection](https://docs.mulesoft.com/mule-sdk/latest/mule-service-injection)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Advanced Sources Settings
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## @ClusterSupport
**Available since version 1.1**
You can use this annotation to indicate how the Source behaves when the Mule Runtime is running in
Cluster mode, for example:
```java
@ClusterSupport(DEFAULT_PRIMARY_NODE_ONLY)
public class JmsListener extends Source {
// ...
}
```
The `@ClusterSupport` annotation takes a parameter of type `SourceClusterSupport`, which can take
the following values:
- NOT\_SUPPORTED: The source does not support cluster mode, so it only runs on the primary node. If
the primary node crashes, a new primary node will be designated, and the source will be started on
it.
- DEFAULT\_ALL\_NODES: Runs on all the cluster nodes by default, but the user can choose to only run
on the primary one.
- DEFAULT\_PRIMARY\_NODE\_ONLY: Only runs on the primary node by default, but the user can choose to
run on all the nodes.
When the selected value is other than `NOT_SUPPORTED`, a parameter named `primaryNodeOnly` is
automatically added so you can configure whether the source should run in all nodes or just the
primary ones.
> [!TIP] Notice that when this parameter is added, it will be optional, and its default value will
> depend on the selected cluster support mode.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Authentication Handler
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
This handler allows you to configure the current context’s authentication, which is used for
encryption and inbound authentication, based on a given request.
## How to Use the Authentication Handler
When you add a parameter of type `AuthenticationHandler` to your operation, the Authentication
Handler instance from the current context will be injected in runtime. You can use this instance to
check the current authentication (if there is any) and set a new one.
The Authentication Handler interface provides the following methods:
- `createCredentialsBuilder` returns a builder that is used to create a `Credentials` instance.
- `createAuthentication`, when given an instance of `Credentials`, creates an `Authentication`
instance.
- `setAuthentication`, when given an `Authentication`, sets that value as the current context’s
authentication. Optionally, you can also provide a List of security providers (the names) that
will be added to the `SecurityManager`.
- `getAuthentication` returns the `Authentication` from the current context. There may be no
`Authentication` for the current context.
## Usage Example
Imagine that after receiving an HTTP Request, you want to authenticate and store the credentials on
the current context’s Authentication Handler. You can use the `basic-security-filter` operation from
the HTTP Connector for this use case.
This simplified example shows how the `basic-security-filter` is implemented:
```java
public class HttpOperations {
/**
* Authenticates received HTTP requests. Must be used after a listener component.
*/
@Throws(BasicSecurityErrorTypeProvider.class)
public void basicSecurityFilter(@ParameterGroup(name = "Security Filter") HttpBasicAuthenticationFilter filter,
AuthenticationHandler authenticationHandler) { (1)
try {
filter.authenticate(authenticationHandler);
} catch (BasicUnauthorisedException e) {
throw new ModuleException(BASIC_AUTHENTICATION, e);
} catch (SecurityProviderNotFoundException | SecurityException | UnknownAuthenticationTypeException e) {
throw new ModuleException(SERVER_SECURITY, e);
}
}
// ...
}
```
1 The operation has an AuthenticationHandler parameter that will be injected in runtime.
```java
public class HttpBasicAuthenticationFilter {
@Parameter
private String realm;
@Parameter
@Optional
@NullSafe
private List securityProviders;
@Parameter
@Optional(defaultValue = "#[attributes]")
HttpRequestAttributes attributes; (1)
public void authenticate(AuthenticationHandler authenticationHandler)
throws SecurityException, SecurityProviderNotFoundException, UnknownAuthenticationTypeException {
String header = attributes.getHeaders().get("Authorization".toLowerCase());
if ((header != null) && header.startsWith("Basic ")) {
String username = retrieveUsername(header);
String password = retrievePassword(header);
Credentials credentials = authenticationHandler.createCredentialsBuilder() (2)
.withUsername(username)
.withPassword(password.toCharArray())
.build();
try {
Authentication authentication = authenticationHandler.createAuthentication(credentials); (3)
authenticationHandler.setAuthentication(securityProviders, authentication); (4)
} catch (UnauthorisedException e) { (5)
throw new BasicUnauthorisedException(authFailedForUser(username), e);
}
} else if (header == null) {
throw new BasicUnauthorisedException(null, "HTTP basic authentication", "HTTP listener");
} else {
throw new UnsupportedAuthenticationSchemeException("Http Basic filter doesn't know how to handle header " + header));
}
}
}
```
1 HttpRequestAttributes from where the username and password will be taken.2 Credentials are created with the information taken from the request.3 An Authentication is created based on Credentials. 4 The authentication information is checked against the securityProviders and set to the handler. 5 When the authentication information is invalid, and an exception is thrown.
If there is another operation in the flow that has an Authentication Handler as a parameter, the
instance that is injected will be the same as the one that is handled on the
`basic-authentication-filter` operation. This way, by using the `getAuthentication` method, you will
get the `Authentication` with the credentials from the HTTP Request.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, grant, oauth
---
# Authorization Code
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Authorization Code is a grant type that allows an application to act on behalf of a user without the
need for that user to share their actual credentials. This grant type allows an application to
impersonate a user.
## Develop an Authorization Code-enabled Connector
OAuth support is added at the `ConnectionProvider` level through the `@AuthorizationCode`
annotation.
Here is an oversimplified `ConnectionProvider` example for the Salesforce connector:
```java
@AuthorizationCode(
authorizationUrl = "https://login.salesforce.com/services/oauth2/authorize",
accessTokenUrl = "https://login.salesforce.com/services/oauth2/token")
public class SalesforceOAuthConnectionProvider implements ConnectionProvider {
@Parameter
@Optional(defaultValue = "34.0")
private Double apiVersion;
/**
* Tailors the login page to the user's device type.
*/
@OAuthParameter
private String display;
/**
* Avoid interacting with the user
*/
@OAuthParameter
@Optional(defaultValue = "false")
private boolean immediate;
/**
* Specifies how the authorization server prompts the user for reauthentication and reapproval
*/
@OAuthParameter
@Optional(defaultValue = "true")
private boolean prompt;
@OAuthCallbackValue(expression = "#[payload.instance_url]")
private String instanceId;
@OAuthCallbackValue(expression = "#[payload.id]")
private String userId;
private AuthorizationCodeState state;
@Override
public SalesforceClient connect() throws ConnectionException {
if (state.getAccessToken() == null) {
throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "accessToken"));
}
if (instanceId == null) {
throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "instanceId"));
}
return new SalesforceClient(state, instanceId, apiVersion); (1)
}
public void disconnect(SalesforceClient connection) {
connection.close();
}
@Override
public ConnectionValidationResult validate(SalesforceClient connection) {
return success();
}
}
```
1 The connection receives the state object and not the access token. Access tokens can be refreshed or unauthorized at any time, which can make the connection useless, thus you must always query the state object whenever the access token is needed. For more information, refer to Always Query the State Object on Each Request .
The class implements `ConnectionProvider`, just like other connections in the SDK. Operations that
are authenticated through the object operate over the `SalesforceClient` object that the provider
returns. This is an important design consideration because it permits you to decouple the operation
from the authentication method that is used because the connector could define another
`ConnectionProvider` that uses plain old, basic authentication, and all the operations would remain
fully compatible.
## @AuthorizationCode
This annotation indicates that this connection provider requires an OAuth dance using the
Authorization Code grant type. The annotation has the following attributes:
```java
public @interface AuthorizationCode {
/**
* @return The Url of the endpoint which provides the access tokens
*/
String accessTokenUrl();
/**
* @return The url of the authorization endpoint which starts the OAuth dance
*/
String authorizationUrl();
/**
* @return Expression to be used on the response of {@link #accessTokenUrl()} to extract the access token
*/
String accessTokenExpr() default "#[payload.access_token]";
/**
* @return Expression to be used on the response of {@link #accessTokenUrl()} to extract the access token expiration
*/
String expirationExpr() default "#[payload.expires_in]";
/**
* @return Expression to be used on the response of {@link #accessTokenUrl()} to extract the refresh token
*/
String refreshTokenExpr() default "#[payload.refresh_token]";
/**
* @return The default set of scopes to be requested, as a comma separated list. Empty string means no default scopes.
*/
String defaultScopes() default "";
}
```
## Connection Management Strategy
The provider in the example above doesn’t implement any specialization of the `ConnectionProvider`
interface, which means that the OAuth mechanism can be combined with the other connection management
strategies. The connection objects can be pooled, cached, or created from scratch each time,
depending on which interface is used (`PoolingConnectionProvider`, `CachedConnectionProvider`,
`ConnectionProvider`, and so on). For more information on connectivity management, see the
[connectivity reference](https://docs.mulesoft.com/mule-sdk/latest/connections).
Be aware of the semantics of using the vanilla (generic) `ConnectionProvider` interface in this
scenario. In a regular, “non-oauth” connection provider, using the vanilla interface means that each
time a component requires a connection, a new one will be created, and it will be destroyed when the
component is finished. Although this will remain true for the OAuth case, it doesn’t mean that the
OAuth dance will be performed again. New connection objects will be created, but the same access
token will be reused as long as it remains valid.
## Regular Parameters Versus OAuth Parameters
This `ConnectionProvider` can have parameters, just like any other connection provider. However, you
have to distinguish regular parameters from the concept of `@OAuthParameter`.
An `OAuthParameter` is included as a custom parameter while performing the OAuth dance. So, for
example, while the `apiVersion` parameter is something that the connection provider will use to
create the `SalesforceClient`, the immediate parameter is actually sent on the OAuth request to the
service provider.
From the module’s point of view, it is just another parameter for which the user will provide a
value. You can combine these parameters with `@Optional`, `@Expression`, and all the other
annotations you can use with the traditional `@Parameter` annotation. In the DSL, regular and oauth
parameters appear together. The module’s end user shouldn’t notice any difference.
### Request Alias
Some custom OAuth parameters might include characters that aren’t supported in Java. For example
"Api-Key". Since you can’t use "-" as part of a field name, the `@OAuthParameter` annotation has an
optional parameter called `requestAlias`, for example:
```java
@OAuthParameter(requestAlias = "api-key")
private String apiKey;
```
## @OAuthCallbackValue
Callback values are extracted from the response that the service provider sends through the OAuth
callback. Although most service providers simply return standard items (such as access and refresh
tokens, expiration information, and so on), some others return additional items. In the Salesforce
case, they return user and instance ids.
The annotation includes an expression that is applied on the response to extract the value. That
value is then assigned to the field for the connection provider to use. When the `connect()`,
`validate()` or `disconnect()` methods are invoked, the fields are set and usable.
## @AuthorizationCodeState
Every `ConnectionProvider` annotated with `AuthorizationCode` **MUST** contain one (and only one)
field of type `AuthorizationCodeState`.
It is a simple immutable POJO that contains information regarding the outcome of the OAuth dance. It
contains the following information:
```java
public interface AuthorizationCodeState {
/**
* @return The obtained access token
*/
String getAccessToken();
/**
* @return The obtained refresh token
*/
Optional getRefreshToken();
/**
* @return The id of the user that was authenticated
*/
String getResourceOwnerId();
/**
* @return The access token's expiration. The actual format of it depends on the OAuth provider
*/
Optional getExpiresIn();
/**
* @return The OAuth state that was originally sent
*/
Optional getState();
/**
* @return The url of the authorization endpoint that was used in the authorization process
*/
String getAuthorizationUrl();
/**
* @return The url of the access token endpoint that was used in the authorization process
*/
String getAccessTokenUrl();
/**
* @return The OAuth consumer key that was used in the authorization process
*/
String getConsumerKey();
/**
* @return The OAuth consumer secret that was used in the authorization process
*/
String getConsumerSecret();
/**
* @return The external callback url that the user configured or {@link Optional#empty()} if none was provided
*/
Optional getExternalCallbackUrl();
/**
* Customizes the placement of the client credentials in the request.
*
* @Since 1.4
*
* @return the selected {@link CredentialsPlacement}. Defaults to {@link CredentialsPlacement#BODY}.
*/
CredentialsPlacement credentialsPlacement() default BODY;
/**
* Whether the redirect_uri parameter should be included in the refresh token request. Defaults to {@code true}
*
* @since 1.4.0
*/
boolean includeRedirectUriInRefreshTokenRequest() default true;
}
```
Through this object, the provider gains access to the `accessToken` and other standard information
that was obtained during the OAuth dance. Returning to the original Salesforce example, you can see
how the `connect()` method makes use of this POJO to create the client.
## Configure an Authorization Code Connector
OAuth-enabled connectors automatically support the Authorization Code grant type. This section
describes the parameters and how to configure them.
### Synthetic Parameters
In addition to the parameters defined in the `ConnectionProvider`, the SDK automatically injects
some standard OAuth parameters for Authorization Code.
Parameter Name Required Expressions Default Value Description consumerKey
YES
SUPPORTED
N.A.
The OAuth consumer key as registered with the service provider.
consumerSecret
YES
NOT_SUPPORTED
N.A.
The OAuth consumer secret registered with the service provider.
authorizationUrl
YES
SUPPORTED
N.A.
The URL of the authorization endpoint to start the OAuth dance.
accessTokenUrl
YES
SUPPORTED
N.A.
The URL to request the access token after the OAuth dance.
scopes
NO
SUPPORTED
N.A.
The OAuth scopes to request during authorization. If not provided, defaults to those in the annotation.
resourceOwnerId
NO
SUPPORTED
N.A.
The ID of the authenticated user.
before
NO
SUPPORTED
N.A.
A flow to execute before authentication.
after
NO
SUPPORTED
N.A.
A flow to execute after authentication.
authServerTlsContext
NO
NOT_SUPPORTED
N.A.
A reference to the TLS context configuration used for the authorization server.
authServerProxyConfig
NO
NOT_SUPPORTED
N.A.
A reference to the proxy configuration used for the authorization server.
### About the Use of Expressions
Many of the synthetic parameters accept expressions. Using expressions allows the configuration to
be dynamic, just like with regular parameters.
### OAuth Connection DSL
The following example shows a basic Authorization Code connection configuration.
```java
```
### OAuth Connection DSL with TLS Context Configuration
This example shows how to configure a TLS context for the Authorization Code flow.
```java
```
### OAuth Connection DSL with Proxy Configuration
This example shows how to set a proxy for the Authorization Code flow.
```java
```
### Custom ObjectStore Configuration
Access tokens are stored in an Object Store. By default, the SDK uses the app’s default Object
Store, but you can define a custom one.
```java
```
## Next Step
[Configuring an OAuth enabled module](https://docs.mulesoft.com/mule-sdk/latest/oauth-configuring)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, streaming, binary
---
# Binary Streaming
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
In binary streaming use cases, the stream is a flux of bytes that are treated in a generic way
regardless of what they represent. Examples include the response of an HTTP request or retrieving
and writing a file in a FTP server.
The SDK supports this abstraction by using the Java `InputStream` class.
## Binary Streaming in Operations
Operations can receive stream parameters, return streams, or do both.
The Write operation in the File connector is an example of an operation that operates over a stream:
```java
public class FileOperations {
public void write(@Content InputStream content, String path) {
// do the writing
}
}
```
If you have parameter of type `InputStream`, the SDK will provide all the necessary support for
using Mule’s streaming capabilities. The `content` parameter in the example above will always be
assigned to a repeatable stream that points to the beginning of the stream, treating it as if this
is the first time the stream is getting read, whether that is true or not.
Another possibility is that your operation _returns_ a binary stream instead, like the Read
operation does:
```java
public class FileOperations {
public InputStream read(String path) {
// do the reading
}
}
```
If you return an `InputStream`, the SDK will automatically add all the necessary magic to make that
stream repeatable.
## Configuring Streaming
By allowing elements such as ` `, ` `
and ` `, the SDK automatically adds support for configuring how streaming
should behave. Here is an example that configures custom file store streaming for the Read example
above:
```xml
```
## Stream from Existing Files
Available since version 1.3.
When the `` strategy is used, a file temporarily holds information
that doesn’t fit into the in-memory buffer. There are particular cases in which using this strategy
is inefficient and leads to suboptimal I/O and disk space requirements.
The most common cases of this include:
Scenario 1
You are building an Operation or Source that returns the content of a file. The component that you
are developing opens a file and returns an InputStream that contains the file content. If the file
is bigger than the memory buffer, the starts building a temporary
file with the stream content. That file becomes an exact duplicate of the original file that was
already opened.
Scenario 2
In a variation of Scenario 1, an Operation or Source obtains an InputStream and needs to pre-process
it _before_ it is returned. Because the original stream is not yet pushed to the flow, it hasn’t
been made repeatable. As a result, the source needs to implement its own buffering by storing the
processed contents into a temporary file as it processes the original stream. When pre-processing
finishes, the source then pushes the contents of the file, going back to Scenario 1.
These two scenarios articulate a need to get a repeatable stream from the content of an existing
file, without the repeatable streaming framework creating a new file of its own, since the contents
already originate from a file.
In these scenarios, use the `ImmutableFileRepeatableInputStream` class, which is similar to the
standard `java.io.FileInputStream` but prevents Mule runtime engine (Mule) from generating a new
buffering file and instructs Mule to reuse the existing file.
For example, this class can be used in an operation:
```java
@MediaType(value = ANY, strict = false)
public InputStream read(String path) {
File file = new File(path);
if (!file.exists()) {
// throw ModuleException
}
return new ImmutableFileRepeatableInputStream(file);
}
```
An important aspect of working with files of this nature is understanding when to delete them.
Depending on the use case, you might need to delete them through your own code. In simpler cases,
you can delete files when the stream is closed. If you want to delete the file when the stream is
closed, you can use the following convenience constructor, which enables you to instruct Mule to
automatically delete the file when the stream is closed:
`new ImmutableFileRepeatableInputStream(file, true);`
> [!IMPORTANT] The file must be immutable for you to use this feature. That means that once the
> `ImmutableFileRepeatableInputStream` instance is created, the contents of that file cannot change,
> at least until `ImmutableFileRepeatableInputStream` is closed. Changing the file’s content while
> the flow is reading it can lead to inconsistencies, dirty reads, and other types of race
> conditions.
## See Also
- [Streaming](https://docs.mulesoft.com/mule-sdk/latest/streaming)
- [Repeatable Streams](https://docs.mulesoft.com/mule-runtime/latest/streaming-about#repeatable-streams)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, create, new, project, getting, started, version
---
# Choosing the SDK Version
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Starting with `mule-java-extension-parent` version 1.11.0, the SDK supports forward compatibility.
The SDK version is now decoupled from the minimum Mule version your module requires, so you can
always use the latest SDK version while controlling runtime compatibility independently.
For new modules, use the latest version of `mule-java-extension-parent`:
```xml
org.mule.extensions
mule-java-extension-parent
1.11.0
```
With forward compatibility, you can:
- Compile against the latest SDK APIs
- Control your module’s minimum Mule version through the `min.mule.version` property
- Use new SDK features for users on recent Mule runtime versions while maintaining compatibility
with earlier Mule runtime versions.
See [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility) for detailed information on how to configure
and use this feature.
## See Also
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
- [Setting Up Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-setup)
- [Extensions API (Deprecated)](https://docs.mulesoft.com/mule-sdk/latest/extensions-api-deprecated)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, grant, oauth
---
# Client Credentials
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Available since version 1.3.
Unlike the Authorization Code grant type, which focuses on authorizing an application that wants to
act on a user’s behalf, the Client Credentials grant type focuses on authorizing an application to
act on its own behalf. This grant type is better suited for machine-to-machine communication because
it doesn’t require human intervention.
## Develop a Client Credentials-Enabled Connector
You can add Client Credentials support at the `ConnectionProvider` level through the
`@ClientCredentials` annotation.
Here is an oversimplified `ConnectionProvider` example for Anypoint Connector for Salesforce
(Salesforce Connector):
```java
@ClientCredentials(tokenUrl = "https://login.salesforce.com/services/oauth2/authorize")
public class SalesforceOAuthConnectionProvider implements ConnectionProvider {
@Parameter
@Optional(defaultValue = "34.0")
private Double apiVersion;
/**
* Tailors the login page to the user's device type.
*/
@OAuthParameter
private String display;
/**
* Avoid interacting with the user
*/
@OAuthParameter
@Optional(defaultValue = "false")
private boolean immediate;
/**
* Specifies how the authorization server prompts the user for reauthentication and reapproval
*/
@OAuthParameter
@Optional(defaultValue = "true")
private boolean prompt;
@OAuthCallbackValue(expression = "#[payload.instance_url]")
private String instanceId;
@OAuthCallbackValue(expression = "#[payload.id]")
private String userId;
private ClientCredentialsState state;
@Override
public SalesforceClient connect() throws ConnectionException {
if (state.getAccessToken() == null) {
throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "accessToken"));
}
if (instanceId == null) {
throw new SalesforceException(MessageFormat.format(COULD_NOT_EXTRACT_FIELD, "instanceId"));
}
return new SalesforceClient(state.getAccessToken(), instanceId, apiVersion);
}
public void disconnect(SalesforceClient connection) {
connection.close();
}
@Override
public ConnectionValidationResult validate(SalesforceClient connection) {
return success();
}
}
```
The class implements `ConnectionProvider`, just like other connections in the SDK. Operations that
are authenticated through the object operate over the `SalesforceClient` object that the provider
returns. This is an important design consideration because it permits you to decouple the operation
from the authentication method that is used because the connector could define another
`ConnectionProvider` that uses basic authentication, and all the operations remain fully compatible.
### @ClientCredentials
This annotation indicates that this connection provider requires an OAuth dance using the Client
Credentials grant type. The annotation has the following attributes:
```java
public @interface ClientCredentials {
/**
* @return The Url of the endpoint which provides the access tokens
*/
String tokenUrl();
/**
* @return Expression to be used on the response of {@link #tokenUrl()} to extract the access token
*/
String accessTokenExpr() default "#[payload.access_token]";
/**
* @return Expression to be used on the response of {@link #tokenUrl()} to extract the access token expiration
*/
String expirationExpr() default "#[payload.expires_in]";
/**
* @return The default set of scopes to be requested, as a comma separated list. Empty string means no default scopes.
*/
String defaultScopes() default "";
/**
* Allows to customize the placement that the client credentials will have in the request.
*
* @return the selected {@link CredentialsPlacement}. Defaults to {@link CredentialsPlacement#BASIC_AUTH_HEADER}
*/
CredentialsPlacement credentialsPlacement() default BASIC_AUTH_HEADER;
}
```
### Connection Management Strategy
The provider in the `@ClientCredentials` example doesn’t implement any specialization of the
ConnectionProvider interface, which means that the OAuth mechanism can be combined with the other
connection management strategies. The connection objects can be pooled, cached, or created anew each
time, depending on which interface is used (for example, PoolingConnectionProvider,
CachedConnectionProvider, ConnectionProvider, and so on). For more information about connectivity
management, see the connectivity reference.
Be aware of the semantics of using the unspecialized (for example, not PoolingConnectionProvider,
CachedConnectionProvider) ConnectionProvider interface in this scenario. In a regular, “non-OAuth”
connection provider, using the unspecialized interface means that each time a component requires a
connection, a new one is created, and it is destroyed when the component is finished. Although this
will remain true for the OAuth case, it doesn’t mean that the OAuth dance is performed again. New
connection objects are created, but the same access token is reused as long as it remains valid.
### Regular Parameters versus OAuth Parameters
This ConnectionProvider can have parameters, just like any other connection provider. However, you
must distinguish regular parameters from the concept of `@OAuthParameter`.
An OAuthParameter is included as a custom parameter while performing the OAuth dance. So, for
example, while the `apiVersion` parameter is something that the connection provider uses to create
the SalesforceClient, the immediate parameter is actually sent on the OAuth request to the service
provider.
From the module’s point of view, it is just another parameter for which the user provides a value.
You can combine these parameters with `@Optional`, `@Expression`, and all the other annotations you
can use with the traditional `@Parameter` annotation. In the DSL, regular and OAuth parameters
appear together. The module’s end user shouldn’t notice any difference.
## requestAlias Parameter
Some custom OAuth parameters include characters that aren’t supported in Java, for example
`Api-Key`. Since you can’t use `-` as part of a field name, the @OAuthParameter annotation has an
optional parameter called `requestAlias`:
```java
@OAuthParameter(requestAlias = "api-key")
private String apiKey;
```
### @OAuthCallbackValue Annotation
Callback values are extracted from the response that the service provider sends through the OAuth
callback. Although most service providers return only standard items (such as access and refresh
tokens, expiration information, and so on), others return additional items (such as user and
instance IDs, in the case of Salesforce).
The annotation includes an expression that is applied to the response to extract the value. That
value is then assigned to the field for the connection provider to use. When the connect(),
validate(), or disconnect() methods are invoked, the fields are set and usable.
### @ClientCredentialsState
Every ConnectionProvider annotated with `@ClientCredentials` _must_ contain one (and only one) field
of type ClientCredentialsState.
It is a simple immutable POJO that contains information regarding the outcome of the OAuth dance. It
contains the following information:
```java
public interface ClientCredentialsState {
/**
* @return The obtained access token
*/
String getAccessToken();
/**
* @return The access token's expiration. The actual format of it depends on the OAuth provider
*/
Optional getExpiresIn();
}
```
Through this object, the provider gains access to the accessToken and other standard information
that was obtained during the OAuth dance. The original Salesforce example shows how the connect()
method uses this POJO to create the client.
## Configure a Client Credentials Connector
An important aspect of OAuth-enabled connectors or modules is how to use them. As much as the SDK
does to hide the complexities of the OAuth protocol, things like the OAuth dance are unavoidable.
The SDK’s approach to this problem is to standardize the experience of all OAuth modules to keep
simplifying the user experience. This section discusses the steps a user must take to use the
module.
### Synthetic Parameters
In addition to everything explicitly defined in the ConnectionProvider, the SDK automatically adds
some extra parameters and injects the proper behavior for them.
Parameter Name Required Expressions Default Value Description clientId
YES
SUPPORTED
N.A.
The OAuth clientId value as registered with the service provider.
clientSecret
YES
NOT_SUPPORTED
N.A.
The OAuth clientSecret value as registered with the service provider.
tokenUrl
NO
SUPPORTED
Value provided in the @ClientCredentials annotation.
The service provider’s token endpoint URL.
scopes
NO
SUPPORTED
The value provided in the @ClientCredentials annotation.
The OAuth scopes to be requested during the dance. If not provided, this value defaults to those in the annotation.
objectStore
NO
NOT_SUPPORTED
N.A.
A reference to the ObjectStore used for storing each resource owner ID’s data. If not specified, the runtime automatically provisions a default one.
authServerProxyConfig
NO
NOT_SUPPORTED
N.A.
A reference to the proxy configuration used to perform the validation.
authServerTlsContext
NO
NOT_SUPPORTED
N.A.
A reference to the TLS context configuration used to perform the validation, with the trust store configured.
### About the Use of Expressions
The synthetic parameters table identifies many of the synthetic parameters that accept expressions.
Using expressions there has the same effect as using expressions in a regular parameter: it turns
the configuration dynamic.
### OAuth Connection DSL
The following example shows generated DSL:
```java
```
Regular and OAuth parameters are all shown at the connection provider level, as they would be in any
other provider. The parameters related to the Client Credentials grant type are placed on a child
element called . The parameters related to ObjectStore are placed in a
child element called .
### OAuth Connection DSL with TLS Context Configuration
This example shows how to set a TLS context for OAuth client credentials authorization.
```java
```
### OAuth Connection DSL with Proxy Configuration
This example shows how to set a proxy configuration for OAuth client credentials authorization.
```java
```
### Configuring a Custom ObjectStore
The obtained access tokens are stored in an Object Store. By default, the SDK stores them in the
app’s default Object Store, but users can define their own custom Object Store, as shown in this
example.
```java
```
## Refresh an Expired Client Credentials Access Token
Most access tokens have a limited lifespan: typically about 30 to 60 minutes after being issued.
This is why most providers also supply a refresh token, which eliminates the need to perform the
OAuth dance again, although this isn’t a standard that is strictly enforced by providers. There
isn’t an enforced standard for how the SDK automatically detects an expired token and replaces it.
Because different APIs communicate that in different ways, the `AccessTokenExpiredException`
exception exists, shown below:
```java
public void someOperation(@Connection SalesforceRestClient client) {
Response response = client.performSomeOperation();
if (response.getStatusCode() == 401) {
throw new AccessTokenExpiredException();
}
}
```
This example uses an imaginary REST client to perform an operation:
- It assumes that this REST client was created through a ConnectionProvider annotated with
`@ClientCredentials`.
- It performs the operation and receives a Response object that contains information about the HTTP
call.
- The example assumes that a status code of 401 (`UNAUTHORIZED`) means that the token is expired.
- It throws the AccessTokenExpiredException.
When the SDK detects this exception, it automatically performs the refresh dance and retries the
operation with a new access token. As noted earlier, different APIs notify you of an access token
expiration in different ways. Some give you clients that throw exceptions, while others give you
custom messages. You should research the remote API to determine the best way to account for this.
### Invalidating Access Tokens
Multitenancy implies the ability to invalidate the access token of a particular resourceOwnerId,
causing the associated token information to be deleted. To invalidate an access token, the SDK
automatically adds an operation called `unauthorize` to every OAuth-enabled connector or module.
Given the following example, you might invalidate the token obtained like this:
```java
```
Note that this operation doesn’t invalidate the token on the service provider. It removes the
service provider from Mule’s caches and Object Stores.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, config, configuration, override, parameter
---
# Configuration Overrides
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
A parameter in your configuration that serves as a _global default_ specifies a default value or
behavior for other operations and sources to use. For components in an app to override the value of
that parameter, you can use `@ConfigOverride`.
## What is a Configuration Override?
This feature binds a parameter from a source or operation to a parameter in a configuration. When a
parameter is annotated with `@ConfigOverride`, but a value is not specified for it through the DSL,
the configuration value for the parameter with _exactly_ the same name will be injected on it.
The `@ConfigOverride` annotation can be applied to an argument of an operation method or to a field
of a source. However, it cannot be used on configurations or connections.
For example, assume that a parameter is declared in your configuration like this:
```java
@Parameter
@Optional(defaultValue = "10")
int maxRetries;
```
Also assume that the above configuration is used in an operation:
```java
public void request(@Config ConfigType config, @ConfigOverride int maxRetries)
// ...
}
```
The `maxRetries` parameter in the `request` operation above can receive its value in a few ways:
- The default value specified in the `maxRetries` parameter configuration is used when the operation
and configuration (shown in the XML below) _do not_ provide a value for `maxRetries`.
```xml
```
In the operation, the `maxRetries` parameter will take the default value of `10`.
- The value provided for `maxRetries` in the configuration (shown below) is used when the value for
the parameter is not specified in the operation but is explicit in the configuration.
```xml
```
In the operation, `maxRetries` will take the value `2`.
- The value provided for the `maxRetries` parameter in the operation is used when this parameter is
explicitly added to the DSL.
```xml
```
In the operation, the `maxRetries` parameter takes the value `5`.
Note that this feature does not change the values set in the configuration. It only injects the
configuration values into the parameters or retains the specified values.
## Configuration Override Requirements
There are a couple of requirements for overriding configuration parameters:
- The name and type of the parameter in the configuration must be the same as the one that is
annotated with `@ConfigOverride`.
- If an operation has a parameter that is annotated with `@ConfigOverride`, it must also have the
corresponding configuration as parameter.
- If a source has a field that is annotated with `@ConfigOverride`, it must also have the
corresponding configuration as a field.
## Configuration Override Parameter within Parameter Groups
This annotation can also be used to reference a `Parameter` that belongs to a `ParameterGroup`
within a configuration, for example:
```java
public class ConfigType{
@ParameterGroup(name = "Strategy")
private RetryStrategy retryStrategy;
// ... Parameter getters
}
```
```java
public class RetryStrategy{
@Parameter
private int maxRetries;
@Parameter
private String retriesExhaustedMessage;
// ... Parameter getters
}
```
This operation uses the `@ConfigOverride` that references `maxRetries` inside the `RetryStrategy`
class:
```java
public void request(@Config ConfigType config, @ConfigOverride int maxRetries)
// ...
}
```
## Configuration Override with POJOs
Your configuration can override any parameters that are POJOs. The content of the POJO parameter in
the operation or source will be totally defined by the configuration or totally defined by the
operation. This means that you cannot define a partially populated POJO and expect the rest of the
POJO to have the configuration values injected.
The logic to decide which values to use is the same as if it were a simple Java type.
## Configuration Parameter without a Default Value
An optional configuration parameter does not have a default value, so its value will default to null
for any operation or source parameter that references it with `@ConfigOverride`.
The parameter in this example is declared in the configuration:
```java
@Parameter
@Optional
private String retriesExhaustedMessage;
```
In the next example, an operation has configuration and configuration override parameters:
```java
public void request(@Config ConfigType config, @ConfigOverride String retriesExhaustedMessage)
// ...
}
```
If `retriesExhaustedMessage` is not specified in the configuration and the operation, its value will
be null.
## Configuration Override Example
This section provides is a simplified example that uses `@ConfigOverride`.
Here is the definition of the Configuration:
```java
@Configuration(name = "config")
@Operations({AmqpConsume.class, AmqpPublish.class, AmqpPublishConsume.class, })
public class AmqpConfig {
@Parameter
@Expression(NOT_SUPPORTED)
@Optional(defaultValue = "*/*")
private String contentType;
@Expression(NOT_SUPPORTED)
@ParameterGroup(name = "Consumer Config", showInDsl = true)
private AmqpConsumerConfig consumerConfig;
// ... All parameter getters
}
```
The `AmqpConsumerConfig` class has parameters that will be referenced by the `@ConfigOverride`
annotation in this example:
```java
public final class AmqpConsumerConfig {
@Parameter
@Optional(defaultValue = "IMMEDIATE")
@Expression(NOT_SUPPORTED)
private AckMode ackMode;
@Parameter
@Optional(defaultValue = "false")
@Expression(NOT_SUPPORTED)
private boolean noLocal;
@Parameter
@Optional(defaultValue = "false")
@Expression(NOT_SUPPORTED)
private boolean exclusiveConsumers;
@Parameter
@Optional(defaultValue = "4")
@Expression(NOT_SUPPORTED)
private int numberOfConsumers;
// ... All parameter getters
}
```
This source has an `AmqpConfig` and parameters with the `ConfigOverride` annotation:
```java
@Alias("listener")
@EmitsResponse
@MetadataScope(outputResolver = AmqpOutputResolver.class)
public class AmqpListener extends Source {
@Connection
private ConnectionProvider connectionProvider;
private AmqpTransactionalConnection connection;
@Config
private AmqpConfig config; (1)
@Parameter
private String queueName;
@Parameter
@ConfigOverride
private AckMode ackMode; (2)
@Parameter
@ConfigOverride
private int numberOfConsumers; (2)
@Parameter
@Optional
private String consumerTag;
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
// ...
}
// ...
@Override
public void onStop() {
// ...
}
// ...
}
```
1 Configuration that specifies the values that override the @ConfigOverride annotated parameters. 2 Parameter that if not specified in the operation will inherit the configuration value of the parameter with exactly the same name. Note that the parameters with these names belong to a ParameterGroup.
This example shows how the override behaves:
```xml
(1)
(2)
```
1 In the configuration, numberOfConsumers is explicitly set to 16, but ackMode takes the default value. 2 In the source, numberOfConsumers is specified, so it will take the value 1. ackMode is not specified, so it will take the value from the config, which is IMMEDIATE.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, security, oauth
---
# Configuring an OAuth-Enabled Connector or Module
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
An important aspect of OAuth-enabled connectors or modules is how to use them. As much as the SDK
does to hide the complexities of the OAuth protocol, things like the OAuth dance are unavoidable.
The SDK’s approach to this problem is to standardize the experience of all OAuth modules to keep
simplifying the user experience.
This section discusses the steps a user must take to use the module.
## Synthetic Parameters
In addition to everything explicitly defined in the Connection Provider, the SDK automatically adds
some extra parameters and injects the proper behavior for them.
Parameter Name Required Expressions Default Value Description resourceOwnerId
NO
SUPPORTED
N/A
To support multi-tenancy, users can specify the ID of the tenant that owns the associated access and refresh tokens. When performing the authorization dance, this value will provide the ID of the obtained token. When a component needs to obtain a new connection, it acts as a default owner ID to use.
consumerKey
YES
NOT_SUPPORTED
N/A
The OAuth consumerKey as registered with the service provider.
consumerSecret
YES
NOT_SUPPORTED
N/A
The OAuth consumerSecret as registered with the service provider.
authorizationUrl
NO
NOT_SUPPORTED
Value provided in the `@AuthorizationCode annotation.
The service provider’s authorization URL.
accessTokenUrl
NO
NOT_SUPPORTED
Value provided in the @AuthorizationCode annotation.
The service provider’s access token URL.
state
NO
REQUIRED
N/A
A String value that you send when the OAuth dance is initiated and that is returned back by the service provider with the token callback. It is used to correlate dance initiations with token callbacks. The most common use case for this attribute is multi-tenancy.
scope
NO
NOT_SUPPORTED
Value provided in the @AuthorizationCode annotation.
The OAuth scopes to be requested during the dance. If not provided, it will default to those in the annotation.
listenerConfig
YES
NOT_SUPPORTED
N/A
A reference to an <http:listener-config /> to be used in order to create the listener that will catch the access token callback endpoint.
callbackPath
YES
NOT_SUPPORTED
N/A
The path of the access token callback endpoint.
authorizePath
YES
NOT_SUPPORTED
N/A
The path of the local HTTP endpoint that triggers the OAuth dance.
externalCallbackUrl
NO
NOT_SUPPORTED
N/A
If the callback endpoint is behind a proxy or should be accessed through a non-direct URL, use this parameter to tell the OAuth provider the URL it should use to access the callback.
resourceOwnerId
YES
SUPPORTED
N/A
The resourceOwnerId that each component should use if it does not reference otherwise.
objectStore
NO
NOT_SUPPORTED
N/A
A reference to the Object Store to user for storing each resource owner ID’s data. If not specified, the runtime will automatically provision the default one.
before
NO
NOT_SUPPORTED
N/A
The name of a flow to be executed right before starting the OAuth dance (see Before Flow ).
after
NO
NOT_SUPPORTED
N/A
The name of a flow to be executed right after an accessToken has been received (see After Flow )
## About the Use of Expressions
The table above identifies many of the synthetic parameters that accept expressions. Using
expressions there has the same effect as using expressions in a regular parameter: It will turn the
configuration into a dynamic one.
## OAuth Connection DSL
This is what the generated DSL looks like:
```xml
```
- Regular and OAuth parameters are all shown at the connection provider level, just like in any
other provider.
- The parameters related to the Authorization Code Grant type (`consumerKey`, `consumerSecret`,
`authorizationUrl`, `accessTokenUrl`, `localAuthorizationHost`, `localAuthorizationPort`,
`localAuthorizationPath`, `before`, `after`, `scope`, `defaultResourceOwnerId`) will be placed on
a child element called ``.
- The parameters related to the callback will be placed in a child element called
``.
- The parameters related to object store will be placed in a child element called
``.
## Custom Logic Before and After the Dance
End users often want to execute some random logic just before initiating the OAuth dance or right
after it has been completed. Use cases include notifying an external system that a given owner ID
has been successfully on-boarded, keeping activity logs, and so on.
The authorization process is triggered by hitting an automatically created endpoint, so the
`` child element has the `before` and `after` parameters.
These optional parameters specify the name of a `` to be invoked before or after the OAuth
dance.
### Before flow
The before flow will be executed just before the OAuth dance is started. The payload of the event
sent to that flow will be an instance of `AuthorizationCodeRequest`, which is an immutable POJO that
looks like this:
```java
public interface AuthCodeRequest {
/**
* @return The id of the user being authenticated
*/
String getResourceOwnerId();
/**
* @return The scopes that were requested
*/
Optional getScopes();
/**
* @return The OAuth state that was sent
*/
Optional getState();
/**
* @return The external callback url that the user configured or {@link Optional#empty()} if none was provided
*/
Optional getExternalCallbackUrl();
}
```
In this flow, the user can perform any custom logic as needed. In particular, the user can set flow
variables (see [After Flow](#after_flow)).
### After Flow
The after flow is executed right after the access token has been received and stored. This flow is
executed with an event that is equivalent to what came out of the before flow (or a blank event if
no before flow was defined), except for the payload, which is replaced by the same
`AuthorizationCodeState` object that is injected in the `ConnectionProvider`. However, any variables
previously set are still there (or will be empty if no before flow was defined).
## Configuring a Custom ObjectStore
The obtained access tokens are stored in an `ObjectStore`. By default, the SDK will store them in
the apps’s default store, but users can define their own custom one, for example:
```xml
(2)
```
1 Define your custom store. 2 Reference it on your module’s config.
## Next Step
[Performing the OAuth Dance with an OAuth-Enabled Connector or Module](https://docs.mulesoft.com/mule-sdk/latest/oauth-dance)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Content Parameters
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Consider the following operation (pseudocode):
```xml
```
Notice that the parameters that compose operations often play different roles.
## Behavior Parameters
These parameters manage settings that determine how the operation is going to behave. In the example
above, the `overwrite` parameter configures the action to take if the file already exists. The
`path` parameter indicates where to write the content. Both parameters configure the operation, but
because this is a Write operation, they do not represent the main concept, which is the data to be
written.
Some operations are exclusively formed by behavior parameters, for example:
```xml
```
Both parameters are behavioral because the operation does not take any content. The content is in
the file that is copied.
## Content Parameters
If you consider the explanation of behavior parameters above, the definition of a content parameter
is obvious. In the `file:write` example above, the content is a `@Content` parameter.
Content parameters have the following characteristics:
- They must accept expressions. Both SUPPORTS\_EXPRESSIONS and EXPRESSION\_REQUIRED are supported,
but compilation will fail if `@Expression(NOT_SUPPORTED)` is used.
- Each content parameter can embed its own DataWeave script to generate the content.
- Content parameters always translate to the DSL as a text element, precisely to enable the embedded
DataWeave script.
Consider the `file:write` operation again, this time with content parameters. Suppose that you are
using this operation in a flow, and the message payload is JSON that you want to store as XML.
```xml
```
In the module’s code, the `content` parameter is marked with the `@Content` annotation:
```java
public void write(String path, @Content InputStream content) {
// write code
}
```
## Primary Content Parameter
In some cases, an operation has many content parameters, for example:
```xml
#[body..]
#[uri-params …]
#[you get the picture..]
```
As you can see, you can have as many content parameters as you want, which means that the `@Content`
annotation can be used on more than one method argument. However, the `body` parameter is still more
important than the rest. Although headers are also part of the content sent in the HTTP request,
those headers are complementary to the body that is sent. So, when an operation has more than one
content parameter, one of them has to be marked as the primary content by using
`@Content(primary = true)`.
The primary content parameter has all of the same characteristics as the regular content parameters,
plus these:
- They are automatically made optional.
- They automatically default to `#[payload]`.
These two features are automatically added to the parameter by the runtime.
> [!TIP] Going back to the `file:write` example in which there was only one content parameter: Is it
> primary? _YES_. When an operation has only one content parameter, the SDK will automatically
> consider it as primary. That means that the content parameter in the `file:write` operation is
> automatically made optional and defaults to `#[payload]`. This helps to enforce consistency across
> modules.
## Changing the Default of a Primary Content
There are edge cases in which a primary content should default to something other than the payload.
This tends to happen more when the operation has only one content parameter, and that parameter is
not always needed. For example, consider the Database connector. The input parameters of a Select
query are primary content, but not all queries require input parameters. So the real default should
be an empty map.
You can do that by combining the `@Content` and `@Optional` annotations. For example, the following
sets the default to an empty map:
```java
public List select(@Text String sql,
@Optional(defaultValue="#[{}]") @Content Map inputParameters) {
// select
}
```
You can also set the content parameter as optional, with no default:
```java
public List select(@Text String sql,
@Optional @Content Map inputParameters) {
// select
}
```
Finally, you can combine the `@Content` annotation with `@NullSafe`, for example:
```java
public List select(@Text String sql,
@Optional @NullSafe @Content Map inputParameters) {
// select
}
```
> [!TIP] The first and third examples are equivalent. However, the `@NullSafe` option is preferred
> because it gives the module’s user a better experience. Having `#[{}]` as an explicit default
> might be confusing for inexperienced Mule users.
## Embedding Content Parameters in Parameter Groups
The content parameters in the [`http:request`](#primary_content_parameter) operation above are
contained in an element called `request-builder`. For usability reasons, the author of the connector
chose to group all the request-related attributes into an enclosing object. This is supported by the
SDK in the following manner:
```java
public void request(String path, @ParameterGroup(showInDsl=true) HttpRequestBuilder requestBuilder) {
// request
}
```
As you can see, there are no content parameters here. However, if you look inside the
`HttpRequestBuilder` class, you see `@Content` annotations:
```java
public class HttpRequestBuilder {
@Parameter
@Content(primary = true)
private InputStream body;
@Parameter
@Content
@NullSafe
private Map uriParams;
@Parameter
@Content
@NullSafe
private Map uriParams;
}
```
> [!TIP] Removing the `@ParameterGroup` annotation from the `HttpRequestBuilder` argument in the
> sample request operation will result in a compilation error. `@Content` is not allowed in complex
> types.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, context, inject, event, location
---
# Context Information Injection
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
To get information about the context in which an operation or source is being processed, you can add
parameters to the operation or source. The parameters do not appear in the UI, but they are injected
by the SDK into the runtime.
## Component Location
When executing an operation or using a source, you might want to have some context about the
location of the component, mostly for logging purposes. To achieve this, you can define a
`ComponentLocation` as a parameter, and it will be injected.
This examples shows how to log the component location when starting a source:
```java
@Alias("listener")
public class HttpListener extends Source {
private static final Logger LOGGER = getLogger(HttpListener.class);
@Connection
private ConnectionProvider serverProvider;
private ComponentLocation location;
@Parameter
private String path;
private HttpServer server;
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
server = serverProvider.connect();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Starting HTTP Listener %s on path %s", location.getLocation(), path);
}
server.listen(path);
}
// ...
}
```
This example shows how to log the component location in an operations (non-source) context:
```java
//ComponentLocation is added as a parameter when used in an operation
public String sayHi(String person, String q, ComponentLocation location) {
// ...
System.out.println("Location: " + location.getLocation());
// ...
}
```
## Tracking an Event
**Available since version 1.1**
To be able to trace an event through logs, you can use a `CorrelationInfo` parameter in your
operations and source callback. This correlation info provides the event ID and correlation ID of
the event that is processed.
You simply need to add a `CorrelationInfo` parameter to your operation method or source callback.
The instance will be populated with the event information the method or callback runs.
This simplified example shows how to use `CorrelationInfo`:
```java
public class ObjectStoreOperations {
private static final Logger LOGGER = getLogger(ObjectStoreOperations.class);
// ...
@Throws(StoreErrorTypeProvider.class)
public void store(String key,
@Content TypedValue value,
ObjectStore objectStore,
CorrelationInfo correlationInfo) {
objectStore.store(key, value);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Object stored with key: %s .The event id is: %s", key, correlationInfo.getEventId());
}
}
// ...
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, functions, function
---
# Contributing Functions with Mule SDK
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
DataWeave is the main expression language in Mule 4, and the Mule SDK is also aligned with that
view. This allows you to contribute functions to DataWeave from your module’s code in a similar
fashion that you code a Mule [Operation](https://docs.mulesoft.com/mule-sdk/latest/operations). Using custom functions allows you to reuse
code in a new way, providing extra functionality in a single Module with very little overhead
regarding how they are declared compared to a Mule operation.
## Declaring a Function
At Extension level, you can use the `@ExpressionFunctions` annotation to reference the classes that
contain the public methods representing the DataWeave functions. This method’s code is executed
directly from DataWeave scripts using it name as identifier:
```java
@Extension(name = "Docs")
@ExpressionFunctions(DocsFunction.class)
public class DocsModule {
}
```
In the `DocsFunction` class, this example defines the following method:
```java
public Object xpath(@Optional(defaultValue = PAYLOAD) InputStream item,
String expression){
try {
return xPathFactory.newXPath().evaluate(expression, documentBuilder.parse(item));
} catch (Exception e) {
return null;
}
}
```
This `xpath` function can now be used from inside a DataWeave script, referencing it _inside our
Module’s namespace_.
The next example reads XML and sets an XPath filter using the new `xpath` function:
```xml
35]/title")]"/>
```
To view the actual implementation of the simplified example shown above, refer to
[XPathFunction.java](https://github.com/mulesoft/mule-xml-module/blob/1.3.3/src/main/java/org/mule/module/xml/internal/xpath/XPathFunction.java).
## Restrictions: Config-less and Connection-less
By definition, functions are not allowed to depend on or receive a particular
[Configuration](https://docs.mulesoft.com/mule-sdk/latest/configs) or [Connection](https://docs.mulesoft.com/mule-sdk/latest/connections).
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, forward compatibility, DoNotEnforceMinMuleVersion, version propagation
---
# Controlling Version Propagation
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
By default, when a component uses an SDK API, it inherits that API’s minimum Mule version
requirement. However, some APIs are designed to enhance functionality without affecting runtime
compatibility, and in some cases you can override this inheritance behavior using the
`@DoNotEnforceMinMuleVersion` annotation.
## APIs That Don’t Affect Minimum Mule Version
Some SDK APIs are annotated with `@DoNotEnforceMinMuleVersion`, which means using them doesn’t raise
your component’s minimum Mule version. These are typically APIs that:
- Provide design-time enhancements (sample data, metadata)
- Add semantic information for tooling (semantic terms, display annotations)
- Enable optional features that degrade on earlier Mule runtime versions
For example, annotations like `@SampleData`, `@DisplayName`, and semantic annotations such as `@Url`
or `@Password` don’t affect your component’s minimum Mule version, even though they were introduced
in specific runtime versions.
## Prevent Version Propagation
Consider using `@DoNotEnforceMinMuleVersion` to prevent version propagation if:
- You use a newer API but provide equivalent fallback behavior for earlier Mule runtime versions
- You use runtime version checking to conditionally enable features (see
[Forward Compatibility Patterns](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-patterns))
- The API you’re using is optional and its absence doesn’t break core functionality
Do not use this annotation to lower your component’s minimum Mule version without implementing
proper fallback behavior. Doing so can cause runtime errors when users deploy to earlier Mule
runtime versions.
### Prevent Version Propagation With @DoNotEnforceMinMuleVersion
Some SDK APIs automatically raise your component’s minimum Mule version when used. If you’ve
implemented fallback behavior for earlier Mule runtime versions, use `@DoNotEnforceMinMuleVersion`
to prevent version propagation.
```java
import org.mule.sdk.api.annotation.DoNotEnforceMinMuleVersion;
import org.mule.sdk.api.annotation.param.Parameter;
public class MyOperations {
public void myOperation(@DoNotEnforceMinMuleVersion @Parameter SomeNewType input) {
// This parameter type requires Mule 4.12.0, but we have fallback logic
// so we don't want it to raise the operation's Minimum Mule Version
}
}
```
> [!IMPORTANT] Don’t use this annotation if you haven’t verified that your component works correctly
> on earlier Mule runtime versions. If the component depends on the API being fully functional,
> don’t suppress version propagation.
## See Also
- [Working with Minimum Mule Versions](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-min-mule-version)
- [Forward Compatibility Patterns](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-patterns)
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, config, configuration
---
# Creating Configuration Objects
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Configurations are a set of configurable parameters that affect the overall behavior of your module.
All modules are required to have at least one configuration, but you can define as many as needed.
Different configurations might not only provide a different set of parameters but also specify their
own set of operations, sources, and connection providers that are only available when using that
configuration.
> [!NOTE] The following examples contain classes mostly from the
> [Mule Extensions API](https://github.com/mulesoft/mule-extensions-api). Some classes, such as the
> `MessageSources.class`, are made up for the following examples.
## Defining Single Configuration Modules
The simplest of cases is that of a Module that has only one configuration. For convenience, you can
use the same class that you previously annotated with `@Extension` for that, for example:
```java
@Extension(name="singleConfig")
@Operations(Operations.class)
@Sources(MessageSources.class)
@ConnectionProviders({BasicAuthConnection.class, OAuthConnection.class})
public class SingleConfigModule {
@Parameter
private String someParameter;
@Parameter
private Integer numericParameter;
public String getSomeParameter() {
return someParameter;
}
public String getNumericParameter() {
return numericParameter;
}
}
```
The example above shows the full skeleton of a module with a single configuration. You can see how
the same class that declares the extension with all its operations, sources, connections, and so on,
is also enriched with `@Parameter` annotated fields, which will translate into the configuration’s
parameters.
When another component, such as an operation or source, requires access to the configuration, it
will do so through instances of the `SingleConfigModule` class.
## Externalizing Single Configuration Object
Depending on how you want to organize your code, you might want to have a single configuration
object without reusing the `@Extension` annotated class. Reasons for doing this might range from
maintainability (you think that you might want to add more configurations in the future), separation
of concerns, or simply personal preference.
You can use the `@Configurations` annotation to do that. The same reworked example looks like this:
```java
@Extension(name="singleConfig")
@Configurations(Config.class) (1)
public class SingleConfigModule {
}
@Configuration(name="config") (2)
@Operations(Operations.class)
@Sources(MessageSources.class)
@ConnectionProviders({BasicAuthConnection.class, OAuthConnection.class})
public class Config {
@Parameter
private String someParameter;
@Parameter
private Integer numericParameter;
public String getSomeParameter() {
return someParameter;
}
public String getNumericParameter() {
return numericParameter;
}
}
```
1 Reference a Config class using the @Configurations annotation. 2 Define a class that acts as a configuration and defines the parameters, plus all the other components such as operations, connections, and so on.
> [!TIP] Notice that the `@Configuration` annotation requires you to give the configuration a name.
> For modules with only one configuration, the name `config` is recommended.
## Defining Multiple Configurations
Let’s explain this one using the HTTP connector as an example.
There are two sides to implementing the HTTP protocol: to listen for requests and to send requests.
Each of these aspects not only requires very different sets of parameters, it also turns out that:
- To listen for request, you need to define an ` ` element that acts as a message
source.
- To send a request, you need an ` ` element that acts as an operation.
Because an application can contain many listener elements, the elements will only work when paired
with an ` ` that contains general settings about how the connection is to be
established and other behavioral parameters. The same happens with the requester operation, which is
paired with an ` ` element.
The code looks like this:
```java
@Extension(name="http")
@Configurations({HttpListenerConfig.class, HttpRequesterConfig.class}) (1)
public class HttpConnector {
}
@Configuration(name="listener") (2)
@ConnectionProviders(HttpListenerConnection.class)
@Sources(HttpListener.class)
public class HttpListenerConfig {
/**
* Base path to use for all requests that reference this config.
*/
@Parameter
@Optional
@Expression(NOT_SUPPORTED)
private String basePath;
public String getBasePath() {
return basePath;
}
}
@Configuration(name="requester") (3)
@Operations(HttpRequester.class)
@ConnectionProviders(HttpRequesterConnection.class)
public class HttpRequesterConfig {
// the requester parameters
}
```
1 The @Extension annotated class defines the two configurations. 2 The HttpListener class defines the inbound connection and the message source that is exclusive to the listener feature. 3 The HttpConfig class defines the request operation and the outbound connection type.
> [!TIP] Notice that this time, the name used in the `Configuration` annotation doesn’t follow a
> specific default, but instead a descriptive name is used.
## Getting the Configuration Name
For logging or debugging reasons, you may want to know the name that this config instance has on the
application. For this, you can use the `@RefName` annotation. This annotation must be used on fields
of type `String`, and no two fields in the same class should bear this annotation. Here is an
example of how to use it.
In this example, you can see how to log the name of our component when it is getting initialized.
This way, you can have traceability of the different config instances.
```java
@Configuration(name="config")
@Operations(Operations.class)
public class Config implements Initialisable {
private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
@RefName (1)
private String configName;
@Parameter
private String someParameter;
public String getSomeParameter() {
return someParameter;
}
@Override
public void initialise(){
LOGGER.debug("Initializing config with name: " + configName);
}
}
```
1 The @RefName annotation signals that the name of the configuration used in the app should be injected to the field configName.
You can see a concrete example of a DSL to see what would happen:
```xml
```
In this case, the variable `configName` would take the value "exampleConfig". When this config is
initialized, you will see this reflected on the logs with the message:
`Initializing config with name: exampleConfig`
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers
---
# Creating Message Sources with the Mule SDK
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Operations are components that process a message and generate a result. Message sources are
components that receive or generate new messages to be processed by the Mule Runtime.
Examples of message sources:
- An HTTP listener
- A File watcher
- A JMS/AMQP listener that retrieves messages from a queue to which the user previously subscribed
- Salesforce Streaming API
## Similarities Between an Operation and a Message Source
Operations and message sources have:
- Parameters
- A return type
- Name and Description
- Reconnection capabilities
## Differences Between an Operation and a Message Source
Operations Message Sources Operations process messages.
Sources create messages and push them to a flow.
The lifecycle of operations is tied to the containing flow.
Message sources can be started and stopped independently of the containing flow.
Parameters of operations have the option of accepting expressions (the default).
Sources have a clear definition of which parameters can accept expressions and which cannot. Only parameters that are part of generating a response can accept expressions.
An operation can have a lifecycle, but its parameter values are not available or not needed.
A Message source must have start() and stop() phases, and they might require access to the parameter values.
A connection is obtained each time the operation is executed.
A connection is obtained each time the message source is started or when reconnection happens.
## Implementing a Message Source through the Mule SDK
The differences listed above make it difficult to define a way to implement a message source in a
way 100% consistent with the model defined for operations.
Sources are required to extend the `Source` class, which takes two generics: one for the type of the
generated event payload, the other for the type of the Attributes:
```java
@Alias("listener")
@EmitsResponse
public class HttpListener extends Source {}
```
> [!TIP] You can use the `@Alias` annotation to force a name. Otherwise, the SDK will infer one.
## Next Step
- [Defining Parameters in a Message Source](https://docs.mulesoft.com/mule-sdk/latest/sources-parameters)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, routers, router
---
# Creating Routers with Mule SDK
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Conceptually, routers are [operations](https://docs.mulesoft.com/mule-sdk/latest/operations) that can receive many executable routes and a set
of parameters that handle the execution of one, all, or none of them.
Routes should be used for receiving multiple possible paths of execution, where the parameters of
the route can be used to decide whether or not the contained processors should be executed.
Stereotypes can be used in the route declaration to define are stereotypes for the contained chain.
Routes don’t allow complex parameters to be defined inline because the DSL content of the element
will be exclusive of the parameterized [operations](https://docs.mulesoft.com/mule-sdk/latest/operations).
## Defining a Route
First you need to declare at least one route in your module by extending the `Route` base class:
```java
public class WhenRoute extends Route {
@Parameter
@Optional
private boolean shouldExecute;
public boolean shouldExecute() {
return shouldExecute;
}
}
```
## Declaring the Router
Next, you need to declare the router method as one of the module’s [operations](https://docs.mulesoft.com/mule-sdk/latest/operations). Any
operation receiving at least one `Route` implementation along with a `RouterCompletionCallback` is
registered as a router:
```java
@Extension(name = "Docs")
@Operations(ChoiceRouter.class)
public class DocsModule {
}
```
The `ChoiceRouter` class defines the following method:
```java
public void choice(WhenRoute when,
@Optional OtherwiseRoute otherwise,
RouterCompletionCallback callback) {
if (when.shouldExecute()) {
when.getChain().process(callback::success, (error, previous) -> callback.error(error));
} else if (otherwise != null && otherwise.shouldExecute()) {
otherwise.getChain().process(callback::success, (e, r) -> callback.error(e));
} else {
callback.success(Result.builder().build());
}
}
```
Above, you can see how a router is declared and how the routes are conditionally executed based on
their configuration. Route execution is performed through their chain, exactly as though each route
was an scope by itself.
Using the router consists of configuring the router parameters and then adding each route
declaration with its own parameters:
```xml
```
This executes the `http:request` operation contained by the `when` route whenever the `payload`
isn’t `null`. If a `null` `payload` arrives, the fallback `otherwise` route executes intead.
## Routers with a Dynamic Number of Routes
Routers can declare a parameter that represents a dynamic list of routes. This enables you to create
routers that accept zero, one, or many route instances, rather than a fixed set.
To declare a list of routes, define a router parameter typed as `List` in the router
operation:
```java
public void choice(List whens,
RouterCompletionCallback callback) {
...
}
```
The handling of the elements in the list is similar to the single-route approach. The code should
select the route or routes to execute and then run them. The implementation decides whether to call
one, none, or many routes, and whether many calls are sequential or parallel.
Using the router involves configuring the router parameters and then adding each route declaration,
with its own parameters within its wrapper element:
```xml
```
This executes the `http:request` operation in the first `when` route whenever the `payload` isn’t
`null`. If a `null` `payload` arrives, the second `when` route executes instead.
## Void Routers
**Available since version 1.1**
You might need to create a router that at the end of its execution leaves the event and message the
same as it was before the execution of the router. This type of router is called Void Router.
To implement a Void Router, the method needs to have an argument of the `VoidCompletionCallback`
type instead of `RouterCompletionCallback`. You use this callback the same was as before (with the
`success` and `error` methods), except in this case, `success` doesn’t receive any parameter.
## Restrictions
The following restrictions apply.
### Config-less and Connection-less
Routers have some restrictions that differentiate them from [operations](https://docs.mulesoft.com/mule-sdk/latest/operations). By definition,
routers aren’t allowed to depend on or receive a particular configuration or connection.
### Always Non-Blocking
All routers have to be defined as a `void` method receiving a `RouterCompletionCallback` for
communicating its result. This means that all routers are non-blocking by default.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, scopes, scope, components
---
# Creating Scopes with Mule SDK
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Scopes are similar to [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations), but their execution includes the execution of other
child [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations). This means that a Scope is basically an operation that receives one
or more arguments that are simple [Parameters](https://docs.mulesoft.com/mule-sdk/latest/parameters) along with a single `Chain` component and
the `CompletionCallback`.
A `Chain` represents the child [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) that you declare inside the Scope and
provide an abstraction to execute them.
## Declaring a Scope
You can see the basic structure of a Scope with this decorator example. It has the `Chain` to be
executed and the `CompletionCallback` to invoke once the scope execution is done _(yes, all Scopes
are declared as [Non-Blocking Operations](https://docs.mulesoft.com/mule-sdk/latest/non-blocking-operations))_:
```java
@Extension(name = "Docs")
@Operations(LogDecorator.class)
public class DocsModule {
}
```
```java
public void logDecorator(Chain operations,
CompletionCallback callback) {
LOGGER.debug("Invoking child operations")
operations.process(
result -> {
LOGGER.debug(result.getOutput());
callback.success(result);
},
(error, previous) -> {
LOGGER.error(error.getMessage());
callback.error(error);
});
}
```
Of course, if you receive a `Chain` of [Operation](https://docs.mulesoft.com/mule-sdk/latest/operations), you need to execute them in some
way, and that is what the `process(successCallback, errorCallback)` does. With it, the example
executes the `Chain` in a non-blocking fashion and listens for the results in case of success or
error. Here, the `successCallback` is called with the execution result when a successful execution
is completed by _all_ the [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) in the `Chain`. The `errorCallback` will be
called if an error occurs during the execution of _any_ child [Operation](https://docs.mulesoft.com/mule-sdk/latest/operations), with both the
error and the last successful result as arguments.
Here is how you use the scope in a Mule app:
```xml
```
This executes the `http:request` child operation wrapped by the `LOGGER` invocations. Any number of
[Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) can be executed inside the scope, including other scopes or routers.
## Adding Parameters
Scopes can receive other simple `@Parameters` and `@ParameterGroups`. They are _simple_ because
Scopes are not allowed to receive _complex_ parameters that are declared as child elements. For
example, if you want to customize the log level of the decorator, you will be able to receive that
as a Parameter:
```java
public void logDecorator(@Optional(defaultValue="true") boolean debug,
Chain operations,
CompletionCallback callback) {
if (debug){
LOGGER.debug("Invoking child operations")
}
operations.process(
result -> {
Object message = result.getOutput();
if (debug){
LOGGER.debug(message);
} else {
LOGGER.info(message);
}
callback.success(result);
},
(error, previous) -> {
LOGGER.error(error.getMessage());
callback.error(error);
});
}
```
With a minimal change in the Scope’s API:
```xml
```
By default, a `Chain` is executed using the Message that was received by the container Scope, but
other definitions of the `process` method allow the user of the scope to customize the `payload` and
`attributes` that will be used to execute the `Chain`.
## Using Stereotypes
`Stereotypes` can be used to limit the [Operation](https://docs.mulesoft.com/mule-sdk/latest/operations) that are allowed to exist inside a
`Chain`, which enforces consistency in its usage. Only the [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) that have the
given `Stereotypes` can be declared inside the Scope.
```java
public void assertAll(@AllowedStereotypes(AssertionStereotype.class) Chain assertions,
@Optional boolean failOnError,
CompletionCallback callback) {
assertions.process(
result -> {
callback.success(Result.builder().output(true).build());
},
(error, previous) -> {
if (failOnError){
callback.error(error);
} else {
callback.success(Result.builder().output(false).build());
}
});
}
```
```xml
```
## Config-less and Connection-less
Scopes have some restrictions that differentiate them from [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations). By definition,
Scopes are not allowed to depend on or receive a particular [Configuration](https://docs.mulesoft.com/mule-sdk/latest/configs) or
[Connection](https://docs.mulesoft.com/mule-sdk/latest/connections).
## Only One Chain
The `Chain` component is key in the definition of a Scope, so it is _required_ to have one and
_only_ one `Chain` argument.
## Always Non-Blocking
All Scopes must be defined as a `void` method receiving a `CompletionCallback` for communicating
their Result, which means that all the Scopes are non-blocking by default.
See [Non-Blocking Operations](https://docs.mulesoft.com/mule-sdk/latest/non-blocking-operations).
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Custom Static Metadata
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
**Available since version 1.1**
We’ll use Static Metadata to reference the Metadata that is known at compile time an available from
the types in the connector’s jar. Simple java types are part of this static Metadata, as well as
custom POJOs defined by the developer in its model. The relevant part is that the structure is well
known or can be introspected, without depending on other Parameters.
The advantage of static metadata over dynamic is that, because it does not change, there is no need
to recalculate its structure. This means that the resolution is already done when developing an
application.
When working with simple java types or POJOs as return or parameter types the SDK will create a
proper static type for the element, but when your type is not defined as a java object (e.g. Json
Schema, XSD, etc) you know exactly the structure of the type you are working with, you need to use
the custom static metadata capabilities that the SDK provides.
## XML and JSON Types
Operations may require parameters to be JSON or XML types that follow a certain structure (schema).
It is possible to signal this to DataSense using the proper XSD or JSON schemas.
> [!NOTE] this will only work for `InputStream` and `String` java type parameters.
### JSON Type
To determine the structure of a JSON type, a JSON schema must be provided.
- `@OutputJsonType`
```java
@OutputJsonType(schema = "person-schema.json")
public Result retrievePerson() {
// ...
}
```
- `@AttributesJsonType`
```java
@AttributesJsonType(schema = "resolution-attributes-schema.json")
public Result getSolution() {
// ...
}
```
- @`InputJsonType`
```java
public void addPerson(@InputJsonType(schema = "person-schema.json") InputStream person) {
// ...
}
```
### XML Type
To determine the structure of an XML, you must provide an XSD file and the qualified name that is
used to reference the element to be loaded.
- `@OutputXmlType`
```java
@OutputXmlType(schema = "order.xsd", qname = "shiporder")
public Result retrieveOrder() {
// ...
}
```
- `@AttributesXmlType`
```java
@AttributesXmlType(schema = "order-attributes.xsd", qname = "attributes")
public Result getOrderStatistics() {
// ...
}
```
- `@InputXmlType`
```java
public void createOrder(@InputXmlType(schema = "order.xsd", qname = "shiporder") InputStream order) {
// ...
}
```
## Static Type Resolvers
The way to resolve custom static metadata for input parameters, output payload or output attributes
is very similar and it is shown on the next examples:
On each example, the resolvers extends of an abstract class that implements `StaticResolver`.
`getStaticMetadata` is the method that has to be implemented in order to resolve the metadata.
### InputStaticTypeResolver
To use custom static metadata resolution on the input parameters of an operation, you must annotate
the parameter with `@TypeResolver` and the value for the annotation must be a
`InputStaticTypeResolver`.
This is an example of a `InputStaticTypeResolver`, it must implement the method `getStaticMetadata`:
```java
public class JsonPersonInputStaticTypeResolver extends InputStaticTypeResolver {
@Override
public MetadataType getStaticMetadata() {
ObjectTypeBuilder object = BaseTypeBuilder.create(MetadataFormat.JSON).objectType();
object.id("json-object");
object.addField().key("name").value().stringType();
object.addField().key("last-name").value().stringType();
return object.build();
}
}
```
### OutputStaticTypeResolver
to use custom static metadata resolution on the output payload of an operation, you must annotate
the method with `@OutputResolver` and the output value for the annotation must be a
`OutputStaticTypeResolver`.
This is an example of a `OutputStaticTypeResolver`, it must implement the method
`getStaticMetadata`:
```java
public class CsvOutputStaticTypeResolver extends OutputStaticTypeResolver {
@Override
public MetadataType getStaticMetadata() {
return BaseTypeBuilder.create(MetadataFormat.CSV).objectType().id("csv-object").build();
}
}
```
### AttributesStaticTypeResolver
to use custom static metadata resolution on the output attributes of an operation, you must annotate
the method with `@OutputResolver` and the attributes value for the annotation must be a
`OutputStaticTypeResolver`.
This is an example of a `AttributesStaticTypeResolver`, it must implement the method
`getStaticMetadata`:
```java
public class CsvAttributesStaticTypeResolver extends AttributesStaticTypeResolver {
@Override
public MetadataType getStaticMetadata() {
ObjectTypeBuilder object = BaseTypeBuilder.create(MetadataFormat.CSV).objectType();
object.addField().key("location").value().stringType();
object.addField().key("size").value().numberType();
return object.build();
}
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: parameter, parameters, mule, sdk, dsl, xml, syntax
---
# Customizing the Parameters DSL
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
To provide the best possible experience for the user, customize or limit some aspects of a
component’s parameters. For example, you can hide irrelevant parameters for clarity.
## Receiving Strings As Reference Or As Value
Let’s say we have an operation like the following:
```java
public void send(@Connection MyConnection connection, Object value) {
connection.doSend(value);
}
```
Which will be invoked like this:
```xml
```
By default, Mule assumes that `requestPayload` is a reference to an object in the registry, like a
global list or POJO. If instead we want the extension to actually receive the `requestPayload`
string, we must modify the operation declaration, using the `@ParameterDsl` annotation:
```java
public void send(@Connection MyConnection connection, @ParameterDsl(allowReferences = false) Object value) {
connection.doSend(value);
}
```
This change explicitly disables the use of references, so the operation will receive the string
value.
## Defining How Complex Types Can Be Used
Any Module is able to expose POJOs that conform to the Module API:
```java
// This is the POJO declaration
public class Door {
@Parameter
private boolean isLocked;
@Parameter
private String color;
}
// This is the configuration
public class HouseConfig {
@Parameter
private Door mainDoor;
}
```
When having this kind of parameters, the Module developer has the responsibility to configure how
the `Door` can be used in the DSL. For this, we have the `@TypeDsl` annotation, that allows you to
configure two important things:
- `allowInlineDefinition`: Defines if the POJO (in the example, the `Door`) can be declared inline
for the element that uses it as parameter. If this value is `true`, then the user can declare:
```xml
(1)
(2)
```
1 The config is declared as the container of the parameter 2 A Door is declared inline (in the config)
- `allowTopLevelDefinition`: Defines if the POJO (in the example, the `Door`) can be declared as a
top-level element in the application. If this value is `true`, then the user can declare:
```xml
(1)
(2)
```
1 A Door is declared as a global element of the application 2 The config is declared separately, referencing the global Door element by name with the door-ref attribute
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Customizing the Parameters UI
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The SDK provides a set of annotations used for customizing many aspects of the UI and UX.
## @DisplayName
Specifies a custom label for an element or field to be used in the UI.
## @Example
Sometimes it is helpful to provide a simple example with the values a parameter can take.
```java
@Parameter
@Example("0.0.0.0")
private String port;
```
That parameter will be rendered as:

## @Summary
`@Summary` is for a short description of the purpose of a parameter.
For example, this description can be used in Studio as the text to be displayed while hovering over
the parameter:
```java
@Parameter
@Optional(defaultValue = "SECONDS")
@Summary("Time unit to be used in the Connection Timeout")
private TimeUnit connectionTimeoutUnit;
```
That parameter will be rendered like this:

## @Placement
This annotation enables you to configure these settings:
- A relative order within the group in which the parameter is defined. The value is relative in the
sense that the element with order `10` is above one with value `25`.
- A tab, which is a graphical way to group parameters together. This attribute specifies the name of
the tab in which the parameter should be displayed. It uses a default of "General" is no name is
specified. To display more than one parameter or field in the same the tab, the value for the tab
should be the same for all of them.
In the following example, `foo` and `bar` will be grouped into the same tab named `Advanced`, while
`foobar` will be the only parameter in the default tab.
```java
@Parameter
@Placement(order = 1, tab="Advanced")
private String foo;
@Parameter
@Placement(order = 2, tab="Advanced")
private String bar;
@Parameter
private String foobar;
```
`foo` and `bar` parameters will be rendered in a new tab `"Advanced"` like this:

## @Text
Indicates that a parameter supports a multi-line string input in the UI. This annotation also
affects the DSL, making the annotated parameter a child element with the text as the content of the
element.
Note that this annotation should only be used in parameters of `String` type.
Example
```java
@Parameter
@Optional
@Text
@DisplayName("SQL Query Text")
private String sql;
```
In Studio, the `@Text` will be rendered like this:

`@Text` also affects the DSL of the element that contains the parameter. using it creates a child
element that accepts `CDATA` content. For example, assume that you have this operation:
```java
public void execute(String message) { ... }
```
The DSL for the operation above looks like this:
```xml
```
This example annotates the `message` operation parameter with `@Text`:
```java
public void execute(@Text String message) { ... }
```
So the corresponding DSL looks like this:
```xml
```
## @Path
Marks a parameter as a path to either a file or a directory. This parameter will be displayed in the
UI as a file-picker field.
Note that this annotation should only be used in parameters of `String` type.
This annotation carries information about:
- `type`: Whether the path points to a directory, a file, or any of those.
- `acceptsUrls`: Whether the path parameter supports URLs.
- `acceptedFileExtensions`: A list of file extensions this parameter can handle.
This example accepts a `.txt` resource that can be remote:
```java
@Parameter
@Path(type = FILE, acceptedFileExtensions = "txt", acceptsUrls = true)
private String resourcePath;
```
## @Password
Indicates that the parameter needs to be masked when it is populated from the UI.
Note that this annotation should only be used in parameters of `String` type.

Figure 1. Example in the UI
## Putting It All Together
This example uses features explained above:
```java
@Parameter
@Placement(order = 3, tab="Additional information")
@Example("My name is Max the Mule and I love MuleSoft!")
@DisplayName("User biography")
@Summary("Information related to the user\'s life")
@Text
private String biography;
```
## @ClassValue
**Available since version 1.1**
Indicates that a parameter is a reference to a class name.
Note that this annotation should only be used in parameters of `String` type.
Besides hinting to the tooling that the parameter is a class, it also allows you to specify
restrictions on the classes that can be referenced. It can indicate that the assigned values must
extend or implement (`extendsOrImplements`) specific classes or interfaces.
Consider a Database connector that requires the end user to provide the class name of the JDBC
Driver to be used, for example:
```java
@Parameter
@ClassValue(extendsOrImplements = "java.sql.Driver")
private String driverClassName;
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Define Configurations and Connection Providers
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## Distributing Parameters
One key aspect is determining which parameters **should** be part of a configuration object and
which **should** be part of a configuration provider.
Connection providers **must** contain only parameters that are used to establish and configure
connections to an external system. Any parameters used for any other purpose **must** go into the
configuration object instead.
## POJO Parameters in Configurations
When a configuration or connection provider uses a POJO as a parameter type, without the use of the
@ParameterGroup annotation, then the POJO **must** comply with the following:
- Have a default constructor
- Expose a getter for each field annotated with @Parameter
- Override the equals() and hashCode() methods with an implementation that uses all the @Parameter
fields
## Don’t Establish Connections During the Lifecycle Phase
ConnectionProviders can hook into the application lifecycle by implementing any of the corresponding
interfaces (Initialisable, Startable, Stoppable, or Disposable).
Connections **must not** be established in the initialisable() or start() methods, and they **must
not** be disconnected during the stop() or dispose() methods. Therefore, the provider’s constructor
and lifecycle methods **must** never throw a ConnectionException.
Connections **must** be established only in the connect() method and **must** be severed only in the
disconnect(T) methods
## Handling SSL Connections
When a connector needs to establish a TLS/SSL secure connection, the SSLContext **must** be obtained
through a TlsContextFactory parameter as explained in this article.
When a ConnectionProvider has a TlsContextFactory parameter, it **must** also implement the
Initialisable interface and invoke the initialise() method on such context during initialization:
```java
public class MyConnectionProvider implements ConnectionProvider, Initialisable {
@Parameter
private TlsContextFactory tlsContext;
@Override
public void initialise() throws InitialisationException {
((Initialisable) tlsContextFactory).initialise();
}
}
```
## Defining a Connection Management Strategy
When defining or designing the [connection management strategy](https://docs.mulesoft.com/mule-sdk/latest/connections), the following decision
process **must** be followed:
- The most efficient option is to use a CachedConnectionProvider.
This however requires that the connection object **must** be thread safe, and that thread safeness
**must not** come at the expense of significant synchronization contention.
- If a CachedConnectionProvider is not possible, then a PoolingConnectionProvider **should** be used
instead, especially if establishing the connection is expensive.
- Only if neither of the previous two options are possible, **should** a plain ConnectionProvider be
considered.
## Handling OAuth Protected Connections
The SDK supports building connectors to systems protected by OAuth.
[As explained in this article](https://docs.mulesoft.com/mule-sdk/latest/oauth), it automatically handles the process of obtaining and
refreshing OAuth tokens, which are made available through an AuthorizationCodeState object (if the
Authorization Code grant type is being used) or the ClientCredentialsState object (if the Client
Credentials Grant Type is being used).
The sections that follow provide additional considerations for OAuth use.
### Handle Token Expiration
Although the SDK provides the ability to refresh access tokens in a thread-safe manner, there’s no
standard way to detect that the token has actually expired because different service providers
communicate this in different ways, making it each connector’s responsibility to detect such a
condition.
When using OAuth authentication, all connectors **must** detect when a token has expired and
communicate it to Mule by raising an AccessTokenExpired exception.
This is difficult because connectors **must** differentiate between the following conditions:
- The access token expired and needs to be refreshed
- The access token is valid, but lacks privileges to perform a given action
- The access token has been remotely revoked
### Always Query the State Object on Each Request
The AuthorizationCodeState and ClientCredentialsState objects are the means through which connectors
gain access to the access tokens that Mule manages. Most precisely, this happens through the
getAccessToken() method that both classes share.
Because of the highly concurrent nature of Mule, those tokens can be refreshed or unauthorized at
any time.
Therefore, the getAccessToken() method **must** be invoked on the state object for every request to
be sent. The access token **must not** be cached or stored in an internal variable.
This consideration is especially important when using third-party client libraries that might
perform caching.
### Do Not Use the Access Token in the Connection Creation
The creation of the connection object in the `ConnectionProvider#connect` method must not depend on
the presence of a valid access token. Connections that need to use the token to perform a
one-time-only request should not rely on the creation of the connection. The request must be
deferred to when the connection is first used.
To adhere to this practice, you can use the `org.mule.runtime.api.util.LazyValue` class. When a
value is initially used, the value is retrieved; subsequent uses get the value that was cached
initially.
The following example shows how to use the `org.mule.runtime.api.util.LazyValue` class:
```java
@AuthorizationCode(accessTokenUrl = MyConnectionProvider.ACCESS_TOKEN_URL,
authorizationUrl = MyConnectionProvider.AUTH_URL,
defaultScopes = MyConnectionProvider.DEFAULT_SCOPE)
public class MyConnectionProvider implements ConnectionProvider {
public static final String ACCESS_TOKEN_URL = "accessTokenUrl";
public static final String AUTH_URL = "authUrl";
public static final String DEFAULT_SCOPE = "defaultScope";
private AuthorizationCodeState state;
@Override
public Connection connect() throws ConnectionException {
return new Connection(new LazyValue(getUserId(state.getAccessToken())));
}
private String getUserId(String accessToken){
...
}
...
}
```
As such, the first time `LazyValue` is used, the information is retrieved, and all later usages get
the value that has already been resolved.
## Connection Object Must Not Expose (Nor Be) the Inner Client
A common anti-pattern often found in connectors is that the ConnectionProvider generates a
connection object that exposes the client or implementation used to access the external system. For
example:
```java
public class HttpConnection {
private HttpClient client;
public HttpClient getClient() {
return client;
}
}
```
An operation would then use it like in this pseudo code:
```java
public void createCustomer(@Connection HttpConnection connection, @Content InputStream content) {
connection.getClient().send(HttpRequest.builder()
.path(connection.getPath() + "/customer")
.method("POST")
.entity(content)
.addHeader("Accept", "application/json")
.build()
);
}
```
This code has several drawbacks. The most obvious is that the operations using the connection are
strongly coupled to the implementation of the connection object. If the need ever comes to change
the implementation of the client, all the components using that connection will be affected.
Another problem is that the connection object is not testable. Because the client object is exposed,
writing a test that interacts with a mock version of the connection object becomes too complicated.
The biggest problem is that it introduces functional coupling between all components using the
connection object and the functional nuances of all supported connection providers.
For example, assume that the example above is part of a connector that supports both Basic
Authentication and OAuth authorization mechanisms.
If invalid credentials are used with the Basic Authentication connection, then the request will
result in a HTTP 401 status code and the operation **should** fail.
However, if the same response code is received using an OAuth protected connection, then the
connector needs to execute logic to determine if the token has expired and an
AccessTokenExpiredException **should** be thrown.
As new connection types and components are added, the worse the problem becomes. This is only one
example. It can happen with all other types of connections, not just HTTP clients.
To prevent this, the connection objects **must** encapsulate their inner communication mechanisms
and security schemes, leading to a pattern like this:
```java
public void createCustomer(@Connection HttpConnection connection, @Content InputStream content) {
connection.createCustomer(content);
}
```
With this approach, each ConnectionProvider implementation can provide its own implementation of the
HttpConnection object, removing the root cause of the problem and providing freedom to change the
inner workings of the connection without affecting other components.
### Alternative: Leverage the Command Pattern
Instead of giving the connection object one method per endpoint to be consumed, another option is to
implement the command design pattern in a more generic way:
```java
public void createCustomer(@Connection HttpConnection connection, @Content InputStream content) {
connection.request(HttpRequest.builder()
.path(connection.getPath() + "/customer")
.method("POST")
.entity(content)
);
}
```
With this approach, the connection object has only one generic request method which receives an
HttpRequestBuilder object. Notice that the builder object never receives the build() command.
Depending on the implementation of the connection object, additional headers can be added, the
request can be performed in different ways and the response can be processed accordingly.
## Do Not Export as Part of the Module’s API
Configuration, ConnectionProvider and Connection classes **must not** be exported as part of the
module’s API.
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Define Operations
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The sections that follow provide general rules that apply to all operations.
## Position Independence
Operations **must not** depend on their position in the flow for them to work.
This means that no component **should** depend on the side effects of a prior or next component to
fulfil its contract.
For example, consider the following flow:
```xml
```
`` **must not** depend on `` to have been previously executed for it to
work.
## Non-Metadata Key Parameters Must Not Change the Output Type
Behavior parameters **must not** change the operation’s return type.
> [!NOTE] There’s a special case regarding parameters that act as Metadata Keys. This rule applies
> to all non-metadata key parameters. For example, a module wants to offer the capability to perform
> a given action both synchronously (which means that the output results are available immediately)
> or asynchronously (the operation returns a promise ID that can be later be used to retrieve the
> result).
This could be solved like this:
```xml
```
The first operation returns an apple object, and the second returns a String representing a job ID.
This example is illegal. The get-apple operation **must** always return an apple. It cannot change
its return type based on the async parameter.
This **should** be modeled as two different operations:
```xml
```
## Dynamic Types and Metadata Key Parameters
Metadata Key parameters are treated as special because they are allowed to change the output type of
an operation. This change can be considered in two levels:
- The operation always returns an apple, but the definition of an apple changes depending on the
system instance or user in use. Even if the structure of the apple is dynamic, it remains an
apple.
- The operation is generic and the Metadata Key parameters actually determine which type will be
returned.
For example:
```xml
```
This operation does not violate the rule that the non-metadata key parameters **must not** change
the output type because:
- This operation returns a List, even if the type of the items in that list depends on the
searchType parameter
- searchType is set to “ORDERS”, it always returns a list of ORDERS. There’s no other parameter in
the operation that makes it return a list of ORDER\_REFERENCES instead.
## Operation Output
The output of operations **must** comply with the following:
### Always Communicate the MIME Type
For DataWeave to handle the output of an operation, it is critical to make sure that the MIME type
of the output value is always communicated.
The SDK does this automatically when the return type is a Map, POJO, or Java simple type (String,
Integer, Short, and so on).
However, when the output type is a String, InputStream, or byte\[\], the module **must** specify the
mimeType for that value. Otherwise DataWeave will not know how to handle it.
There are two ways of doing this:
- @MediaType annotation
When the output type of the operation is always certain, the @MediaType annotation **must** be
used:
```java
@MediaType("application/json")
public InputStream getPerson(String personId) {
// ....
}
```
- Use the Result object
There are other cases in which the return MIME type is known only at runtime. Examples of this
include:
- Reading a file (the actual MIME type depends on the file being read)
- Hitting an HTTP endpoint that accepts several MIME types (the server communicates the MIME type
through the Content-Type header).
For example:
```java
public Result read(String path) {
return Result.builder()
.output(readStream(path))
.mediaType(inferMediaTypeFromFileName(path))
.attributes(getAttributes(path))
.build();
}
```
- Using Java POJOs as return types
If the operation returns a POJO, then:
- The class **must** be part of the module’s API.
- The object **must** be a value object that cannot contain any logic.
- The object **must not** contain any static state.
- The object **must** be Serializable.
- Handling JSON and XML output types
Some operations return values in the form of JSON or XML documents.
- Java Types
The JSON and XML documents **must** be returned in the form of an InputStream. None of the usual
Java types for representing these types (Reader, Sax objects, Document, Node, JSON Node, and so
on) are allowed.
- DataSense Resolution
For tooling to assist the user with handling the documents returned by the operation, the schema
of the returned documents needs to be known. Therefore, operations **must** clearly define the
output schema.
- Static DataSense
Sometimes, the schema is fixed and well known. If the schema is well known and static, the
problem **must not** be resolved through the use of dynamic DataSense resolvers. The connector
**must** specify that schema through either of the following instead:
- @OutputJsonType
Define the output type by pointing to a JSON schema that’s part of a module’s resources:
```java
@OutputJsonType(schema = "person-schema.json")
public InputStream getPerson(String personId) {
// ...
}
```
- @OutputXmlType
Similar to @OutputJsonType, but for XML schemas:
```java
@OutputXmlType(schema = "order.xsd", qname = "shiporder")
public void getOrder(String orderId) {
...
}
```
- OutputStaticTypeResolver
Define the type programmatically.
```java
@OutputResolver(OrderTypeResolver.class)
public InputStream getOrder(String orderId) {
...
}
```
### Dynamic DataSense
If the schemas are dynamic, a dynamic output resolver is needed. This is done by implementing the
OutputTypeResolver interface.
The key rule is that the module **must** resolve to a specific schema that the user can abide by.
The dynamic resolver cannot return a generic ANY type.
```java
@OutputResolver(DynamicOrderTypeResolver.class)
public InputStream getOrder(String orderId) {
...
}
```
### Dynamic Java Type Parameters
It’s very common for connectors to handle dynamic types. For example, services like Salesforce,
NetSuite, or SAP define a set of core entities (Person, Order, and so on) that have a base structure
that the user can customize.
Other services go further and allow for a completely custom type set, for example, any OData
service.
All operations returning these dynamic types **must** have an associated @OutputTypeResolver that
provides the actual type definition to be used for the current configuration.
Prior sections discussed this for output values communicated in the form of JSON or XML documents.
The same applies for parameters represented as Java types, such as Map or custom POJOs. A well
defined, non trivial OutputTypeResolver **must** exist for all other dynamic types, regardless of
which Java class is being used to represent them.
## Streaming
### Favor InputStream over byte\[\]
InputStream **should** be used as a return type instead of a byte\[\] array. Returning an array of
bytes is valid when such array is certain to be of a small size.
If the array size is unknown, variable or potentially large, then the operation **must** return
InputStream.
This avoids large memory requirements that can lead to an OutOfMemoryError, especially when running
in small workers. Returning InputStream implies that your code needs to avoid fully loading that
large piece of information into memory. Loading the entire byte\[\] array into memory and only
wrapping it into a ByteArrayInputStream completely defeats the purpose of this rule and **must** be
avoided.
### Don’t Return Large Strings
Returning a String is acceptable, but only if you can ensure that the string does not become a
String larger than 4 KB. If that’s a possibility, then the operation **must** return InputStream
instead, and use @OutputResolver to provide metadata on the expected media type.
### Use the StreamingHelper
When a component returns a streamable resource (InputStream or PagingProvider), the SDK
automatically makes those streams repeatable (provided that the application is configured to do so).
When those resources are contained in a higher level structure such as a Map, you **must** use
[StreamingHelper](http://www.mulesoft.org/docs/site/4.1.1/apidocs/org/mule/runtime/extension/api/runtime/streaming/StreamingHelper.html)
to explicitly tell the SDK to perform that adaptation.
Common cases:
- Stream contained inside a Map
An example of this case is the operation, in which the result set obtained from the
database is returned in the form of a Map for which the keys are the column names and the values
are the actual result. If the result set contains a BLOB column, then that value is of type
InputStream. For that case, the connector **must** use this method, which returns a new Map in
which all streamable resources have been made repeatable:
`org.mule.runtime.extension.api.runtime.streaming.StreamingHelper#resolveCursors(Map, boolean)`
- Stream contained in a POJO
Although not applicable for the case of database, it is possible to have a use case in which
InputStream is actually contained in a field of a POJOo.
In the previous case, `` returns a Map because the actual structure of the response is
unknown, as it changes with each query. Ensure you plan ahead to avoid causing problems that
require difficult troubleshooting.
However, if you’re using a POJO, it’s because the structure is fixed, which means that the POJO
most likely contains some well-known attributes and some streamable information. Although we
cannot 100% ensure it , most likely the fixed attributes of that POJO **should** go into an
Attributes object and the stream into the payload, reducing this to the standard case.
On the corner case in which doing this actually makes sense, the field containing the streaming
resource **must** be adapted using the
org.mule.runtime.extension.api.runtime.streaming.StreamingHelper#resolveCursorProvider(Object)
method.
> [!NOTE] Although the pattern of a POJO containing a streamable resource is not explicitly
> forbidden, it is a big code smell that **should** be reviewed carefully and **must** be matched
> with a custom Metadata resolver.
Assuming that the scenario is valid, a custom Metadata resolver is necessary because you don’t
know if the value will be adapted into a CursorProvider or not. It will have to be of type Object,
which means it will become obscure to DataSense without the aid of a custom resolver.
### Favor Non-Blocking I/O
Mule 4 is a reactive execution engine that is optimized to perform non-blocking I/O operations.
When an input or output operation executes in non-blocking mode, the connector **must** adhere to
the MuleSoft [Non-Blocking Operations](https://docs.mulesoft.com/mule-sdk/latest/non-blocking-operations) requirements.
Best uses for non-blocking I/O:
- Accessing files in the local file system
- HTTP requests
- TCP/UDP socket requests
- Any I/O operation for which a non-blocking client exists
Where not to use non-blocking I/O:
- Accessing a database through JDBC (non-blocking JDBC drivers are still experimental)
- Using clients where non-blocking equivalents do not exist or are unreliable, such as using Apache
Commons Net for accessing FTP servers where no reliable non-blocking option exists.
#### Non-Blocking and Asynchronous Are Not the Same
It’s common to confuse asynchronous with non-blocking. They are not the same thing. This rule of
favoring non-blocking I/O does not mean that all I/O operations **should** be dispatched to a
separate thread that is executed asynchronously just for the sake of it.
Be sure you have a good understanding of the principles of non-blocking IO and how it’s implemented
in Mule.
See [Non-Blocking Operations](https://docs.mulesoft.com/mule-sdk/latest/non-blocking-operations).
### Use Transactions
When an operation interacts with a transactional system (including XA transactions), the operation
**must** support that capability. See Transactions.
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Define Sources
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## Assure Restartability
Tools like Anypoint Runtime Manager allow you to start and stop individual sources or flows,
independently from the rest of the application.
This means that all sources must:
- Be able to be stopped and restarted at any time, without their functionality being affected
- Release all resources when stopped including connections, threads, files, and so on.
## No Manual Polling
Sources that work by doing polling **must not** implement the polling logic manually. They **must**
extend the PollingSource class instead.
## Declare When a Response Is Emitted
There are sources that only trigger messages into a flow. Others, also send a response to an
external system, like the HTTP connector.
Sources that emit a response **must** be annotated with [@EmitsResponse](https://docs.mulesoft.com/mule-sdk/latest/sources-response).
## Handle Asynchronous Callbacks
Sources define callbacks (methods annotated with @OnSuccess and/or @OnError) in which asynchronous
tasks are performed. These async tasks can range from sending a response using non-blocking I/O to
sending notifications or auditing tasks.
For asynchronous callbacks, the source **must** use SourceCompletionCallback to signal the
completion of such tasks. See
[Sending Asynchronous Responses from a Message Source](https://docs.mulesoft.com/mule-sdk/latest/sources-async-response).
## Use Transactions
When the source obtains its messages from a transactional system, it **must** do so using
[transactions](https://docs.mulesoft.com/mule-sdk/latest/transactions).
## Handle Back Pressure
The Mule [execution engine](https://docs.mulesoft.com/mule-runtime/latest/execution-engine) may apply back pressure to a
message source when at capacity. By default, the SDK forces the source to wait when back pressure
occurs by making this method block and wait for Mule to have resources available to handle the
request:
`org.mule.runtime.extension.api.runtime.source.SourceCallback#handle(org.mule.runtime.extension.api.runtime.operation.Result)`
Although this default behavior suits most cases, some modules require different actions. For
example:
- Instead of waiting, the HTTP connector sends a 503 response
- The JMS connector makes it configurable if the source **should** wait, fail, or drop the message,
as those are valid options in the messaging domain
When the module’s domain includes use cases in which waiting **should not** be the default, or
additional options **should** be available, then the source **must** use the @BackPressure
annotation to provide that behavior.
### Custom Actions When Back Pressure Occurs
Some modules may need to take custom actions when back pressure errors occur, such as:.
- Resolving transactions
- Releasing resources
- Sending notifications to external systems
Modules with this functional need **must** do so by including a callback method annotated with
@OnBackPressure. For example:
```java
@OnBackPressure
public void onBackPressure(BackPressureContext ctx) {
// .. implementation
}
```
Notice that if the action to be taken is asynchronous, a SourceCompletionCallback **must** be
leveraged too:
```java
@OnBackPressure
public void onBackPressure(BackPressureContext ctx, SourceCompletionCallback completionCallback) {
// .. implementation
}
```
### Resolving Transactions
If the source is transactional, then it **must** add a back pressure handler in which the
transaction is resolved.
## Mind the Cluster Behavior
All sources **must** consider how they are going to behave when Mule operates in cluster mode or the
same app is deployed to several workers in CloudHub.
In some cases, it’s okay for the source to run on all replicas. An example of this is the
. The underlying protocol already guarantees that no two nodes will pick up the same
file at the same time. This is the default behavior.
However, there are some cases in which the source **should** run on the primary node only, as
running on all replicas could lead to bogus behavior or data corruption. An example of this is a
`` that is listening to a topic, or a source reading from a stream of events. In these
cases, a source **must** be annotated with the @ClusterSupport annotation, and specifying the
NOT\_SUPPORTED or DEFAULT\_PRIMARY\_NODE\_ONLY options.
## Display Name
Sources **should** have a @DisplayName that uses the “On ..” prefix to communicate in which event or
action the source/listener/trigger will be executed/triggered, for example:
- JMS Connector
The source is called On New Message communicating that the source will dispatch a message when a
new message arrives to a Queue.
- Database Connector
On Table Row communicates that triggers for each table row.
- Salesforce Connector
On Created Object, every time the connector detects a new object in Salesforce, the connector
triggers the flow.
### DSL Naming
At the DSL level, the sources **should** instead use the `listener` suffix, or simply use the
listener name.
For example:
- The HTTP connector defines the message source for exposing inbound HTTP endpoints
- The WebSockets connector defines the and sources
These can be controlled using the @Alias annotation.
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
# Defining Parameters
Defining parameters well is a key aspect of the usability of any component. Even if the components provides awesome functionality, the user is not going to have a great experience if the component is not easy and intuitive to configure. Handling JSON and XML Parameters
Some operations expose parameters that expect values in the form of JSON or XML documents.
- Java types
The JSON and XML parameters **must** be received in the form of an InputStream. None of the usual Java types for representing these types (Reader, Sax objects, Document, Node, JsonNode, and so on) are allowed.
- DataSense resolution
Users need tooling support to make sure that they feed these parameters with documents that conformed to the expected schemas. Therefore, these parameters **must** clearly define the expected schema.
- Static DataSense
Sometimes, the schema is fixed and well known. If the schema is well known and static, the problem **must not** be resolved through the use of dynamic DataSense resolvers. The connector **must** specify that schema through either of the following instead:
- @InputJsonType annotation
Allows you to define the expected type by pointing to a JSON schema that’s part of the module’s resources:
```java
public void createPerson(@InputJsonType(schema = "person-schema.json") @Content InputStream person) {
...
}
```
- @InputXmlType annotation
Similar to @InputJsonType, but for XML schemas:
```java
public void createOrder(@InputXmlType(schema = "order.xsd", qname = "shiporder") @Content InputStream order) {
...
}
```
- InputStaticTypeResolver
Another option is the use of an InputStaticTypeResolver to define the type programmatically:
```java
public void createOrder(@TypeResolver(OrderTypeResolver.class) @Content InputStream order) {
...
}
```
More information about [handling static DataSense](https://docs.mulesoft.com/mule-sdk/latest/static-metadata).
- Dynamic DataSense
If the schemas are dynamic, then a dynamic resolver is needed. This is done by implementing the InputTypeResolver interface.
The key rule is that the module **must** resolve to a specific schema that the user can follow. The dynamic resolver cannot return a generic ANY type.
```java
public void createOrder(@TypeResolver(DynamicOrderTypeResolver.class) @Content InputStream order) {
...
}
```
## [](#dynamic-java-type-parameters)Dynamic Java Type Parameters
It’s very common for connectors to work with dynamic types. For example, services like Salesforce, NetSuite, or SAP define a set of core entities (Person, Order, and so on) which have a base structure that the user can customize.
Other services go further and allow for a completely custom type set, such as an OData service.
All parameters using these dynamic types **must** have an associated @TypeResolver that provides the actual type definition to be used for the current configuration.
Prior sections discussed the need for @TypeResolver for parameters communicated in the form of JSON or XML documents. The same applies for parameters represented as Java types, such as Map or custom POJOs. A well defined, non-trivial TypeResolver **must** exist for all other dynamic types, regardless of which Java class is used to represent them.
## [](#streaming)Streaming
Streaming is a key aspect of Mule 4. It’s important to define operations in a way that allows to leverage that.
- Don’t use byte\[\] array parameters
Parameters **must not** be of byte\[\] type. Use InputStream instead. Mule automatically transforms any byte\[\] parameter value into an InputStream.
- Avoid large String parameters
String parameters are perfectly fine, but always consider what are the odds of the assigned values to become larger than 4 KB. If that’s a possibility, then the parameter **must** be an InputStream instead and use an InputTypeResolver to provide metadata on the media type that’s expected.
## [](#layout)Layout
The MuleSoft layout mechanism comprises two organizational concepts: groups and tabs.
Although you are free to define your own groups and tabs, there’s a set of standard names for them.
Default groups:
- General
- Advanced
- Connection
Default tabs:
- Default
- Advanced
- Security
- Connection
If a given parameter does not fit these categories, define a new one that can be defined. That decision needs to be made explicit and documented in the extension’s design spec.
- Required Parameters
Required parameters **must** always be in the default group and tab, and **must** be the first to appear in the generated UI.
Required parameters **must** be placed on the main group and tabs so that the end user can see at all of them at first glance.
- Optional Parameters
Optional parameters **should not** be placed in the main view. This is to not overload the view with too much content that in most cases won’t be configured by the average customer.
Exceptions:
- Some optional parameters are not required to be configured, but are used very frequently.
- The parameter is optional because it has a default value, but it’s still key to the component’s behavior (for example, the method parameter of the http:request operation).
- Default Values
Expressions **should** never be used as default values. This includes expressions that access the event (such as `[vars]`, `[attributes]`, or `[payload]`), and expressions that obtain dynamic values (such as `[now()]`) or create default empty structures (such as `#[[]]`).
- @NullSafe
Optional parameters of Collection or Map types **must** be annotated with @NullSafe to guarantee that null values are avoided by automatically providing empty instances instead.
- Security parameters
When talking about security parameters, it’s important to distinguish between actual security parameters and connection parameters. For example, username and password could be thought of as security parameters because they’re used for access control. But in reality, you can’t establish a connection without those in the first place, so they are also required connection parameters.
- Therefore, optional security parameters like tlsContext, or hashing algorithms **must** go into a security tab, except when they are required.
- Required security parameters, **must** go in general as any other required parameter.
- Parameter ordering
As explained earlier, required parameters **must** also be shown first, but in which order **should** they be listed? The same thing applies to optional parameters: we know they go after the required ones, but in which order?
Parameter ordering considerations:
- There’s a strong and known relevance ranking
In some cases, the developer knows that some parameters are more relevant than others. That relevance might be given based on how frequently they are used or by how relevant they are to the particular domain of the connector. For example: when talking about the http:listener, the path is by far the most relevant parameter, even if other required parameters exist. The same applies to the optional parameters: the allowed-methods parameter is more relevant than the keep alive settings.
The problem with this case is that relevance might be subjectively biases. People might not agree on what’s relevant or not and the person making the call could simply be wrong. In these cases, the case for that relevance sorting **must** be made explicit in the extension’s design document and justified. Reviewers **must** also have the chance to challenge that decision.
- Metadata Keys order:
This scenario applies only for operations. If the operation has a metadata key hierarchy, parameters that match with metadata keys **should** follow the same order.
- There’s no usage or relevance ranking
- Mixed
There might be a strong relevance among some group or subgroup of parameters, but another group (for example advanced or security) might not be.
For cases with no explicit relevance, alphabetic sorting **should** be used.
- Parameter Types
When working on Java based connectors, the connector **must not** expose types from external libraries.
For example: if is being used the MongoDB Library to create a MongoDB Connector, the result of the queries are represented as BSON objects. This could never be the output or input of an operation because of many reasons:
- The connector gets coupled to implementations that are not managed by the connector developer.
- The type is difficult or impossible to consume or create from DataWeave.
- The internal library gets shared on the application classloader and could cause class clashing.
## [](#parameter-hints)Parameter Hints:
- @Example
For optional parameters that don’t specify a default, the @Example annotation **should** provide an example of a valid value. This increases the UX of Mule developers to be more sure about the kind and structure of data that they **should** configure.
This applies to parameters of simple types only. It doesn’t include POJOs, lists or maps.
- Display Name
The SDK and Studio makes a best effort at transforming the parameter’s name to what is shown in the UI, but sometimes this is not enough. A name that makes sense on the connector’s DSL maybe doesn’t make sense in the UI and vice versa. For these cases, you **should** use the @DisplayName feature.
Also because the parameter name used on the extension is also the one used for the DSL (XML) and the display name, once the connector is released, this name can’t change since that would break backwards compatibility. The @DisplayName annotation is also useful in those cases to change the name shown in the UI without affecting backwards compatibility. Lastly, keep in mind that unlike Java or the Mule DSL, the @DisplayName does accept spaces.
- Expression Support
By default, parameters accept expressions. There are some cases in which this default **should** be changed.
Disable expression support when it doesn’t make sense to support expressions in the context of a configuration or connection provider parameter, for example, the port number in which to place an http listener. It doesn’t make sense for the port of an inbound listener to be changing each time mule processes a message.
Make the use of expression mandatory when there’s no use case in which that parameter is to take a fixed value. For example, an aggregator’s group identifier.
- Summary
All parameters have a matching Javadoc that explains the purpose of that parameter and its semantics. Sometimes, that explanation can be quite lengthy. For those cases, it’s a good practice to use the @Summary annotation to provide a one liner description of the parameter. It’s ok if this summary doesn’t fully cover its meaning and purpose. It’s just intended to be a quick one liner that the UI can turn into a tooltip.
- Configuration Overrides
Sometimes a configuration object defines a parameter that **should** globally affect a connector. However, some components might want to override that parameter.
The canonical example of this is a charset encoding. A file connector could define the encoding to use at a configuration level. However, in the context of an application, one might have one specific flow in which a different encoding **should** be used (even though the rest of the application might still use the one specified in the config). The @ConfigOverride annotation **must** be used in these cases. This is not only a matter of simplifying your own code (as opposed to manually checking for an override and defaulting to the config one instead). The @ConfigOverride not only does that automatically, but in Studio also overrides the config parameter allowing the UI to surface this accordingly.
[Configuration Overrides](https://docs.mulesoft.com/mule-sdk/latest/config-override) are explained at length in this article.
- Putting the pieces together
Here’s an example of how the hinting features can interact together
```java
@Parameter
@Optional
@Summary("The sender 'From' address. If not provided, it defaults to the address specified in the config")
@Example("example@company.com")
private String fromAddress;
```
## [](#enum-versus-value-provider)Enum Versus Value Provider
There are use cases in which certain parameters are exposed to the user as a list of predefined values.
Sometimes that list is fixed, meaning that all possible values to select from are already defined at compilation time and never change. An example of this is the protocol of an SFTP proxy. Possible values are HTTP, SOCKS4, and SOCKS5. That list is fixed and unaltered by any other condition.
For cases like this, modules **must** use a [Java Enum](https://docs.mulesoft.com/mule-sdk/latest/value-providers#java_enum) as the parameter type. The Enum lists all the possible values and the SDK automatically generates the proper experience at design time.
Alternatively, the list of possible values can be dynamic and depends on other conditions.
For example, the Slack connectors allow users to send messages to different channels. The list of available channels actually depends on the logged user. Therefore, the list is dynamic.
To include values that are not known or dynamic, such as custom values, you **should** use [Value Providers](https://docs.mulesoft.com/mule-sdk/latest/value-providers#value_providers), instead.
When to use an Enum?
- When the values Set is well known
- When the value set is limited
- When the value set is not context dependant
- When the value set is closed
- When the required a combo inside a POJO (Value Providers are not supported inside POJOs)
When to use a Value Provider?
- When the values are not well known
- When the value set is context dependent depending on the Connection or Configuration or other parameters
- When the value set is open such that the connector can suggest some values, but other ones can also be valid
- When the value set is dynamic
## [](#exclusive-parameters)Exclusive Parameters
If parameters values are invalid, modules **should not** fail at startup time or execution time. For example, the scripting module executes user scripts that can be provided either inline or referenced from a file. This module provides two parameters: one called script for the inlining option, and another called scriptFile. The user can use only one of these at a time, which means that they’re both optional.
To provide a good user experience, the UI **should** provide hints to a user at design time when:
- The two parameters are provided at the same time
- No parameter is provided
Use cases like this **must** leverage the [Exclusive Optionals](https://docs.mulesoft.com/mule-sdk/latest/exclusive-optionals) feature to provide a good experience at design time.
## [](#using-pojo-parameters)Using POJO Parameters
Sometimes, you need to define parameters of POJO types. Depending on the scenario, that practice might be advised or simply discouraged.
- Using POJOs for parameter grouping
One use case for a POJO parameter is when the same set of parameters constantly repeat across several components (either operations or sources). The Java good practice would be to put those together into a single reusable class.
For example, consider the Aggregators module, in which all group-based aggregators require a set of common parameters. This example creates the GroupBasedAggregatorParameterGroup class:
```java
public class GroupBasedAggregatorParameterGroup extends TimeoutContainingAggregatorParameterGroup {
/**
* An expression that determines the aggregation group unique ID.
* This ID determines which events *must* be aggregated together.
*/
@Parameter
@Expression(REQUIRED)
@Optional(defaultValue = "#[correlationId]")
private String groupId;
/**
* The size of the expected group to aggregate. All messages with
* the same correlation ID *must* have the same groupSize.
* If not, only the first message groupSize is considered and
* a warning is logged.
*/
@Parameter
@Expression(SUPPORTED)
@Optional
private Integer groupSize;
/**
* The time to remember a group ID once it was completed or timed out.
* 0 means, don't remember, -1 remember forever
*/
@Parameter
@Expression(NOT_SUPPORTED)
@Optional(defaultValue = "180")
private int evictionTime;
/**
* The unit for the evictionTime attribute
*/
@Parameter
@Expression(NOT_SUPPORTED)
@Optional(defaultValue = "SECONDS")
private TimeUnit evictionTimeUnit;
}
```
This object would then be used as follows:
```java
@Alias("groupBasedAggregator")
@Throws(GroupBasedAggregatorErrorProvider.class)
public void aggregateByGroup(
GroupBasedAggregatorParameterGroup aggregatorParameters,
@Alias("incrementalAggregation") @Optional IncrementalAggregationRoute incrementalAggregationRoute,
@Alias("aggregationComplete") AggregationCompleteRoute onAggregationCompleteRoute,
RouterCompletionCallback completionCallback)
throws ModuleException {
// impl...
}
```
This approach however introduces some problems:
- The GroupBasedAggregatorParameterGroup object defines a complex type in the module’s type catalog, even though this type has no real semantic meaning for the module’s domain model.
This is just a convenience internal type, derived from good practices of the programming language used to write the module. There would be no sense for this type to appear in the catalog.
- Because the type appears in the catalog, it becomes part of the module’s API.
Therefore, modifications to it, or even the decision to replace it with something else, results in a backwards compatibility problem.
- Complex objects are hard to translate into a good user experience in Studio.
All of the these issues can be traced to one root cause: the module’s structure **should not** reflect nor be affected by the nuances of the programming language being used (notice that we wouldn’t be having this discussion if the XML SDK would be used here instead).
To be able to still maintain parameters in a POJO without generating the side effects in the generated module, use the @ParameterGroup annotation:
```java
public void aggregateByGroup(
@ParameterGroup(
name = "Aggregator config") GroupBasedAggregatorParameterGroup aggregatorParameters,
@Alias("incrementalAggregation") @Optional IncrementalAggregationRoute incrementalAggregationRoute,
@Alias("aggregationComplete") AggregationCompleteRoute onAggregationCompleteRoute,
RouterCompletionCallback completionCallback)
throws ModuleException {
// implemented as privileged operation in GroupBasedAggregatorOperationsExecutor
}
```
This annotation opens the POJO and exposes its inner parameters, as if they had been inlined as method arguments. As far as the user and the type catalog know, there’s no GroupBasedAggregatorParameterGroup and the operation simply defines multiple String parameters. However, the developer still needs to leverage the Java POJO.
- Forcing child elements in the Mule DSL
Another use case for POJO parameters is forcing certain parameters to appear as child elements in the Mule DSL. For instance, consider this example from the email connector:
```xml
Email Content
```
The is a POJO that contains the content and contentType parameters. Because the email connector is quite complex, we want the body to appear as a child element in the Mule DSL, for increased readability.
To use a POJO just for this has the same drawbacks as in the prior example, but again, you can use the @ParameterGroup annotation to overcome them:
```java
@Summary("Sends an email message")
@Throws(SendErrorTypeProvider.class)
public void send(@Connection SenderConnection connection,
@Config SMTPConfiguration configuration,
@Placement(order = 1) @ParameterGroup(name = "Settings") EmailSettings settings,
@Placement(order = 2) @ParameterGroup(name = "Body", showInDsl = true) EmailBody body,
@Placement(order = 3) @ParameterGroup(name = "Attachments") AttachmentsGroup attachments) {
```
As you can see, the @ParameterGroup annotation has a showInDsl attribute that can be used to force the DSL to put the inner parameters as a child element.
- Defining Global Elements
Another use case is the ability to define a global element (which is not a Configuration) to referenced from another component.
For example, the File connector has the concept of a matcher, which is a set of rules that are used to decide whether a file **should** be processed or ignored. Matchers can be used in either the operation or in any of the message sources defined in the connector.
Because the exact same matcher might be needed in different flows, the connector provides the ability to define global matchers than can be later referenced. For example:
```xml
```
For these cases, it makes sense to define the matcher parameter as a POJO, without the use of the @ParameterGroup annotation. Notice that in this case, having the concept of a matcher being listed in the connector’s type catalog makes sense, since this is not an implementation detail but a core piece of functionality.
There’s one caveat though: for this to work, the class in which the matcher is implemented needs to declare that it is to be used as a global element:
```java
@Alias("matcher")
@TypeDsl(allowTopLevelDefinition = true)
public class LocalFileMatcher {
/**
* Files created before this date are rejected.
*/
@Parameter
@Summary("Files created before this date are rejected.")
@Optional
private LocalDateTime createdSince;
/**
* Files created after this date are rejected
*/
@Parameter
@Summary("Files created after this date are rejected")
@Optional
private LocalDateTime createdUntil;
...
}
```
- DSL Decision Making
As a summary, here’s a simple flow chart to aid with the decision process of how to use POJOs and parameter groups.

- Implementing `equals` and `hashCode` methods
Java classes used for POJO parameters or Parameter Groups must implement the `equals` and `hashCode` methods for [Dynamic Configurations](https://docs.mulesoft.com/mule-sdk/latest/static-dynamic-configs#Dynamic-Configuration-Lifecycle) to function correctly. Even if existing configurations do not have POJO parameters, the configurations need `equals` and `hashCode` methods because future runtime functionality may depend on it. The following example from a class in the Database Connector that illustrates the implementation of `equals` and `hashcode` methods:
```java
/**
* Pooling configuration for JDBC Data Sources capable of pooling connections
*
* @since 1.0
*/
@Alias("pooling-profile")
public class DbPoolingProfile implements DatabasePoolingProfile {
/**
* Maximum number of connections a pool maintains at any given time
*/
@Parameter
@Optional(defaultValue = "5")
@Placement(order = 1)
@Expression(NOT_SUPPORTED)
private int maxPoolSize = 5;
/**
* Minimum number of connections a pool maintains at any given time
*/
@Parameter
@Optional(defaultValue = "0")
@Placement(order = 2)
@Expression(NOT_SUPPORTED)
private int minPoolSize = 0;
/**
* Determines how many connections at a time to try to acquire when the pool is exhausted
*/
@Parameter
@Optional(defaultValue = "1")
@Placement(order = 3)
@Expression(NOT_SUPPORTED)
private int acquireIncrement = 1;
/**
* Determines how many statements are cached per pooled connection. Setting this to zero will disable statement caching
*/
@Parameter
@Optional(defaultValue = "5")
@Placement(order = 4)
@Expression(NOT_SUPPORTED)
private int preparedStatementCacheSize = 5;
/**
* The amount of time a client trying to obtain a connection waits for it to be acquired when the pool is
* exhausted. Zero (default) means wait indefinitely
*/
@Parameter
@Optional(defaultValue = "0")
@Placement(order = 5)
@Expression(NOT_SUPPORTED)
private int maxWait = 0;
/**
* A {@link TimeUnit} which qualifies the {@link #maxWait}.
*/
@Parameter
@Optional(defaultValue = "SECONDS")
@Placement(order = 6)
@Expression(NOT_SUPPORTED)
private TimeUnit maxWaitUnit;
/**
* Determines how many seconds a Connection can remain pooled but unused before being discarded.
* Zero means idle connections never expire.
*/
@Parameter
@Optional(defaultValue = "0")
@Placement(order = 7)
@Expression(NOT_SUPPORTED)
private int maxIdleTime;
@Parameter
@Optional
@Placement(tab = ADVANCED_TAB, order = 8)
@Expression(NOT_SUPPORTED)
@Summary("Additional properties used to configure pooling profile.")
private Map additionalProperties = emptyMap();
//getters...
@Override
public int hashCode() {
return Objects.hash(minPoolSize, maxPoolSize, acquireIncrement, preparedStatementCacheSize, maxWaitUnit, maxWait);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof DbPoolingProfile)) {
return false;
}
DbPoolingProfile that = (DbPoolingProfile) obj;
return maxPoolSize == that.maxPoolSize &&
minPoolSize == that.minPoolSize &&
acquireIncrement == that.acquireIncrement &&
preparedStatementCacheSize == that.preparedStatementCacheSize &&
maxWait == that.maxWait &&
maxWaitUnit == that.maxWaitUnit;
}
}
```
## [](#parameter-type-restrictions)Parameter Type Restrictions
You cannot add parameters or POJOs with types `org.mule.runtime.core.api.source.scheduler.Scheduler` or `org.mule.runtime.api.scheduler.SchedulingStrategy`. Mule runtime engine and the SDK add parameters of these types, for example, in polling sources.
## [](#see-also)See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers, parameters
---
# Defining Parameters in a Message Source
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Parameters are defined as fields of your `Source` class. All the features and annotations (such as
`@NullSafe`, `@ParameterGroup`, `@TypeResolver`) are available when defining an operation, for
example:
```java
@EmitsResponse
public class HttpListener extends Source {
@Config
private HttpListenerConfig config;
@Parameter
@Optional(defaultValue = "/")
private String path;
@Parameter
private Integer port;
/**
* Comma separated list of allowed HTTP methods by this listener.
*/
@Parameter
@Optional
@Placement(tab = Placement.ADVANCED_TAB)
@Summary("Comma separated list of methods. Leave empty to allow all.")
@Example("GET, POST")
private String allowedMethods;
}
```
This is similar to how configs are defined, except that none of these parameters accept expressions.
Using the `@Expression` annotation to support or require expression support results in an error.
## Next step
- [Lifecycle of a Message Source](https://docs.mulesoft.com/mule-sdk/latest/sources-lifecycle)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, config, dynamic, multitenant, multitenancy
---
# Dynamic Configurations
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The need to use expressions in a configuration parameter is a common one. Typical use cases are:
- Multi-Tenancy: Credentials or any other setting might change depending on the active user.
- Dynamic endpoints: Different destinations are used depending on the routed message.
- Dynamic settings: For example, a timeout might change depending on the destination of the message.
## Static Configurations
A configuration is static when none of its parameters are assigned an expression (even if those
parameters do support expressions), for example:
Example: Static Configuration
```xml
```
All the parameters in the example have fixed values, so this configuration is static.
Note that there is a difference between a parameter with a value that is not an expression and a
parameter that does not accept expressions. The former might accept an expression as a value.
## Dynamic Configurations
In dynamic configurations, at least one parameter has an expression, for example:
Example: Dynamic Configuration
```xml
```
This configuration is dynamic because the `defaultWriteEncoding` can resolve to a different value
for each execution.
Here is another dynamic configuration:
Example: Multi-tenancy
```xml
```
This example shows how to configure multi-tenancy. Expressions in connection parameters also resolve
into dynamic configurations.
## Dynamic Configuration Lifecycle
Static and dynamic configurations have very different lifecycles. For static configurations, a
single instance is created and used each time it is needed.
Dynamic configurations have a different behavior. Each time an operation that points to a dynamic
configuration is executed, all the parameters in the configuration are evaluated. A configuration
instance is created for each unique set of resolved parameters. In that way, each time the same
values are resolved, the same instance is returned, but for each different set of values, a
different instance is created.
## Dynamic Configuration Expiration
Although it is easy to create dynamic configurations, you still need a configurable mechanism for
disposing the configuration instances that are no longer needed (or that have been idle for a
certain period). This is critical to prevent out-of-memory (OOM) issues.
Returning to the [FTP multi-tenant](#multi_tenancy) example, the worst case scenario mandates that a
new configuration instance is produced on a per-message basis. Depending on the app, these instances
not be needed once the transfer is completed.
By default, dynamic instances of any configuration element are automatically disposed of between 5
to 10 minutes after the configuration has been idle. This is because the disposal depends not only
on the configuration’s expiration time, which is set to 5 minutes by default, but also on the
frequency of the Expiration Monitor, which runs every 5 minutes and ultimately performs the
disposal.
> [!TIP] The instance is inactive if no operation has started _or finished_ in that lapse. If an FTP
> transfer started 6 minutes ago, but the file is too big, and the transfer is still in progress,
> that configuration will not be expire.
SDK-based modules also support specifying custom timeouts for specific config definitions. This is
something that the module user might do to fine-tune an app to handle cases where the default
timeout is known to be too short or too long. The following example lowers the timeout to 30
seconds:
Example: Modifying a Timeout
```xml
```
> [!TIP] No particular action is required from you for the ` ` element to be
> available. The SDK does this automatically.
It is also possible to configure the global default at an app level so that any dynamic
configuration has a different default. You set this up through the `` element in the
[Mule DSL](https://docs.mulesoft.com/mule-runtime/latest/about-mule-configuration), which is provided for you in
Anypoint Studio:
```xml
```
Finally, it is also possible to set the frequency at which the runtime checks for and disposes of
configurations that have expired (default is 5 minutes). This cannot occur on a config-by-config
basis, only at the app level. The following example not only sets the default expiration time to 30
SECONDS, it also makes the runtime check every 1 minute.
```xml
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Enforcing the Output MediaType
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The [`Result` object](https://docs.mulesoft.com/mule-sdk/latest/result-object) allows you to set the output `mimeType`. However, this setting
is optional (SDK developers are not forced to set the `mimeType`).
However, there are some cases in which it is mandatory to specify the output `mimeType` of an
operation:
- When the operation returns a `String`.
- When the operation returns an `InputStream`.
This restriction is not arbitrary. Mule 4 uses DataWeave as its expression language, so users do not
need to worry about the format of the data. They only need to concern themselves with the its
structure. However, this means that DataWeave must be able to determine the media type of all the
values carried on the Mule Message.
The SDK automatically handles most of the work needed for DataWeave to have that information
automatically, but when the operation returns a generic type such as `String`, it is impossible to
know if the data is supposed to be in JSON, XML, or even plain text format. The same thing happens
with `InputStream`: it could be a stream of JSON, XML, or CSV, or it could be binary information. In
either case, the SDK needs help from a developer to know this in design time.
The `@MediaType` annotation exists for this purpose. Every source or operation that returns a
`String` or an `InputStream` is forced to have this annotation, even if the specified mediaType is
`**/**`.
For example, suppose you are developing an operation that returns information about a customer. Also
suppose that this operation returns the information in XML format. You can do this:
```java
@MediaType(MediaType.APPLICATION_XML)
public String getCustomerInfo(String customerId) {
return fetchCustomerXml(customerId);
}
```
Or suppose you are developing a video streaming module that returns videos in `mp4` format:
```java
@MediaType("video/mp4")
public InputStream getVideo(String videoId) {
return getVideoStream(videoId);
}
```
> [!TIP] The `@MediaType` annotation defines a set of constants with the most common media types.
> However, as shown in the video media type example, you can use whatever custom \`mediaType \`you
> need.
## Strict False Media Types
In the examples above, it is impossible for operations to return a media type other than the one
specified. In other cases, you might know what the media type is _most likely_ to be, or you simply
do not know what the `mediaType` is. For these cases, the `@MediaType` annotation has a
`strict = false` option.
### Variable Media Type
Returning to the example that gets a customer information operation, suppose that the service to
which you are connecting returns XML by default, but you could also configure your particular
account to use a different format instead. Also suppose there is no way for you to know this
beforehand. You can do this:
```java
@MediaType(value = MediaType.APPLICATION_XML, strict = false)
public String getCustomerInfo(String customerId) {
return fetchCustomerXml(customerId);
}
```
Setting the `strict` parameter to `false` automatically adds an `outputMimeType` parameter to the
operation. This parameter allows the module’s user to manually override the `mimeType`. So, users
who know that their account and are configured to use JSON can do this:
```xml
```
### Unknown Media Type
Consider the case of an HTTP request. Depending on which endpoint you hit, the obtained media type
changes. Because you do not know which media type you will get, you use the `ANY` (`**/**`) one.
```java
@MediaType(value = "*/*", strict = false)
public InputStream request(String path) {
return httpClient.request(path);
}
```
Again, the `strict = false` attribute allows the end user to manually set the `mimeType` depending
on the endpoint:
```xml
```
> [!TIP] The `outputMimeType` parameter that is automatically added is optional and has no default.
> The user can just leave it blank. In that case, the SDK uses the media type you set in the
> annotation.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Error Handling
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## Defining Error Types
The module **must** define an error type for all business related or technical conditions that can
be expected and make sense for the user to want to handle specifically.
Examples of conditions that **should** have a matching error type:
- Entity referenced by ID does not exists
- Account has no funds
- User is unauthorized
- User lacks privileges to perform a certain action
- Remote system is at capacity
Examples of conditions that **should not** have a matching error type:
- Network error
- Unexpected server error
- Unknown error
## Use Error Hierarchies
Mule 4 Error types support the concept of hierarchies. That means that an error can stand on its
own, or it can be a child of another ErrorType defined in the same module or defined as a generic
Mule Error.
Leveraging Mule 4 error handling allows the user to reuse generic error handlers that tackle generic
problems in consistent ways. For example, imagine a flow that uses multiple connectors in the same
flow and wants to trigger a specific alert when a connectivity issue appears. If all the connectors
in that flow use MuleErrors.CONNECTIVITY as the parent error for all connectivity problems, then
that becomes easy to accomplish.
The same applies internally for any module that defines error types that hold some kind of internal
relationship.
Here’s an example taken from the WebSockets connector:
```java
public enum WsError implements ErrorTypeDefinition {
CONNECTIVITY(MuleErrors.CONNECTIVITY),
CLIENT_SECURITY(MuleErrors.CLIENT_SECURITY),
SERVER_SECURITY(MuleErrors.SERVER_SECURITY),
BASIC_AUTHENTICATION(SERVER_SECURITY),
UNAUTHORIZED(CLIENT_SECURITY),
FORBIDDEN(CLIENT_SECURITY),
NOT_FOUND,
SERVICE_UNAVAILABLE,
NO_SUCH_SOCKET,
INVALID_SOCKET_ID,
NON_UNIQUE_SOCKET_ID,
REMOTELY_CLOSED,
INTERNAL_SERVER_ERROR;
private ErrorTypeDefinition extends Enum>> parent;
WsError(ErrorTypeDefinition extends Enum>> parent) {
this.parent = parent;
}
WsError() {}
@Override
public Optional>> getParent() {
return Optional.ofNullable(parent);
}
}
```
In this example you can see how:
- To define error types with parents
- The CONNECTIVITY error extends the Mule one
- The CLIENT\_SECURITY and SERVER\_SECURITY errors are defined
- BASIC\_AUTHENTICATION, FORBIDDEN, and UNAUTHORIZED errors extend CLIENT\_SECURITY and
SERVER\_SECURITY
- The set of other errors that are domain-specific and stand on their own
## Correct Use of Module Exception
The ModuleException class (or a custom subclass of it) **must** be thrown only when an error matches
a defined ErrorType. Unexpected or non-handable errors that do not have a matching ErrorType
**must** be thrown as regular exceptions.
## Avoid Proliferation of Error Types
A common anti-pattern is to excessively apply the concept of “one error type per business error”
into “one error type for every error detail”. An example of that is creating errors like
INVALID\_EMAIL, INVALID\_ID, INVALID\_NAME, INVALID\_CARD, and so on, that lead to an explosion of
types that makes the feature unusable.
The module **must** collapse error types of similar semantics and leverage the exception message
instead. So per the previous example, only one ErrorType called INVALID\_DATA **should** exist, and
then the exception message can provide additional context on whether the problem was the credit
card, client name, and so on.
Notice that this rule is closely related to the previous concept of “the error has to be handleable”
as it’s extremely unlikely that an end user will want to catch an invalid ID and invalid email
differently (simply think of how many times have you actually done that in Java in your life).
## Do Not Expose Exceptions or Error Types
Exception, ErrorTypeDefinition, and ErrorTypeProvider classes defined in the module **must not** be
exported as part of its API.
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: error, sdk, error handling, operations, try, catch, on error, propagate
---
# Errors Definition
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
In Mule, errors are a way of communicating that something went wrong and providing meaningful
information so that a user can take corrective action depending on the kind of error that was
thrown.
See [About Error Handling](https://docs.mulesoft.com/mule-runtime/latest/error-handling) for more detail.
## Defining Module Errors
The first step is to define all the errors that can be thrown by a Module. To do so, you define an
`enum` that implements the `ErrorTypeDefinition` interface. Each value defined in this `enum` is
considered to be an Error.
```java
public enum SimpleError implements ErrorTypeDefinition {
INVALID_PARAMETER,
TIME_OUT,
NOT_ALLOWED
}
```
### Errors Hierarchy
Module errors can only inherit from errors of the same module (values of the same `enum`) or Mule
errors. Mule errors are defined in `org.mule.runtime.extension.api.error.MuleErrors`.
Note that any error that does not define a parent error automatically inherits from `MULE:ANY`.
```java
public enum HierarchalError implements ErrorTypeDefinition {
INVALID_PARAMETER,
TIME_OUT,
NOT_ALLOWED,
ILLEGAL_ACTION(NOT_ALLOWED),
BAD_CREDENTIALS(MuleErrors.CONNECTIVITY);
private ErrorTypeDefinition extends Enum>> parent;
HierarchalError(ErrorTypeDefinition extends Enum>> parent) {
this.parent = parent;
}
HierarchalError() {
}
@Override
public Optional>> getParent() {
return Optional.ofNullable(parent);
}
}
```
### Registering Errors in the Module
The `@Extension` annotated class should be annotated with `@ErrorTypes` to indicate which errors a
Module handles. This annotation references an `ErrorTypeDefinition` `enum` containing the defined
errors.
```java
@Extension(name = "Foo")
@ErrorTypes(HierarchalError.class)
@Xml(prefix = "test-connector")
public class FooExtension {
// Content
}
```
## Specifying Errors That Can Be Thrown
After declaring all the possible errors in your Module, you need to provide the information that
binds the errors with the Operations that can throw them.
To do that, you need to implement an `ErrorTypeProvider`, which is a class that communicates the
errors that can be thrown by an Operation.
```java
public class ExecuteErrorsProvider implements ErrorTypeProvider {
@Override
public Set getErrorTypes() {
HashSet errors = new HashSet<>();
errors.add(HierarchalErrors.INVALID_PARAMETER);
errors.add(HierarchalErrors.BAD_CREDENTIALS);
errors.add(HierarchalErrors.ILLEGAL_ACTION);
return errors;
}
}
```
After defining the `ErrorTypeProvider`, you must bind it with the proper Operation. You bind it
using the `@Throws` annotation at the Operation level, for example:
```java
@Throws(ExecuteErrorsProvider.class)
public void execute(){
// operation body
}
```
In the Studio, an operation that is annotated with `@Throws` annotated Operation will provide a hint
to the user about the errors the operation can throw:

The XML looks like this:
```xml
```
## Throwing Errors
Errors are a Mule representation of a Java Exception that is bound to an specific Error.
There is no static binding between Errors and Exceptions. To communicate an error, the Operation
should throw `org.mule.runtime.extension.api.exception.ModuleException` or child exceptions of this
class, indicating in the Constructor the desired `ErrorTypeDefinition` to throw.
```java
@Throws(ExecuteErrorsProvider.class)
public void execute(){
try {
throw new IllegalStateException();
} catch (IllegalStateException e){
throw new ModuleException(HierarchalErrors.ILLEGAL_ACTION, e);
}
}
```
Also, a recommended practice is to wrap this logic inside new exception classes:
```java
public final class IllegalActionException extends ModuleException {
public IllegalActionException(Exception cause) {
super(HierarchalErrors.ILLEGAL_ACTION, cause);
}
}
```
> [!WARNING] Throwing an Error that is not declared in the `ErrorTypeProvider` of an Operation will
> result in an Unexpected Error Exception. Operations are not allowed to throw undeclared Errors.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, annotation, exclusive, optional
---
# Exclusive Optionals
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
When you are developing a module that provides several ways of configuring the same thing, but only
one of them should be used, you might need to set the following rule:
- From a given set of parameters, only one shall be used at any time.
You use `@ExclusiveOptionals` to enforce this restriction.
## @ExclusiveOptionals
The `@ExclusiveOptionals` annotation can only be used on types that are used as a `@ParameterGroup`
(see [Parameters](https://docs.mulesoft.com/mule-sdk/latest/parameters) for details).
Example
```java
@ExclusiveOptionals
public class ExclusiveOptionalsExample {
@Parameter
private String requiredParameter;
@Parameter
@Optional
private String optionalParameter;
@Parameter
@Optional
private String anotherOptionalParameter;
}
```
As the name of the annotation implies, the exclusivity restriction only applies to the optional
parameters. So, setting `requiredParameter` at the same time as `optionalParameter` or
`anotherOptionalParameter` is allowed, but setting `optionalParameter` and
`anotherOptionalParameter` at the same time causes an error to be thrown.
Tip: You can have as many parameters as you want inside an object that is annotated with
`@ExclusiveOptionals`, but only one optional parameter is allowed to be set at any time.
## Enforcing At Least One Parameter
There can be cases where exactly one (but no more than one) of the optional parameters must be set.
You can configure this requirement by using `@ExclusiveOptionals(isOneRequired = true)`, for
example:
```java
@ExclusiveOptionals(isOneRequired = true)
public class OneRequiredExample {
@Parameter
private String requiredParameter;
@Parameter
@Optional
private String optionalParameter;
@Parameter
@Optional
private String anotherOptionalParameter;
}
```
So, an error is thrown if you set `requiredParameter` but do not set one of the optional parameters:
`optionalParameter` or `anotherOptionalParameter`.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, extensions api, deprecated, legacy
---
# Extensions API (Deprecated)
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
This page documents the legacy approach to SDK versioning using `mule-modules-parent`. For new
modules, see [Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility) with `mule-java-extension-parent`
instead.
In traditional SDK development, the SDK version is tightly coupled to the Mule runtime engine
version. When you develop with the SDK, you use the Extensions API. Whenever you annotate a field or
method with SDK annotations, or implement any interface, you are using parts of this Extensions API.
The module you ship contains only your code. The Extensions API implementation in the runtime
bridges the gap between your module and the Mule runtime internals.
## SDK Version and Mule Runtime Compatibility
Each Mule runtime version ships with support for one particular version of the Extensions API, plus
all previous versions.
For example:
- Mule `4.1` ships with SDK version `1.1`
- Mule `4.2` ships with SDK version `1.2`
Mule `4.2` fully supports modules developed with SDK versions `1.2`, `1.1`, and `1.0`. However, a
module built with SDK `1.2` requires at least Mule `4.2`, it won’t work in Mule `4.1`.
This concept works both ways:
- Any Mule runtime version supports all earlier SDK versions, so a module built for Mule `4.1` works
with any later Mule 4.x version
- If a module is built using SDK `1.2`, it only works in runtimes that support that SDK version
## Choosing a Version
When using the legacy approach, use the oldest SDK version that includes all the features you need:
- If you need only basic connectivity and DataSense, use version `1.0`
- If you need `PollingSource`, use SDK `1.1` which introduced that feature
This ensures your module is compatible with the widest range of Mule runtime versions.
## Change the Version
The SDK version is specified in the `parent` element of your `pom.xml`:
```xml
org.mule.extensions
mule-modules-parent
1.9.0
```
To change versions, update the `` in the parent element. Choose the `mule-modules-parent`
version that corresponds to your target Mule runtime version.
## Bug Fixes
The Extensions API implementation resides in Mule runtime, so most SDK-related bug fixes are
released in patch releases and service packs for Mule, not through new SDK versions.
In some cases where the issue is in the API definition, a patch release of the SDK is made available
(for example, `1.1.2`). Always choose the higher bug fix version—between `1.0.0` and `1.0.4`, pick
`1.0.4`.
## See Also
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
- [Choosing the SDK Version](https://docs.mulesoft.com/mule-sdk/latest/choosing-version)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, SDK, library, dependency, external, jar, maven
---
# External Libraries
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Connectors and Modules sometimes depend on external libraries that cannot be packaged inside the
connector due to licensing, versioning, custom libs, and so on.
The Database connector is an example of a case where the same base code you can work with several
different drivers and several versions of a same driver. The solution to this problem is ask users
of the Database connector to identify the JDBC Driver to use for the database to which they want to
connect.
## Usage
To declare that the Connector or Module requires an external library to work in a Mule app, you need
to annotate your `@Extension`, [Configuration](https://docs.mulesoft.com/mule-sdk/latest/configs), or [ConnectionProvider](https://docs.mulesoft.com/mule-sdk/latest/connections) class
with the `@ExternalLib` annotation and provide properties that will help the Mule App developer
understand how to configure these libraries.
> [!TIP] To help your users configure libraries more easily, it is highly recommended that you fill
> out all the properties that the annotation provides, for example:
-
```java
@ExternalLib(name = "MySQL JDBC Driver",
description = "A JDBC driver that supports connection to the MySQL Database",
nameRegexpMatcher = "(.*)\\.jar",
requiredClassName = "com.mysql.jdbc.Driver",
coordinates = "mysql:mysql-connector-java:5.1.44")
public class MySqlConnectionProvider implements ConnectionProvider {
//
}
```
\+ Note that a Connector can require multiple external libraries. The `@ExternalLib` annotation can
be used many times as needed.
### Properties
Property Required Type Description name
true
String
Friendly name to be displayed in the UI.
description
false
String
Short description of the external library.
nameRegexpMatcher
false
String
Regular expression used to match the name of the library’s file and validate that the library specified by your user is the correct one.
requiredClassName
false
String
(Only for Java Libraries) Name of a Class that will be present in the external library. This will be used for validating whether the library specified by your user is the correct one.
type
true
Enum
NATIVE: Native library dependency
JAR: JAR file dependency
DEPENDENCY: External dependency (for example, an obtained dependency that is specified in the pom.xml if you are using Maven)
For custom connectors, all Maven dependencies must be accessible from Anypoint Exchange. Maven dependencies published to private or public repositories are not accessible from Anypoint Exchange.
You can publish Maven dependencies before publishing your custom connector by using one of the following options:
Publish the Maven dependencies on Anypoint Exchange to make them available to your Anypoint Platform organization.
Publish the Maven dependencies on the Maven Central repository to make them publicly available.
You cannot use MuleSoft repositories for publishing.
coordinates
false
String
Maven coordinates suggestion that indicates where the required library can be found. They should follow Maven’s convention groupId:artifactId:packaging:classifier:version.
optional
false
Boolean
Indicates whether the library is not required for the Connector or Module to work.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Field-Level Capabilities
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Java SDK includes several features that support field-level capabilities for value providers and
sample data. Using these features enables you to define value providers for parameter fields, or to
use parameter fields as acting parameters for either a value provider or sample data.
These features are compatible with Mule 4.4.0, however, all Anypoint Connectors can use these
features, regardless of their Mule version.
## Defining a Value Provider for One Part of a Parameter
Define a value provider for a parameter field by using the annotation `@FieldValues`.
The `@FieldValues` annotation requires:
- **value**
Provides values for a field.
- **targetSelectors**
Describes which part of a parameter contains the values supplied by the value provider. The
DataWeave syntax defines this part of the annotation to describe the selector through nested
fields, XML attributes, or fields that contain spaces in their names.
The following example shows an operation that includes values provided for a parameter named `body`,
which is a JSON input stream:
public class ChatOperations { public void sendChatMessage(@Connection ChatConnection chatConnection,
@FieldValues(value = WorkspacesValueProvider.class, targetSelectors = "routingInfo.workspace")
@TypeResolver(ChatMessageResolver.class) @Content InputStream body) { // Do message sending } }
The `body` parameter has a field named **routingInfo**, which has a field named `workspace`.
**WorkspacesValueProvider** is a value provider that uses the connection and retrieves possible
workspaces.
## Defining a Value Provider for Several Parts of a Parameter
Parameters can have more than one part where values are provided. The `@FieldValues` annotation is a
repeatable annotation, so parameters can be annotated multiple times.
The following example shows an operation with a parameter named `body`, which is a JSON input stream
that has two parts with value providers:
public class ChatOperations { public void sendChatMessage(@Connection ChatConnection chatConnection,
@FieldValues(value = WorkspacesValueProvider.class, targetSelectors = "routingInfo.workspace")
@FieldValues(value = ChannelIdValueProvider.class, targetSelectors = "channelId")
@TypeResolver(ChatMessageResolver.class) @Content InputStream body) { // Do message sending } }
The parameter `body` defines values for two fields (**routingInfo.workspace** and **channelId**)
that have values that are independent of each other.
## Defining a Multilevel Value Provider for Several Parts of a Parameter
Use multilevel value providers for several parts of a parameter.
For example, imagine that you want the values for the **channelId** field to depend on the values
for the **routingInfo.workspace** field.
To define this, the **targetSelectors** attribute from the `@FieldValues` annotation always receives
an array of strings. If more than one string is given, a multilevel value provider is defined. Each
given field defines the value parts of the value provider, the order in the array, and the order of
the value part.
The following example shows how to define multilevel value providers for parameter parts:
public class ChatOperations { public void sendChatMessage(@Connection ChatConnection chatConnection,
@FieldValues(value = ChatMultiLevelValueProvider.class, targetSelectors = {"workspace",
"channelId"}) @TypeResolver(ChatMessageResolver.class) @Content InputStream body) {} }
The multilevel value provider is included like any other value provider.
The following is an example of what a multilevel value provider looks like:
public class ChatMultiLevelValueProvider implements ValueProvider {
@Connection private ChatConnection chatConnection;
@Override public Set resolve() { Set values = new HashSet<>(); List workspaces
= chatConnection.getWorkspaces(); workspaces.stream().forEach(workspace -> { ValueBuilder
valueBuilder = newValue(workspace); chatConnection.getChannels(workspace).stream().forEach(channel
-> valueBuilder.withChild(newValue(channel))); values.add(valueBuilder.build()); }); return values;
}
@Override public String getId() { return "Chat multilevel value provider"; } }
## Defining a Value Provider for XML Attributes
Target selectors use the DataWeave syntax. If a parameter of an operation is an XML element, use
this syntax to define a value provider for an attribute that is a part of that parameter.
The following example shows how the DataWeave syntax defines a value provider for an attribute:
public class ChatOperations { public void sendChatMessage(@Connection ChatConnection chatConnection,
@FieldValues(value = ChannelIdValueProvider.class, targetSelectors = "message.target.@channelId")
@TypeResolver(XmlChatMessageResolver.class) @Content InputStream body) {} }
In this example, the `body` parameter is an XML element that has a root tag named **message**, which
has a **target** that has the **channelId** attribute and an associated value provider.
## Parameters Static Metadata
When resolving acting parameter values, always know the media types of the parameters from the
component that executes the extraction expression and that gives the acting parameter its value.
Use the static metadata of the parameter to retrieve the media type of the parameter. For example,
if the parameter is a JSON input stream but the static metadata does not reflect this, the parts of
the parameter cannot be used as acting parameters.
## Define Acting Parameters as Parts of Parameters
To define acting parameters as parts of parameters, components must define bindings for their
references for value providers and sample data providers. These bindings enable an acting parameter
of the provider to take the value of the evaluated DataWeave expression.
When no binding is defined for an acting parameter, the same implicit binding is applied. The name
of the acting parameter must be the same as the name of the parameter in the component to take that
parameter’s value.
Use the `@Binding` annotation to define an acting parameter. The `@FieldValues` annotation and the
`@SampleData` annotation takes an array of bindings to define the values the acting parameter takes.
A defined binding declares the value that an acting parameter takes by providing an extraction
expression. This extraction expression is a DataWeave expression that uses only selectors to
retrieve the value for the acting parameter.
The extraction expression used for the extraction of the value of the acting parameter has some
limitations:
- It does not aggregate any data from the context. It is limited to access only the value of a field
in the parameter.
- The first part of the extraction expression corresponds only to the name of a parameter from the
component.
- The output media type is always `application/java` when executing the extraction expression to
give values to the acting parameters of a value provider or sample data provider. This means that
the provider does not expect other media types, such as `application/json` or `application/xml`.
The available context for the expression has the value of all the component’s parameters. The
expression must start with the name of the parameter of the component. If the value comes from a
part of the parameter, the expression follows the selector to the desired field.
The following example shows a parameter named `body` that has a field with values that depend on the
acting parameter `workspace`:
public class ChatOperations { public void sendChatMessage(@Connection ChatConnection chatConnection,
@FieldValues(value = ChannelsValueProvider.class, targetSelectors = "channelId", bindings =
{@Binding(actingParameter = "workspace", extractionExpression = "body.routingInfo.workspace")}))
@TypeResolver(ChatMessageResolver.class) @Content InputStream body) { // Do message sending } }
This acting parameter is taken from the same `body` parameter.
The following syntax shows the value provider used in this example:
public class ChannelsValueProvider implements ValueProvider {
@Connection private ChatConnection chatConnection;
@Parameter private String workspace;
@Override public Set resolve() { return
ValueBuilder.getValuesFor(chatConnection.getChannels(workspace)); }
@Override public String getId() { return "Channels value provider"; } }
The `workspace` acting parameter defined in the value provider is bound to the extraction expression
that takes the value of the field from the context of the component.
## Sample Data Example
The following example illustrates a `@SampleData` annotation that binds an acting parameter to the
value of a field of a parameter in the component:
public class ChatOperations { @SampleData(value = ChatMessageSampleDatatProvider.class, bindings =
{@Binding(actingParameter = "workspace", extractionExpression = "body.routingInfo.workspace")}))
public Result retrieveChatMessage(@Connection ChatConnection
chatConnection, @TypeResolver(ChatMessageResolver.class) @Content InputStream body) { // Do chat
message retrieval } }
**ChatMessageSampleDatatProvider** contains a parameter named `workspace` that provides the sample
data. The value of this acting parameter is taken from the extraction expression defined in the
binding.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, forward compatibility, RuntimeVersion, MuleVersion, conditional behavior
---
# Forward Compatibility Patterns
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
When building forward-compatible modules, you often need to use newer SDK features while providing
fallback behavior for older runtimes. The following patterns show how to implement conditional
behavior based on the Mule runtime version.
## Check the Mule Runtime Version
Use the `@RuntimeVersion` annotation to inject the current Mule Runtime version into your component.
You can apply this annotation to fields of type `org.mule.runtime.api.meta.MuleVersion`.
> [!NOTE] The `mule-sdk-api` artifact has a dependency on `mule-api` for basic APIs that aren’t
> intended to evolve over time. `MuleVersion` is one of these stable APIs, so there’s no
> `org.mule.sdk.api` counterpart for it. You can safely use `org.mule.runtime.api.meta.MuleVersion`
> in forward compatible modules.
```java
import org.mule.runtime.api.meta.MuleVersion;
import org.mule.sdk.api.annotation.RuntimeVersion;
public class MyOperations {
@RuntimeVersion
private MuleVersion runtimeVersion;
public void myOperation() {
if (runtimeVersion.atLeast("4.12.0")) {
// Use newer feature
} else {
// Use fallback behavior
}
}
}
```
The `MuleVersion` class provides methods to compare versions:
Method Description atLeast(String version)
Returns true if the Mule runtime version is equal to or greater than the specified version.
atLeastBase(String version)
Returns true if the base version (ignoring patch level) is equal to or greater than the specified version.
The runtime version is constant across your module, so @RuntimeVersion applies only at the field
level. Centralize your version-dependent logic in a shared field rather than checking in every
operation.
## Call New Methods in Existing APIs
SDK APIs can add new methods in later versions. If you call a method that doesn’t exist on an
earlier Mule runtime version, you get a `NoSuchMethodError`.
The SDK doesn’t introspect which methods your code actually calls. Even if a method has
`@MinMuleVersion("4.12.0")`, using it doesn’t automatically raise your component’s Minimum Mule
Version. You are able to deploy a module to earlier versions where the method doesn’t exist. For
this reason, you must check the Mule runtime version before calling new methods, and provide
fallback behavior for older versions.
### Example: Using a New Method with Fallback
The following example shows how to conditionally call a method that exists in Mule 4.12.0 and later:
```java
import org.mule.runtime.api.meta.MuleVersion;
import org.mule.sdk.api.annotation.RuntimeVersion;
import org.mule.sdk.api.runtime.streaming.StreamingHelper;
public class MyOperations {
@RuntimeVersion
private MuleVersion runtimeVersion;
public void processStream(InputStream stream, StreamingHelper streamingHelper) {
if (runtimeVersion.atLeast("4.12.0")) {
// Use new reset() method available in 4.12.0
streamingHelper.reset(stream);
} else {
// Implement fallback for older runtimes where reset() doesn't exist
if (stream instanceof Cursor) {
((Cursor) stream).seek(0);
} else {
stream.reset();
}
}
}
}
```
If no fallback is possible, explicitly annotate your operation with `@MinMuleVersion` to restrict it
to compatible versions.
## Use Newer APIs Without Raising Minimum Version
If you use a newer API but provide fallback behavior for older Mule runtime versions, you can
prevent that API from raising your component’s Minimum Mule Version. Combine Mule version checking
with `@DoNotEnforceMinMuleVersion` to keep your component available on earlier versions while using
new features when available.
```java
import org.mule.runtime.api.meta.MuleVersion;
import org.mule.sdk.api.annotation.DoNotEnforceMinMuleVersion;
import org.mule.sdk.api.annotation.RuntimeVersion;
public class MyOperations {
@RuntimeVersion
private MuleVersion runtimeVersion;
public void myOperation(@DoNotEnforceMinMuleVersion NewFeatureType input) {
if (runtimeVersion.atLeast("4.12.0") && input != null) {
// Use new feature when available
} else {
// Fallback behavior for earlier versions
}
}
}
```
The `input != null` check is necessary because parameters with types from `org.mule.sdk.api` resolve
to `null` on earlier versions that don’t recognize the type. By combining the version check with
`@DoNotEnforceMinMuleVersion`, you:
- Prevent the API from raising your component’s Minimum Mule Version
- Safely use the feature on later Mule versions
- Provide fallback behavior when the feature isn’t available
## Best Practices for Forward-Compatible Code
Follow these guidelines when implementing version-dependent behavior:
- Check versions before calling new methods
Failing to do so causes `NoSuchMethodError` at runtime.
- Centralize version checks
Use a shared field annotated with `@RuntimeVersion` rather than checking in every method.
- Test on multiple Mule runtime versions
Verify your fallback logic works correctly on the earliest Mule version you support.
- Document runtime-specific behavior
If a feature behaves differently on earlier versions, document this for your users.
## See Also
- [Controlling Version Propagation](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-enforcement)
- [Working with Minimum Mule Versions](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-min-mule-version)
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
- [HTTP-Based Connectors](https://docs.mulesoft.com/mule-sdk/latest/http-based-connectors) for the forward-compatible `org.mule.sdk.api.http`
client API
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# General Coding Rules
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
This set of general rules applies to any component of a module or connector. These apply on all
operations, sources, configs, connection providers, and functions).
## Connectors Must Closely Reflect the Target System
In the context of Anypoint Platform, a connector’s purpose is to bring the target system into the
Mule language. The connector **must not** add higher-level abstractions or include operations that
implement specific business use cases.
For example, imagine a billing API that contains resources for creating an invoice, adding items to
an invoice, and submitting an invoice. The connector for such an API **must** contain one operation
per each of those resources, but **must not** include an operation that combines all three calls
into a single unit.
The one exception is auto-paging operations, which, to achieve the paging effect, perform several
calls as part of processing the output of one single Mule operation.
## Do Not Mix Protocols
One connector **must** connect to only one type of protocol at a time. For example, suppose an
external system exposes a REST API, a SOAP API, and an OData API.
In Anypoint Platform, there are three different APIs, even if they access the same external system.
Therefore, each of those APIs **must** have its own connector, instead of one that understands the
three protocols.
## Exported Module Java API
Before reading this section, see [Classloading isolation](https://docs.mulesoft.com/mule-sdk/latest/isolation) in the Mule SDK.
The module **must** export only packages defined in your module. Packages from dependency libraries
**must not** be exported.
### Java Packages
Packages from the JDK are treated differently since modules don’t export them but only consume them.
Mule automatically exports all available Java packages for the modules to use.
However, the module **must** use only Java packages available on all of the JDKs supported by the
Mule versions that the module is compatible with. Vendor-specific packages such as com.sun **must
not** be used.
### Java Compatibility
See [Java Support](https://docs.mulesoft.com/general/java-support) to decide which Java version to use based on the
target Mule runtime.
#### Java 11 Compatibility
Starting with Mule 4.2.0, JDK 11 is also supported. That means that when depending on native Java
APIs, the module **must** account for the fact that the needed API might not be available given
Java’s new modular architecture (also known as
[Project Jigsaw](https://openjdk.org/projects/jigsaw/), first introduced in Java 9).
For example, if your module requires the Java Transaction API (JTA), the module **must** declare the
following dependency in its pom.xml file:
```xml
javax.transaction
javax.transaction-api
1.2
```
Or if the Java Mail API is used:
```xml
javax.mail
javax.mail-api
1.6.2
```
### Design for Thread Safety
Mule is a reactive execution engine, designed for highly concurrent workloads. Therefore, all
components **must** always be designed to support concurrent executions at minimal contention.
[Thread safety](https://en.wikipedia.org/wiki/Thread_safety) is a basic concept for any Java
developer familiar with concurrency. Users of the SDK are expected to be familiar with this.
## Use Immutable Payload and Attributes Objects
All output types, used as either payload or message attributes, **must** be immutable objects.
## Correct Use of Content Parameters
Make correct use of @Content parameters according to the MuleSoft
[Content Parameters](https://docs.mulesoft.com/mule-sdk/latest/content-parameters) document.
## Never Access Flow Variables
In Mule 4, variables are for exclusive access of end users only. No module **should** ever access
flow variables directly.
Although the SDK doesn’t provide any API for accessing them, optional parameters can be leveraged to
hack this restriction. For example:
```java
@Optional(defaultValue = "#[vars.foo]") String foo
@Optional(defaultValue = "#[vars]") Map> vars
```
However, these statements (or any other way of getting to the vars from inside a module) are
forbidden. Every piece of information required by the module **should** be made explicit through a
parameter. End users decide to assign that value to a variable or not.
Notice that violating this rule automatically violates position independence.
## Never Use Message Attributes as Parameters
No component **should** define a parameter of a type that’s also used as message attributes, even if
the attributes object is defined as part of the same module.
For example, if a connector has an operation that uses the LocalFileAttributes class as output
attributes, the following is illegal:
```java
public void checkAccess(@Content LocalFileAttributes attributes) {
doCheckAccess(attributes);
}
```
Instead, add parameters that reflect what information from the attributes class you actually need:
```java
public void checkAccess(String path) {
...
}
```
## Use Correct Encodings
When connecting to systems that accept multiple encodings, the encoding to be used **must** be
configurable through a [Configuration Override](https://docs.mulesoft.com/mule-sdk/latest/config-override). This means that the encoding to
use **should** be parameterizable at the config level, but also on each component that requires it
(operations, sources, functions, and so on).
At the config level, the encoding parameter **must** default to the Mule default encoding, which is
obtained through the @DefaultEncoding annotation.
For example:
```java
public class MyConfig implements Initialisable {
@DefaultEncoding
private String defaultEncoding;
@Parameter
@Optional
private String encoding;
public void initialise() throws InitialisationException {
if (encoding == null) {
encoding = defaultEncoding;
}
}
public String getEncoding() {
return encoding;
}
}
```
## Duration Parameters
Modules often require that you configure durations with classical examples such as timeouts and
cache evictions.
Durations **must** be expressed as the combination of two parameters:
- An int or Integer scalar parameter with the Timeout suffix
- A java.util.concurrent.TimeUnit parameter that qualifies the scalar
This parameter **must** be named exactly the same as its companion scalar except for adding the
TimeUnit suffix. The TimeUnit parameter **should** default to SECONDS.
For example:
```java
/**
* The socket connection timeout value. This attribute works in tandem with {@link #connectionTimeoutUnit}.
*/
@Parameter
@Optional(defaultValue = "5")
@Placement(tab = ADVANCED_TAB, order = 1)
@Summary("Socket connection timeout value")
private int connectionTimeout;
/**
* A {@link TimeUnit} that qualifies the {@link #connectionTimeout}
*/
@Parameter
@Optional(defaultValue = "SECONDS")
@Placement(tab = ADVANCED_TAB, order = 2)
@Summary("Time unit to be used in the Timeout configurations")
private TimeUnit connectionTimeoutUnit;
```
## Timeouts Must Have Configurable Configuration Overrides
All components that perform operations that could be affected by timeouts **must** make those
configurable through [Configuration Override](https://docs.mulesoft.com/mule-sdk/latest/config-override) parameters.
Such timeouts **must** be expressed as duration parameters.
## Only Primary @Content Should Default to Payload
No parameter other than a primary content **should** default to payload. This means that the
following **should** never be used:
```java
@Optional(defaultValue = "#[payload]")
```
## Handle Dates and Time Parameters
Date and time parameters **must** be implemented by using java.time.LocalDate,
java.time.LocalDateTime, or java.time.ZonedDateTime types. Do not use java.util.Date or
java.util.Calendar.
## Check the End-to-End Experience
Before publishing your module, test it in Anypoint Studio. Make sure it provides good usability and
a good experience. A module that works but is hard to use is not complete.
You **must** check for the following:
- DataSense is correctly resolved for all input parameters and output values.
- Each component’s parameter [layout](https://docs.mulesoft.com/mule-sdk/latest/parameter-layout) is correct.
- No typos exist in labels and descriptions.
- Users can easily build an application that uses the module’s main use cases.
## Discourage the Use of POJOs
The SDK allows using POJOs as both input parameters and output types. However, their use is
discouraged. All modules **should** make a best effort to use JSON or XML instead. In the case of
dynamic types, Java Maps may also be used.
This rule doesn’t mean that there’s no use case for using POJOs, nor that you need to convert all
structures to JSON or Java Maps. This rule is merely about favoring data formats that interoperate
better with other components and avoid serialization issues.
For example, suppose that your organization developed a Java taxes library that you want to leverage
in your Mule applications. If this library returns POJOs, it is okay for you to build an SDK module
that wraps this library, even if that means that this tax module will accept and produce POJOs.
Instead, if what you are leveraging is a Tax API that returns JSON, then your Tax connector
**should** return the same JSON as the API instead of transforming that JSON into a POJO.
## Expose POJOs
All POJOs that are exposed (because they’re being used as output types, input parameters, or message
attributes) **must** be DataWeave compliant. This means that all have a default constructor and a
getter method for each @Parameter annotated field.
## User Must Not Be Aware of Java Types
The user **must not** need to know the Java type used to implement a module in order to use it.
For example, consider the following transformation:
```json
{
name: "Pedro",
address: {
x: 11,
y: 12
}
} as com.foo.Person
```
The module **must** be defined in a way in which explicit transformations such as this are not
needed. Some ways of achieving this are:
- Don’t use POJOs to represent a person (recommended)
- Make com.foo.Person a DataWeave compliant concrete class
- When used as an input parameter, refer to com.foo.Person explicitly instead of using an abstract
type or interface
## Payload and Attributes Must Be Serializable
Message attributes objects returned by either operations or message sources **must** be Java
Serializable. Otherwise they cannot be used with ObjectStore, VM queues, or Mule in cluster mode.
## Don’t Access the MuleContext
The MuleContext is deprecated and **must not** be accessed by any module or connector.
Most of the time, the only reason for a module to access the MuleContext is to obtain certain
Runtime service. For example:
```java
muleContext.getRegistry().lookupByType(ObjectStoreManager.class)
```
Instead, use @Inject to obtain those services.
```java
public class MyComponent {
@Inject
ObjectStoreManager osm;
}
```
## Log Through SLF4J
All logging **must** be made through the SLF4J API.
The module **must not** add any dependency with this API as it’s already provided in the parent pom
file provided by MuleSoft.
## All Loggers Must Be Static
Loggers are expensive to create. Therefore, all loggers **must** be private, static, and final.
For example:
```java
public class Operation {
private static final Logger LOGGER = LoggerFactory.getLogger(Operation.class);
...
}
```
## Avoid Static State
All module classes **must not** contain a static state. The only exceptions are Loggers and the
serialVersionUID of Serializable classes.
## Choose the SDK Version
Normally, developers tend to use the latest available version of any given product. This **should
not** be the case with the SDK. To extend Mule, you should:
- Identify the features you need
- Choose the lower version that includes the features you need.
For more on selecting the correct SDK version, see [Choosing the SDK Version](https://docs.mulesoft.com/mule-sdk/latest/choosing-version).
## Do Not Use Boxed Booleans
Boolean parameters **must** be of the native boolean type. A boxed Boolean is not allowed as a
parameter type.
All boolean parameters are considered optional and **must** default to false. You can use the
@Optional annotation to change the default of a boolean, but you can never make it a required
parameter.
## Use Plural Names for List Parameters
All parameters implemented as a Java Collection, Map, or Array, or any other type that represents an
array of some sort, such as a JSON array, **must** have a plural name.
## Use Semver Versioning
Modules **must** be versioned using the [Semantic Versioning](https://semver.org/) standard.
## Use Strict Camel Casing
The entirety of the module’s source code **must** correctly apply camel casing. This is critical
since otherwise the SDK will not be able to correctly generate the XML DSL or process layouts.
## Specify Java Compatibility
Specify the Java compatibility of your custom module. In Mule 4.6.0 and later, custom modules that
do not specify the Java compatibility are assumed to be compatible with Java 8 and Java 11 only. If
your custom module is compatible with a more recent Java version, you must specify the Java
compatibility to include that version.
For more information, refer to [Java Version Support](https://docs.mulesoft.com/mule-sdk/latest/java-version-support).
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, create, new, project, getting, started
---
# Getting Started with the Mule SDK for Java
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Create your first Mule SDK project in just a few steps:
1. Install the required software.
2. Generate a project using Maven and explore it.
3. Set up your IDE.
4. Build the project you generated.
5. Develop a connector or module.
6. Run the connector or module in Anypoint Studio.
The SDK provides a Maven plugin and a Maven archetype to create new projects. The archetype is a
project template; use it to ensure your new project has a consistent structure, employs recommended
practices, and contains a few elements for you to experiment with.
## Install the Required Software
Install and verify that the following tools are working in your local environment:
- Java Development Kit 17 (JDK 17) or earlier to compile and build your custom Java code.
- For preexisting connectors, [JDK 8 might be needed](https://docs.mulesoft.com/mule-sdk/latest/java-version-support#jdk_8).
- Apache Maven 3.9.8 or later to manage your project’s build.
## Generate a Project Using the Maven Plugin
Run the `generate` command to create an extension project based on the Maven archetype:
mvn org.mule.extensions:mule-extensions-archetype-maven-plugin:1.11.0:generate
You are prompted to provide required field values, then a new project is generated.
## Explore the Generated Project
The generated project contains the basic Mule [module structure](https://docs.mulesoft.com/mule-sdk/latest/module-structure) with some basic
classes, a dummy implementation, and two running tests that use the generated module.
Because this project is a Maven project, it contains a `pom.xml` file that contains all the
information and configuration details used by Maven to perform the build. This generated POM file
inherits from the module’s parent POM, which contains all the common configurations and defaults for
all Mule module projects. The parent `pom.xml` file does not include any release information, so you
must add the release repository to the parent `pom.xml` file manually.
```xml
org.mule.extensions
mule-java-extension-parent
1.11.0
```
> [!NOTE] The generated POM defines a Minimum Mule Version by default, that version must be
> compatible with the target Mule version. See [Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility) for
> more information on how to configure and work with Minimum Mule Versions.
## Set Up Your IDE
For the SDK to work, you must pass the command line parameter `-parameters` to the Java compiler.
### For Development in IntelliJ
If you are using IntelliJ:
1. Go to **Preferences > Build, Execution, Deployment > Compiler > Java Compiler**.
2. Add `-parameters` in the **Additional command line parameters** section.

## Build the Project
After your project is generated, build it:
mvn clean install
This command compiles your project, runs the tests, and installs the project in your local Maven
repository.
## Develop Custom Module Code
Find the `@Extension` annotated class and examine [module structure](https://docs.mulesoft.com/mule-sdk/latest/module-structure) and the
different elements that you can add to a module. Use these elements to modify a connector.
## Add a Custom Icon to Your Connector
Connector icons are files in the .svg format. To customize the icon of a connector, add an
`icon.svg` file that contains the custom icon under the `icon` folder in the root of the connector
tree.
The following image shows an example of the folder structure for the icon:

After you add the custom icon to your connector, the icon appears in Anypoint Exchange and in
Anypoint Studio.
## Add Your Connector to Studio
Once your connector is working, you can try it in Anypoint Studio.
Go to your Mule app `pom.xml` file and add the connector as a `` with its `groupId`,
`artifactId`, and `version`.
Example: Dependency
```xml
...
...
org.mule.connector
mule-connector
1.0.0
mule-plugin
...
...
```
> [!NOTE] Different features are available in different versions of the SDK for Java. See
> [Choosing the SDK version](https://docs.mulesoft.com/mule-sdk/latest/choosing-version) to pick the right version for your connector.
## Publish Your Connector or Module to Anypoint Exchange
After you run your connector or module in Studio, publish your connector or module to Anypoint
Exchange. For more information, refer to
[Publishing Assets Using Maven](https://docs.mulesoft.com/exchange/to-publish-assets-maven).
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, security, oauth
---
# Handling Expired Access Tokens
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Most services providers return (or should return) access tokens with a limited lifespan. In general,
access tokens usually expire about 30 to 60 minutes after being issued, although this is not a
standard that strictly enforced by providers.
In the same way, providers often provide a refresh token with the access token. The refresh token is
a second token that can be used to replace an expired access token with a fresh one, without the
need to perform the dance again.
Unfortunately, there is no enforced standard that the SDK can use to automatically detect a token
expiration scenario and obtain a new one. Different APIs communicate that in different ways. That is
why the `AccessTokenExpiredException` exception exists.
```java
public void someOperation(@Connection SalesforceRestClient client) { (1)
Response response = client.performSomeOperation(); (2)
if (response.getStatusCode() == 401) { (3)
throw new AccessTokenExpiredException(); (4)
}
}
```
1 The example above uses an imaginary REST client to perform an operation. It assumes that this rest client was created through a ConnectionProvider annotated with @AuthorizationCode. 2 It performs the operation and gets a Response object that contains information of the HTTP call. 3 The example assumes that a status code of 401 (unauthorize) means that the token has expired. 4 It throws the AccessTokenExpiredException.
When the SDK detects this exception, it automatically performs the refresh dance and retries the
operation with a new access token.
Note that in real life, different APIs notify you of the access token expiration in different ways.
Some give you clients that throw exceptions, while others give you custom messages. You need to
research the remote API to determine the best way to account for this.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# HTTP-Based Connectors
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
There is a special set of considerations for connectors that access a remote system by either
issuing HTTP requests or exposing HTTP endpoints.
## Use the Mule HTTP Client
The Mule HTTP Client **must** be used for making HTTP requests. Other HTTP clients (such as the
Jersey client, Apache HTTP Client, Jetty, Netty, and so on) **should not** be used in favor of the
Mule HTTP client.
The only exception to this rule is when the remote system vendor already provides a client library
that has some level of added value that would be too difficult to replicate with the use of the Mule
HTTP Client.
For example, the Amazon AWS connectors work by consuming an HTTP API that requires custom message
signing. Amazon provides a client library that encapsulates the logic necessary to make such
signing.
However, a client library that does nothing but wrap an HTTP client for convenience (like the Google
clients) is not a valid exception to this rule.
### Create the HTTP Client
There are two APIs for creating a Mule `HttpClient`:
- The `org.mule.sdk.api.http` API (recommended). Its entry point is
`HttpService.client(Consumer)`. Because `mule-sdk-api` is bundled with your
connector and isn’t coupled to the Mule Runtime lifecycle, a connector can use this API to consume
newer HTTP features without raising its Minimum Mule Version. Use this API for new connectors and
when migrating an existing connector that needs newer HTTP capabilities. See
[SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility) for more about forward compatibility.
- The legacy `org.mule.runtime.http.api` API, whose `HttpClient` is created from an
`HttpClientConfiguration` builder through `httpService.getClientFactory().create(…)`. This API
remains fully supported and is a valid choice when your connector’s Minimum Mule Version already
permits it. See [Use the Legacy org.mule.runtime.http.api HTTP Client](#legacy-http-client).
#### Use the org.mule.sdk.api HTTP Client
Inject the `org.mule.sdk.api.http.HttpService` and call `client(…)` with a callback that configures
the client through an `HttpClientConfigurer`:
```java
@Inject
private HttpService httpService;
HttpClient client = httpService.client(configurer -> configurer
.setName("client-name")
// other setters...
);
```
The `HttpService.client(…)` method returns an `org.mule.sdk.api.http.client.HttpClient` and throws
a `ClientCreationException` if the client can’t be created.
#### Configure the Client
The `HttpClientConfigurer` passed to the callback exposes these methods. Each one returns the same
configurer, so you can chain the calls:
Method Description setName(String)
Sets the name of the HttpClient. Base it on the name of the owning configuration (see [set-the-http-client-name] ).
setTlsContextFactory(TlsContextFactory)
Required for HTTPS. Provides the TLS data used to establish secure connections.
setMaxConnections(int)
Maximum number of outbound connections kept open at the same time. Unlimited by default.
setUsePersistentConnections(boolean)
Whether connections are kept open after a request completes. true by default.
setConnectionIdleTimeout(int)
Number of milliseconds a connection can remain idle before being closed.
setResponseBufferSize(int)
Size, in bytes, of the buffer used to store the HTTP response. Defaults to 10 KB.
setStreaming(boolean)
Whether the HTTP response is streamed, so processing continues as the body arrives.
setDecompress(Boolean)
Whether responses are decompressed automatically. false by default.
configProxy(Consumer<ProxyConfigurer>)
Configures a proxy for the client. See [provide-http-proxy-configuration] .
configHttp1(Consumer<Http1ProtocolConfigurer>)
Enables, disables, and configures HTTP/1-specific parameters.
configHttp2(Consumer<Http2ProtocolConfigurer>)
Enables, disables, and configures HTTP/2-specific parameters.
configClientSocketProperties(Consumer<TcpSocketPropertiesConfigurer>)
Configures TCP-specific properties, such as the socket connection timeout.
For the complete reference, see the `HttpClientConfigurer` interface (package
`org.mule.sdk.api.http.client`) in the `mule-sdk-api` javadoc.
#### Send a Request
The `HttpClient` implements `Startable` and `Stoppable`, so it **must** be started before use and
stopped when you no longer need it. Build requests with `HttpService.requestBuilder()` and send them
without blocking through `sendAsync(…)`, which returns a `CompletableFuture`:
```java
client.start();
HttpRequest request = httpService.requestBuilder()
.method(GET)
.uri("https://api.example.com/resource")
.build();
CompletableFuture future = client.sendAsync(request, options -> options
.setResponseTimeout(5000)
.setFollowsRedirect(true));
// ... use the response, then stop the client during the stop() phase
client.stop();
```
Because `sendAsync(…)` defers response body processing, handle the response on a different thread
when you need the full body right away. For example, with `CompletableFuture.whenCompleteAsync(…)`.
This avoids blocking the client’s I/O threads.
#### Migrate from the Legacy HTTP Client
If your connector currently creates its client with the legacy
`org.mule.runtime.http.api.client.HttpClient` and the `HttpClientConfiguration` builder, you can
move to the configurer-based API as follows:
- Replace the injected `org.mule.runtime.http.api.HttpService` with
`org.mule.sdk.api.http.HttpService`.
- Replace `httpService.getClientFactory().create(new HttpClientConfiguration.Builder()…build())`
with `httpService.client(configurer → …)`, mapping each builder setter to the equivalent
configurer method (for example, `.setName(…)`).
- Update the imports of `HttpClient`, `HttpRequest`, `HttpResponse`, and related types to their
`org.mule.sdk.api.http` counterparts.
> [!NOTE]
>
> - The new API delegates to the legacy one and **does not** deprecate it.
>
> - The legacy API remains valid. You can keep using it when your connector’s Minimum Mule Version
> already permits it.
>
> - Moving to the new API is the recommended path when a connector wants access to newer HTTP
> features without raising its Minimum Mule Version.
Because the new HTTP types come from `org.mule.sdk.api`, follow the guidance in
[Forward Compatibility Patterns](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-patterns) when you need to call newer methods
conditionally and provide fallback behavior for older runtimes.
#### Use the Legacy org.mule.runtime.http.api HTTP Client
The legacy API creates the `HttpClient` from an `HttpClientConfiguration` builder:
```java
httpClient = httpService.getClientFactory()
.create(new HttpClientConfiguration.Builder()
.setName(configName)
.build());
httpClient.start();
```
This API is still fully supported. Use it when your connector’s Minimum Mule Version already covers
it and you don’t need the newer HTTP features exposed by `org.mule.sdk.api.http`.
### Manage the Client in a Connection Provider
Regardless of which API creates the `HttpClient`, the connector’s `ConnectionProvider` is
responsible for managing it according to these rules.
- Handle the HTTP Client Lifecycle
The ConnectionProvider that creates the HttpClient is responsible for managing its lifecycle.
- Use Cached Connection Providers
Every ConnectionProvider that creates an HttpClient **must** implement the
CachedConnectionProvider interface.
Notice that this rule has implications on the connection object that the Connection Provider can
yield. Because of the previously discussed Connection Object **must not** expose (nor be) the
inner client rule, this means that the provided connection object needs to contain the HTTP client
as part of its state and **must** be thread safe.
- Use Startable and Stoppable Connection Providers
The Connection Provider **must** also implement the Startable and Stoppable interfaces. The
HttpClient **must** be created and started during the start() phase and **must** be stopped during
the stop() phase.
Lifecycle example:
```java
public class HttpConnectionProvider implements CachedConnectionProvider, Startable, Stoppable {
@Inject
private HttpService httpService;
@Parameter
private TlsContextFactory tlsContext;
@RefName
private String configName;
@Override
public void start() throws MuleException {
initialiseIfNeeded(tlsContext);
httpClient = httpService.client(configurer -> configurer
.setName(configName)
.setTlsContextFactory(tlsContext));
httpClient.start();
}
@Override
public void stop() throws MuleException {
if (httpClient != null) {
httpClient.stop();
}
}
// rest of the implementation removed for example simplicity
}
```
- Set the HTTP Client Name
The HttpClient created by each ConnectionProvider **must** have a name which is based on (or
simply matches) the name of the configuration that owns that ConnectionProvider.
This is very important for performance troubleshooting. Each HttpClient creates a set of selector
threads that it uses for I/O. Those threads are named after the client’s name. Giving those
threads a meaningful name is key for diagnosing performance problems.
The name of the owning config can be obtained using the @RefName annotation.
Here’s an example of how to do this:
```java
public class HttpConnectionProvider implements
CachedConnectionProvider, Startable, Stoppable {
@Inject
private HttpService httpService;
@RefName
private String configName;
@Override
public void start() throws MuleException {
httpClient = httpService.client(configurer -> configurer.setName(configName));
httpClient.start();
}
// rest of implementation removed for example simplicity
}
```
- Leverage Non-Blocking I/O in Operations
The HttpClient is capable of using non-blocking I/O to make the requests. Operations **must**
leverage this capability and also be defined as non-blocking.
- Do not reference Elements
The HttpService allows you to obtain the HttpClient associated with a separate
element. Although this capability exists, it is not meant to be used by
connectors. Connectors **must not** use this feature.
All connectors in need of a HttpClient instance, **must** create and manage their own.
- Provide HTTP Proxy Configuration
Connectors using HTTP Client instances must provide the ability to configure a proxy, similar to
HTTP Connector. Common reasons to use proxy configuration include security, maintenance, and proxy
caching. Many organizations also require proxy configuration when working behind firewalls.
The following code snippets show how to configure proxy, for example, for the OAuth endpoint in
HTTP Request Connector:
Use this global proxy configuration as a reference:
When configuring for the Client Credentials grant type, use the following snippet:
When configuring for the Authorization Code grant type, use the following snippet:
; ; ;
When using the `proxyConfig` type, the connection provider must include a `@Parameter` annotation
so that the connection refers to the proxy, for example:
```java
@Parameter
@Optional
@Placement(tab = "Proxy", order = 1)
private MyConnectorProxyConfiguration proxyConfig;
```
You must also set the proxy configuration in the HTTP Client:
```java
.setProxyConfig(connectionParams.getProxyConfig())
```
For more information, refer to the
[Java code](https://github.com/mulesoft/mule-http-connector/blob/9914ce6aa6ceb3aa16a5b821289f15b9c6af6acc/src/main/java/org/mule/extension/http/api/request/proxy/DefaultProxyConfig.java)
for how HTTP Connector handles the proxy.
## Exposing HTTP Inbound Endpoints
Some connectors need to expose their own HTTP inbound endpoints.
To achieve this, connectors **must** reference an external element to obtain
an HttpServer instance. Connectors **must not** create their own servers.
This **must** be achieved as follows:
- Correctly reference the listener config
The connection provider **must** expose a String parameter called listenerConfig. This parameter
**must** be of type String, not accept expressions, and use the @ConfigReference annotation to
indicate that it points to an element.
For example:
```java
@Parameter
@Expression(NOT_SUPPORTED)
@ConfigReference(name = "LISTENER_CONFIG", namespace = "HTTP")
private String listenerConfig;
```
- Add a RequestHandler
Using the listenerConfig parameter added above, a matching HttpServer instance can be obtained
like this:
```java
HttpServer httpServer;
try {
httpServer = httpService.getServerFactory().lookup(listenerConfig);
} catch (ServerNotFoundException e) {
throw new IllegalArgumentException(
format("Connector configuration '%s' refers to an with name '%s', "
+ "but such element doesn't exist", configName, listenerConfigName),
e);
}
```
With the obtained HttpServer, a new RequestHandler can be added using the
org.mule.runtime.http.api.server.HttpServer#addRequestHandler(java.lang.String,
org.mule.runtime.http.api.server.RequestHandler) method.
The connector **must** carefully follow the contract defined in the Javadocs for that method. Most
importantly, invoking that method will return a RequestHandlerManager instance. Those instances
**must** be kept by the connector as they expose two important methods: start() and stop().
The inbound endpoint will not be actually functioning until the start() method is invoked on the
RequestHandlerManager. At the same time, the endpoint does not go away until the stop() method is
invoked on the RequestHandlerManager.
That means that when the component owning the custom endpoint is stopped, so **must** the
RequestHandlerManager be stopped. Otherwise, your connector will generate a memory leak.
### Make Timeouts Configurable
The connector **must** expose a parameter that controls the timeout of the HTTP requests.
This **must** be done in a way that is consistent with the previously discussed rules about how to
handle duration parameters and making timeouts Config Override parameters.
## HTTPS Security
The connector **must** support the HTTPS scheme whenever possible and **must** consider it as the
recommended option:
- If the remote system supports only HTTPS, then the connector **must** have a required
TlsContextFactory parameter.
- If the remote system supports both HTTP and HTTPS schemes, then the connector **must** support
both options but log a warning when HTTP is used.
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Implicit Configurations
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Some configurations can be classified as implicit. A configuration can be used implicitly when none
of its parameters are required. For example, suppose a `myConfig` configuration object which has a
required parameter `param1`:
```java
```
Now suppose that the bar parameter were to turn optional instead:
```java
```
In this case, the entire my-config element (and subsequent config-ref) are redundant because they
have no real effect. In these cases, implicit configurations can be used:
```java
```
Because `my-config` does not have required parameters, the SDK can create an implicit instance in
which all parameters are automatically assigned to their default values. The implicit configuration
is either static or dynamic depending on its parameter’s default values. If any of those default
values is an expression, then the implicit configuration is dynamic.
> [!NOTE] Using an expression as a default value violates the best practice of the
> [position independence](https://docs.mulesoft.com/mule-sdk/latest/define-operations#position-independence).
## Mixing Implicit and Explicit Configurations
You can use implicit and explicit configurations in tandem:
```java
```
> [!TIP] Only one implicit `config` is created per configuration type. If two operations try to use
> implicit configurations of the same type, each uses the exact same instance:
```java
```
## Forcing Explicit Configurations
Available since version 1.3.
There are cases in which you might want to force configurations to always be explicit, even if they
contain no required parameters. Usually, such requirements revolve around clarity and usability
concerns.
Use the `@NoImplicit` annotation to instruct the SDK to never build implicit instances of a given
configuration type:
```java
@Extension(name="example")
@NoImplicit
@Operations(ExampleOperations.class)
public class ExampleModule {
@Parameter
@Optional
public String bar;
}
```
You can also use this annotation if your configuration has been externalized into a separate class:
```java
@Extension(name="example")
@Configurations(MyConfiguration.class)
public class ExampleModule {
}
@Configuration(name="myConfig")
@NoImplicit
@Operations(ExampleOperations.class)
public class MyConfiguration {
@Parameter
@Optional
public String bar;
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, forward compatibility, implicit parameters
---
# Implicit Parameters
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Implicit parameters are parameters that the Mule runtime engine automatically injects without
requiring configuration from the application developer. Examples include `StreamingHelper`,
`ComponentLocation`, and `CorrelationInfo`. These parameters don’t appear in the Extension Model.
## Implicit Parameter Types from org.mule.sdk.api
Starting with Mule 4.5, the runtime automatically treats parameters with types from
`org.mule.sdk.api` and its subpackages as implicit, enabling forward compatibility for new implicit
parameter types.
When you use a new implicit parameter type that was introduced in a later Mule version:
- On runtimes that support the type, the parameter is injected normally
- On earlier Mule runtime versions that don’t recognize the type, the parameter resolves to `null`
and the runtime treats the parameter as implicit, meaning it doesn’t appear in the Extension Model
and can’t be configured by the application developer.
## Handle Null Values
Implicit parameters from `org.mule.sdk.api` resolve to null on earlier Mule runtime versions. Your
code must handle this possibility:
```java
import org.mule.sdk.api.runtime.SomeNewHelper;
public class MyOperations {
public void myOperation(String input, SomeNewHelper helper) {
if (helper != null) {
// Use the helper on runtimes that support it
helper.doSomething();
} else {
// Fallback for older runtimes
}
}
}
```
> [!IMPORTANT] If the implicit parameter is essential to your operation and no fallback is possible,
> annotate the operation with `@MinMuleVersion` to restrict it to runtimes that support the
> parameter type.
## See Also
- [Forward Compatibility Patterns](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-patterns)
- [Working with Minimum Mule Versions](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-min-mule-version)
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: parameter, parameters, mule, sdk, dsl, xml, import, type
---
# Importing Types From Other Modules
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Every module can declare a set of types that are part of the module’s API. This set of types can
then be imported by other modules, while keeping the original module’s namespace definition.
Importing another module’s types is useful in many cases, including:
- Reusing the logic bundled inside the type, such as a specific authentication method.
- Exposing the user to the same API for configuring the same properties. For example, if you want to
configure the same parameters in the same order, with the same descriptions, you can enforce that
by using the same types in different modules.
You can reuse a module’s type in three steps:
1. Add the dependency in your `pom.xml` to the `mule-plugin` whose API you want to use:
```xml
org.mule.connectors
mule-sockets-connector (1)
${muleSocketsConnectorVersion}
mule-plugin (2)
```
1 The module where the Type is declared 2 Remember to add the mule-plugin classifier in the dependency
2. Declare an `@Import` in the Extension class referencing the type you want to import:
```java
@Extension(name = "HTTP")
@Import(type = TcpClientSocketProperties.class)
@Import(type = TcpServerSocketProperties.class)
public class HttpConnector {
}
```
3. Use the types in your parameters declaration:
```java
@Alias("request")
public class HttpRequesterProvider implements CachedConnectionProvider {
@Parameter
private TcpClientSocketProperties clientSocketProperties;
}
```
Notice how this changes the DSL declaration, since now your extension (in this case `http`) can
receive parameters declared in another namespace (in this example, `sockets`):
```xml
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, metadata, datasense, input, type
---
# Input Metadata
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
We refer as input Metadata to the type resolution for the Parameters of a Component. Each Parameter
can provide either Static or Dynamic Metadata isolated from what kind of Metadata do other
Parameters of the same Component expose. Only Operations can have Parameters with dynamic metadata,
while Sources, Configurations and Connections will always have static metadata for their Parameters.
## Declaring an InputTypeResolver
An `InputTypeResolver` implementation handles the request for resolving a `MetadataType` based on
the information provided by the `MetadataContext` and most importantly, using the `MetadataKey` to
identify which is the `MetadataType` required by the app developer. Refer to
[What is the Metadata of a Component](https://docs.mulesoft.com/mule-sdk/latest/metadata#component-metadata) for more information about the
`MetadataType`.
```java
public class InputEntityResolver implements InputTypeResolver {
@Override
public String getCategoryName() {
return "DocEntities";
}
@Override
public MetadataType getInputMetadata(MetadataContext context, String key)
throws MetadataResolvingException, ConnectionException {
final ObjectTypeBuilder objectBuilder = context.getTypeBuilder().objectType();
switch (key) {
case "Author_id":
objectBuilder.addField().key("name").value().numberType();
objectBuilder.addField().key("lastName").value().stringType();
break;
case "BookList_id":
objectBuilder.addField().key("genre").value().stringType();
objectBuilder.addField().key("bookIds").value().arrayType().of().stringType();
break;
case "Book_id":
objectBuilder.addField().key("title").value().stringType();
objectBuilder.addField().key("ISBN").value().numberType();
break;
default:
throw new MetadataResolvingException("Unknown key:" + key, INVALID_METADATA_KEY);
}
return objectBuilder.build();
}
}
```
In the example above, we are using the `MetadataContext` only to obtain the `typeBuilder`, but we
could also use the provided Configuration and Connection elements. For example, we could fetch the
Metadata from an external service using the Connection, or access an static resource present in the
Configuration like an schema.
## Using the InputTypeResolver
Now that we have a `TypesKeysResolver` and an `InputTypeResolver` we can add input DataSense support
on our Operations and Sources. The main restriction to use an `InputTypeResolver` along with a given
`TypesKeysResolver` is that both have to belong to the same `category`, so we can guarantee that the
`MetadataKey` provided by the `TypesKeysResolver` can be resolved to a `MetadataType` by the
`InputTypeResolver`:
```java
public class DemoOperation {
public void create(@Connection MyConnection connection,
@MetadataKeyId(EntityKeysResolver.class) String type,
@TypeResolver(InputEntityResolver.class) Map entity){
// Code that handles the creation based on the "type" of the "entity"
if ("Account_id".equals(type)){
//...
} else {
//...
}
}
}
```
Each Parameter can have its own `TypeResolver` each using any `InputEntityResolver`. This means that
both can have the same resolver thus describing the same MetadataType for the two parameters, or
using the same `MetadataKeyId` to describe two different `MetadataType`, one for each Parameter.
For example, we can do an entity merge using the same resolver for two parameters:
```java
public void merge(@MetadataKeyId(EntityKeysResolver.class) String type,
@TypeResolver(InputEntityResolver.class) Map first,
@TypeResolver(InputEntityResolver.class) Map second){
// Code that handles the merge based on the "type" of the "entity"
if ("BookList_id".equals(type)){
((List)first.get("bookIds")).addAll((List) second.get("bookIds"));
} else {
//...
}
}
```
Or we instead need to define two different `MetadataType` for each entity, but always bound to the
same `MetadataKeyId` (which is resolved only once) and, again, all belonging to the same `category`:
```java
public void crete(@MetadataKeyId(EntityKeysResolver.class) String type,
@TypeResolver(ItemTypeResolver.class) Map item,
@TypeResolver(ContainerTypeResolver.class) Map container){
// Code that handles the item based on the "type" of the "entity"
if ("developer".equals(type)){
createDeveloperInTeam(item, container);
} else {
//...
}
}
```
## Input Metadata with User defined MetadataKey
In the previous section we saw that when the `MetadataKeyId` parameter doesn’t declare a
`TypeKeysResolver`, then any key can be defined by the app developer when configuring the Operation.
Here is a simplified example of how the `MetadataKeyId` is used without a `TypeKeysResolver`, and
the value configured for that Parameter is used to resolve the input MetadataType of the
`queryParameters` in the Database Connector:
```java
public List> select(@MetadataKeyId String sql,
@TypeResolver(DbInputMetadataResolver.class) Map queryParameters,
@Config DbConnector connector){
//...
}
```
```java
public class DbInputMetadataResolver implements InputTypeResolver {
@Override
public String getCategoryName() {
return "DbCategory";
}
@Override
public MetadataType getInputMetadata(MetadataContext context, String query)
throws MetadataResolvingException, ConnectionException {
// The MetadataKey is the `query` parameter, we have to parse it to resolve
// all the Metadata of its parameters
QueryTemplate queryTemplate = parseQuery(query);
List inputParams = queryTemplate.getInputParams();
if (inputParams.size() == 0) {
// No input metadata when no input parameters
return context.getTypeBuilder().nullType().build();
}
PreparedStatement statement = getStatement(context, queryTemplate);
return getInputMetadataUsingStatementMetadata(statement, inputParams);
}
}
```
## Resolving dynamic Input Metadata without MetadataKey
Many times we don’t have multiple entities whose structure is unknown but just one, that has a
dynamic MetadataType depending, for example, on the credentials that the app developer is using to
connect to it’s sandbox. In that case, different accounts may see different properties for the same
`Organization` entity.
In order to declare a `KeyLess` InputMetadata resolution, just skip the `MetadataKeyId` Parameter
and use the `TypeResolver` without depending on the `MetadataKey`:
```java
public void createOrg(@TypeResolver(OrganizationTypeResolver.class) Map organization){
//...
}
```
```java
public class OrganizationTypeResolver implements InputTypeResolver {
@Override
public String getCategoryName() {
return "Organization";
}
@Override
public MetadataType getInputMetadata(MetadataContext context, Object key)
throws MetadataResolvingException, ConnectionException {
// The `key` parameter will be `null` if the fetch is performed
// as a `KeyLess` Metadata resolution. We'll just ignore it.
DemoConnection connection = context.getConnection()
.orElseThrow(() -> new MetadataResolvingException("A connection is required to resolve Metadata but none was provided",
FailureCode.INVALID_CONFIGURATION));
String schema = connection.getClient().describeOrganization();
return new JsonTypeLoader(schema).load("http://demo.org")
.orElseThrow(() -> new MetadataResolvingException("No Metadata is available for the Organization",
FailureCode.NO_DYNAMIC_TYPE_AVAILABLE));
}
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Java EE Libraries
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
In the first Mule runtime version that exclusively supports Java 17 (Mule 4.9.0), connectors can no
longer include Java EE libraries. To ensure backward compatibility, Mule versions 4.6.0 through
4.9.0 continue to export Java EE libraries as part of the Container API only when Mule runtime runs
on Java 8 or Java 11. However, if Mule runtime runs on Java 17 or higher, you must include the Java
EE libraries manually. For connectors that support multiple Java versions, such as Java 11 and Java
17, the Java EE libraries must match the versions included in Mule runtime.
Because Mule 4.6.x exposes Java EE libraries differently than earlier Mule versions, you must add
the BOM dependency to your connector and, if applicable, exclude the provided conflicting library.
You can also add the libraries in the BOM dependency separately.
```java
4.6.0
org.mule
mule-javaee-runtime-bom
${muleJavaEeBomVersion}
pom
import
```
## See Also
- [Upgrading Java for Custom Connectors (Customers)](https://docs.mulesoft.com/general/customer-connector-upgrade)
- [Upgrading Java for Custom Connectors (Partners)](https://docs.mulesoft.com/general/partner-connector-upgrade)
- [Java Support](https://docs.mulesoft.com/general/java-support)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Java Version Support
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Specify the Java compatibility of your custom module. In Mule 4.6.0 and later, custom modules that
do not specify the Java compatibility are assumed to be compatible with Java 8 and Java 11 only. If
your custom module is compatible with a more recent Java version, you must specify the Java
compatibility to include that version.
Communicating the Java compatibility of your custom module also ensures:
- Safe upgrades
Users can determine whether their Mule applications can safely upgrade to run on a given Java
version, ensuring a smooth transition and avoiding potential issues.
- User experience
Providing clear information about Java compatibility enhances the user experience, especially for
Anypoint Exchange users who rely on this information for selecting modules.
## Specify Java Compatibility
To specify Java compatibility of your custom module:
1. Generate metadata to specify Java compatibility of your custom module by adding or upgrading the
custom module `mule-sdk-api` dependency to the latest version, for example:
```xml
org.mule.sdk
mule-sdk-api
0.11.0
```
2. Add the `@JavaVersionSupport` annotation in the same class as the `@Extension` annotation and
include the supported Java versions as values, for example:
```java
import org.mule.sdk.api.annotation.JavaVersionSupport;
import org.mule.sdk.api.meta.JavaVersion;
@Extension(name = "Database")
@Operations(...)
@JavaVersionSupport({JavaVersion.JAVA_8, JavaVersion.JAVA_11, JavaVersion.JAVA_17})
public class DatabaseConnector {
..
}
```
> [!NOTE] If the `mule-modules-parent` version is earlier than 1.9.0, all code, including
> third-party dependencies, **must** be compiled for Java 8, and you must use Java 8 to build the
> connector.
You can mark your custom module as compatible with a single Java version only; however, you must
ensure that no adoption or backward compatibility issues exist.
When you deploy a Mule app, Mule verifies that all modules in the Mule app are compatible with the
Java version. If Mule finds an incompatibility, Mule throws an error and the application does not
deploy.
If your code is compatible with a given Java version but you do not declare that compatibility, you
can still get a successful test run (only when running a test on Java 8).
## See Also
- [Upgrading Java for Custom Connectors (Customers)](https://docs.mulesoft.com/general/customer-connector-upgrade)
- [Upgrading Java for Custom Connectors (Partners)](https://docs.mulesoft.com/general/partner-connector-upgrade)
- [Java Support](https://docs.mulesoft.com/general/java-support)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, module, extension, components, structure
---
# Learning the Module Model
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The entry point for building a Mule module is the `@Extension` annotated class. This class is used
to export all the module functionality and all the elements associated with it.
> [!WARNING] This class **must** be a public, non-abstract class. The `@Extension` annotation cannot
> be used on interfaces, abstract classes, private/protected classes, or typed classes (with
> generics).
```java
@Extension(name = "basic")
public class BasicModule {
}
```
When using the `@Extension` annotation, you need to provide a descriptive and concise name for your
module. You should not use `extension`, `module`, or `connector` in the module name. If you do, the
SDK will trim them. Optionally, you can specify the attribute `vendor` and the attribute `category`
(See [Licensing](https://docs.mulesoft.com/mule-sdk/latest/license)).
Once you have created an empty module, you can start adding elements to it.

Figure 1. Basic Module Structure
At a high level, the elements are:
- [Components](#components-2)
- [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations)
- [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources)
- [Functions](https://docs.mulesoft.com/mule-sdk/latest/functions)
- [Routers](https://docs.mulesoft.com/mule-sdk/latest/routers)
- [Scopes](https://docs.mulesoft.com/mule-sdk/latest/scopes)
- [Connection Providers](https://docs.mulesoft.com/mule-sdk/latest/connections)
- [Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs)
- [Parameters](https://docs.mulesoft.com/mule-sdk/latest/parameters)
## Components
Components are the key to the functionality of a module. Given a set of parameters, they can be
executed to produce or alter messages in a flow.
Sources and Operations are the most common components in a module:
- [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) are components that process an incoming message and generate a result.
- [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources) are components that receive or generate new messages to be processed by the
Mule Runtime.
## Configuration
Configurations are a set of configurable parameters that affect the behavior of the Module.
[Sources](https://docs.mulesoft.com/mule-sdk/latest/sources) and [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) typically depend on a Configuration for parameters
that determine their behavior. However, some can work on their own without a Configuration.
There is no requirement to declare a Configuration for a Module, but you can declare as many as you
need. Different configurations might provide a different set of parameters and specify a set of
[Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) and [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources) that are only available when using that
configuration.
## Connection Providers
A [Connection Provider](https://docs.mulesoft.com/mule-sdk/latest/connections) is the Module element in charge of handling connections, which
are created from a [Configuration](https://docs.mulesoft.com/mule-sdk/latest/configs). They centralize the logic and parameterization to
provision and release connections of some specific type.
Like the [Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs), [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources), and [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations), Connection
Providers typically depend on a connection in order to be executed. A connection is not required but
is common. Connections used by [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) and [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources) are provided by the
[Connection Provider](https://docs.mulesoft.com/mule-sdk/latest/connections).
[Connection Providers](https://docs.mulesoft.com/mule-sdk/latest/connections) are bound to [Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs).
[Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs) can have none, one, or many [Connection Providers](https://docs.mulesoft.com/mule-sdk/latest/connections) that
create different types of connections, for example, one `ConnectionProvider` for HTTPS and another
for (non-secured) HTTP connections.
## Parameters
`Parameters` are the most granular elements on the module model, and they are used in all these
elements: [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations), [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources), [Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs), and
[Connection Providers](https://docs.mulesoft.com/mule-sdk/latest/connections).
They represent configurable elements that accept the values for elements to execute, or they hold
the configured values.
## Other Elements
A module can have other element types, for example, [Routers](https://docs.mulesoft.com/mule-sdk/latest/routers), [Scopes](https://docs.mulesoft.com/mule-sdk/latest/scopes),
[Functions](https://docs.mulesoft.com/mule-sdk/latest/functions), or [Errors](https://docs.mulesoft.com/mule-sdk/latest/errors). The ones described here are the core elements that most
modules are likely going to have.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers, lifecycle
---
# Lifecycle of a Message Source
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Unlike operations, where the lifecycle is tied to the owning Flow, sources can be started or stopped
separately through Runtime Manager.
To support that, the `Source` class forces you to implement the `onStart()` and `onStop()` methods.
## On Start
This example from the VM connector shows the `onStart()` method:
```java
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
}
```
In this method, you have to initialize all the resources (such as threads, schedulers, connections,
and so on) that you need so that you can produce messages. If an exception or error condition is
found trying to do that, then you have to:
- Release any resources you did got to allocate.
- Throw an exception with a meaningful message.
If the source fails to start, the app that contains it will fail to start.
> [!TIP] All of the source parameters values that defined through the `@Parameter` annotation are
> resolved and available at this point.
### SourceCallback
The method receives a SourceCallback object. The `SourceCallback` is arguably the most important
piece of the Source, since it is involved in pretty much every aspect of the source’s functionality.
We will elaborate on the uses and responsibilities of the `SourceCallback` as this documentation
progresses, but in a nutshell, the `SourceCallback` is what the source uses to communicate with the
runtime. It is used for:
- Pushing messages into the Flow
- Communicating connection issues and triggering reconnection
- Passing state between the push phase of the Source into the response handling part
Because the `SourceCallback` plays such an important role, it is very important that the provided
instance is always available. Depending on how your source’s complexity and code organization, you
may accomplish this by simply holding it as a method argument. More complex sources might need to
keep a reference to it through an instance field. If you decide to do this, then you need to make
sure that the reference is cleared when the `onStop()` method is executed
## On Stop
This method will be invoked by the runtime to make the source stop producing messages. **This method
should not fail**. Any exceptions found during the stop process should be logged and correctly
handled by the source, but after invoking this method the source must:
- Stop producing messages
- Free any allocated resources
- Be capable of being restarted
## Next step
- [Obtain configuration and connections from a Message source](https://docs.mulesoft.com/mule-sdk/latest/sources-config-connection)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, metadata, datasense, keys, type
---
# Metadata Keys Parameter
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
To describe a dynamic metadata structure, you need to know what type to represent. This type
reference is done by defining a `@MetadataKeyId` parameter in the operation that contains the ID of
the type (for example, Account) that will be passed to the metadata resolver defined for that
parameter.
This means, for example, that if your operation can save a generic record to a remote system, but
you want to provide a better design-time experience by describing the supported types `Account` and
`Organization`, then one of your operation parameters will be a type reference containing either the
ID `Account` or the ID `Organization`. This parameter will be used to describe either the Account
structure or the Organization structure for the record to be saved into the bucket, depending on
what the end user decides to use.
## Providing a List of Metadata Keys
The most common case when resolving dynamic metadata is to have a dynamic set of keys that identify
each of the possible types to be resolved. At design time, the end user will configure the
connector, select an operation, and choose one of those keys from the set that gets populated
dynamically, and the selected key will become the `MetadataKeyId` for the metadata resolution.
Implementing the dynamic key’s resolution starts with a `TypeKeysResolver`:
```java
public class RecordKeysResolver implements TypeKeysResolver {
@Override
public String getCategoryName() {
return "Records";
}
@Override
public Set getKeys(MetadataContext context) throws MetadataResolvingException, ConnectionException {
// First we need to obtain the key IDs that will be used.
// This is where you'd normally use `context.getConfig()`
// or `context.getConnection()` to obtain the entity id's
// from a remote service, for this demo the keys will be fixed
List keyIds = Arrays.asList("Author_id", "BookList_id", "Book_id");
HashSet keys = new HashSet<>();
for (String id: keyIds){
// For each possible if, we create a new MetadataKey with that ID
MetadataKeyBuilder builder = MetadataKeyBuilder.newKey(id);
// Then, we add a DisplayName to that MetadataKey,
// this will be the name shown in the UI
builder.withDisplayName(StringUtils.removeEnd(id, "_id"));
//finally, add the key to the Set of known MetadataKeys
keys.add(builder.build());
}
return keys;
}
}
```
Above, all the elements that are required to create a dynamic set of MetadataKeys. The method to
implement is `getKeys`, which outputs all the keys available to the user.
The `id` element, like `Author_id` is used internally and must be unique for each structure that you
want to represent across all the resolvers. The `displayName` is the name to show to the user for
that key, so it is expected to be more user friendly and readable.
After the resolver is defined, you can use it as an operation or a source by adding the
`@MetadataScope` annotation with its `keysResolver` value at the class definition level and
annotating the parameter that is the key with `@MetadataKeyId`. All metadata resolvers must belong
to the same category in an operation or a source.
```java
@MetadataScope(keysResolver = RecordKeysResolver.class)
public class OperationWithMetadataKey {
public void create(@MetadataKeyId String type,
@Config MyConfig config){
//...
}
}
```
```java
@MetadataScope(keysResolver = RecordKeysResolver.class)
public class DocsMetadataSource extends Source, Void> {
@MetadataKeyId
@Parameter
public String type;
//...
}
```
> [!NOTE] The previous example is the only way to support metadata keys for sources. Do not set the
> resolver at the `@MetadataKeyId` annotation when defining sources.
Setting the `@MetadataScope` annotation at the operation class definition level indicates that all
of its operations provide metadata and that they must all have a parameter annotated with
`@MetadataKeyId` because they inherit the resolver from the scope.
You can also set a key resolver for a single operation:
```java
public class MyOperations {
public void operationWithMetadataKey(@MetadataKeyId(RecordKeysResolver.class) String type,
@Config MyConfig config){
//...
}
public void plainOperation(@Config MyConfig config){
//...
}
}
```
In addition, if there is a `@MetadataScope` annotation at the operation class definition level, you
can set a value for the `@MetadataKeyId` annotation in a parameter to override the resolver defined
at the scope level for a single operation:
```java
@MetadataScope(keysResolver = ClassLevelResolver.class)
public class MyOperations {
public void operation(@MetadataKeyId String type, @Config MyConfig config){
// This operation will use the ClassLevelResolver
}
public void operationWithAnotherResolver(@MetadataKeyId(OverridingResolver.class) String type,
@Config MyConfig config){
// This operation will use the OverridingResolver
}
}
```
> [!IMPORTANT] The two previous examples (setting the resolver at the parameter level and overriding
> the inherited resolver from the scope) work only when defining operations. These features are not
> available for sources.
## User-Defined MetadataKey
An user-defined `MetadataKey` is one that is provided freely by the end user and not defined by you
as one of the possible elements of a List.
For example, this is a very common case in queries, where you use the whole query that the end user
wants to execute as a `MetadataKey`.
To declare a user-defined `MetadataKey`, annotate a parameter with `@MetadataKeyId` without
providing a `TypesKeyResolver` for the parameter annotation or for the `@MetadataScope` annotation
if it is present at the class definition.
```java
public class MyOperations {
public void query(@MetadataKeyId String query){
//...
}
}
```
## Optional MetadataKey Parameters
Available since version 1.3.
You can make `MetadataKey` parameters optional like other parameters, by adding the `@Optional`
annotation:
```java
public void query(@MetadataKeyId @Optional String query){
//...
}
```
When an optional MetadataKey parameter is not assigned a value, metadata calls are made using `null`
as the value of `MetadataKey`. This means that any `MetadataResolver` parameter associated with this
`MetadataKey` parameter must be prepared to receive a null value.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Module Licensing
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Modules written with the SDK have three possible kinds of licensing, each setting different
requirements on how the application can be executed.
## Community Module
The default for all Modules, apps that use a Community Module can be executed in all Mule runtimes
with no further requirements.
## Enterprise Module
Only Mule EE Runtimes can be used to execute the apps that use the Enterprise Modules, which means
that the user of the Module needs a MuleSoft Enterprise License. Declaring a Module to be EE-only is
very easy. You simply need to add the `@RequiresEnterpriseLicense` annotation:
```java
@Extension(name = "enterprise")
@RequiresEnterpriseLicense
public class EnterpriseConnector {
}
```
By default, `RequiresEnterpriseLicense` forces the user to have a full MuleSoft Enterprise License,
but you can also declare that the Module allows an evaluation license to be used for the Runtime.
This can be configured using the `allowEvaluationLicense` flag in the `RequiresEnterpriseLicense`
annotation:
```java
@Extension(name = "enterprise")
@RequiresEnterpriseLicense(allowEvaluationLicense = true)
public class EnterpriseConnector {
}
```
## Custom Module License
MuleSoft Certified Connectors can request a _certified license generation key_ from MuleSoft that
allows them to create their own Custom License. This ensures that those who use the Certified
Connector contact the Partner that developed the Module to obtain their Custom License.
Partners who have built a MuleSoft Certified Connector can give potential customers the chance to
build a Mule app with their connector and test it at design time. When attempting to deploy the Mule
app with the connector, customers are prompted for the Partner’s Custom License.
### Obtaining a License Generation Key for your Connector
Before submitting the developed connector to MuleSoft for certification, the prospective certified
connector partner must complete these steps:
1. Include the following information for MuleSoft to use before generating a partner key and
keystore:
- Company Name (also known as "Vendor Name")
- Contact Email
- Contact Message
- Connector Name
2. Request the key and keystore from MuleSoft:
1. The public `.key` is the file that you store in the connector.
2. The `.jks` keystore is for you as the partner to generate licenses with.
## Adjusting the Connector Code and Storing the Public Key
After obtaining the key and keystore:
1. The partner adjusts the connector project code by applying the `@RequiresEntitlement` annotation
and entering values for all requested attributes.
- `name` must be the name of the connector.
- `vendor` attribute must be the part before the `.key` suffix. For example, if MuleSoft
generated a vendor key `prov-name.key`, the partner puts `prov-name` as the vendor.
```java
@Extension(name="connector-name", vendor="prov-name")
@RequiresEntitlement(name="connector-name")
public class LicensedConnector {
...
}
```
- Put the MuleSoft-provided `.key` file under `src/main/resources` or
`src/main/resources/license` in the connector’s project directory.
### Sample Partner Connector
You can download and import the sample connector to Studio to see how the license management
annotations are configured in the connector code. The customer `.key` license file should reside in
`src/main/resources`.
## Producing a License File
MuleSoft partners use the `.jks` file and the license generation plugin to generate a license to
send to the connector customer.
From the command line, where `vendor.keystore` should be replaced with the path to your `.jks` file,
execute the command in the same directory where the `.jks` file is:
mvn org.mule.tools.devkit:mule-devkit-license:license
-Dvendor.keystore=betaprovider-license-demo.jks
> [!NOTE] Optionally, you can specify the expiration date of the license by appending
> `-Ddays.to.expire=` to the above command. To add the customer’s
> name to the license, append `-Dclient=`.
If the license is successfully created, the output looks something like this:
\[INFO\] Scanning for projects... \[NOTE\] \[INFO\]
------------------------------------------------------------------------ \[INFO\] Building Maven
Stub Project (No POM) 1 \[INFO\]
------------------------------------------------------------------------ \[NOTE\] \[INFO\] ---
mule-devkit-license:license (default-cli) @ standalone-pom --- \* Enter the name of the client whom
will receive this license: Bob \* Enter the name of the provider of the Entitlement as it appears in
the @RequiresEntitlement annotation: betaprovider \* Enter the name of the Entitlement as it appears
in the @RequiresEntitlement annotation: lic-demo \* Enter the name of the Connector as it appears in
the @Connector "name" attribute: license-demo \* Enter keystore password: \[INFO\]
------------------------------------------------------------------------ \[INFO\] BUILD SUCCESS
\[INFO\] ------------------------------------------------------------------------ \[INFO\] Total
time: 18.151s \[INFO\] Finished at: Thu Dec 10 09:34:41 ART 2015 \[INFO\] Final Memory: 6M/287M
\[NOTE\]
## Developing a Mule Application with a Licensed Connector
For customers to validate that their connector license is working, they need to make the license
(`.lic` file) available through either the Mule app or the Mule server.
### License File in the Mule Application
Once the customer has bought a license for the connector, the `.lic` file provided to the customer
by the partner or vendor can be placed in one of these directories:
- Under `src/main/resources` in the app (developed in Studio).
- Under `app/classes` if the app has already been unpacked and deployed on the server.
### License File in the Mule Server
Instead of storing the license in the app, you can be place in the `conf/` folder of the Mule
server.
> [!NOTE] Storing the license in the Mule server is the recommended approach if multiple apps
> require the same license.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, connection, connectivity, management, pooling, cached, provider, connection-provider
---
# Modules Connectivity Framework
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Connected modules (connectors) are the most common type of module. They provide a connection between
a Mule flow and an external resource. Configure these connections with the `ConnectionProvider` in a
connectivity framework to create, disconnect, and describe the connection for Mule runtime engine to
handle. For more information about how to use connections, refer to
[Using Connections](#use-connections).
## Declaring a Connection Provider
To declare a new `ConnectionProvider` you should create a new class that implements the
`ConnectionProvider` interface. The `ConnectionProvider` interface is a typed interface that
receives one type argument that indicates the class of the instances that the `ConnectionProvider`
handles.
This example declares a `MyConnectionProvider` class that implements the `ConnectionProvider`
interface:
```java
public class MyConnectionProvider implements ConnectionProvider {
@Parameter
private String password;
public MyConnection connect() throws ConnectionException {
return new MyConnection(password);
}
public void disconnect(MyConnection connection) {
connection.invalidate();
}
public ConnectionValidationResult validate(MyConnection connection) {
return connection.isValid() ?
ConnectionValidationResult.success() :
ConnectionValidationResult.failure("Connection is not valid", new InvalidConnectionException());
}
}
```
> [!NOTE] Each defined `ConnectionProvider` must be instantiable, public, and have a default
> constructor.
Other components (such as an operation or source) that require access to the connection will gain
access to the connection through instances of the `MyConnection` class.
The above example contains a `@Parameter` and these methods: `connect()`, `disconnect()`, and
`validate()`. The next sections describe each of them.
### Connection Provider Parameters
Like any other `Module` element, a `ConnectionProvider` can have `@Parameters`. Each
`ConnectionProvider` `@Parameters` must be a configurable element that is required to instantiate
the actual connection, in the `connect()` method.
> [!WARNING] Common `@Parameters` that are required by more than one operation must **not** be part
> of the `ConnectionProvider`. That’s a common case for [Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs) `@Parameter`. See
> [`@Parameter` section](https://docs.mulesoft.com/mule-sdk/latest/parameters).
### Connect
The `connect()` method is in charge of instantiating the actual connections with all the configured
parameters. It’s **very important** to know that the returned connection is expected to be ready to
use.
The returned **connection** does not need to implement an interface or contract. It doesn’t
necessarily reference the socket connection. It can simply be a client or something of that sort.
### Disconnect
The `disconnect(Connection)` method receives a live connection and disposes it, freeing all it’s
allocated resources.
### Validate
As mentioned [above](#_connections_connect), the `connect()` method in the `ConnectionProvider`
**must** return a valid, fully functional connection. Because connections might become stale while
sitting idle, the `ConnectionProvider` provides the `validate(Connection)` method. This method is
invoked to check the connection before using it.
If the validation fails, the connection will be invalidated and a new one will be taken.
#### Connection Validation Result
The `validate(Connection)` method will return an object of type `ConnectionValidationResult`, which
can result in two types: a `ConnectionValidationResult.success()` or a
`ConnectionValidationResult.failure()`.
When a `failure()` is returned, a descriptive message and a failing `Exception` (which provides
context about why the connection is invalid) should be provided to the new `failure()`. Optionally,
an `ErrorType` can be provided to add the [error handling](https://docs.mulesoft.com/mule-sdk/latest/errors) capabilities.
- `failure(String, Exception)`
- `failure(String, ErrorType, Exception)`
## Adding a Connection Provider
Each `ConnectionProvider` is bound to a Configuration that can have none, one, or more than one
`ConnectionProvider`.
To add a `ConnectionProvider` implementation to a Module Configuration, you need to use a
`@ConnectionProviders` annotation. This annotation declares each `ConnectionProvider` that a
`Module` defines. It can be used at the `@Extension` or `@Configuration` level.
If an extension contains more than one `ConnectionProvider`, you need to use the `@Alias` to provide
each with a significant name. By convention, the name of that connection provider adds the
`` `-connection `` suffix to the provided name.
Example of a `ConnectionProvider` declared at `@Extension` level:
```java
@Extension(name="xyz")
@Operations(Operations.class)
@ConnectionProviders(MyConnectionProvider.class)
public class MyModule {
@Parameter
private String someParameter;
public String getSomeParameter() {
return someParameter;
}
}
```
Example of the XML for this config with the example `MyConnectionProvider`:
```xml
```
## Connection Management
You can specify a few connection management strategies for a `ConnectionProvider`.
### Pooling Strategy
The connections are pooled. A cache of connections is maintained so that they can be reused when
future requests require one.
This is useful when connections are expensive to create or when concurrent access to a connection
instance is not supported.
For this pooling strategy, a pooling profile configuration is automatically added to the connection.
The following table shows the default values for the pooling profile of type **Use default
connection pool configuration**:
Name Default Value Max Active
5
Max Idle
5
Max Wait
5
Exhausted Action
GROW
Initialisation Policy
INITIALIZE_ONE
Min Eviction Millis
1800000
Eviction Check Interval Millis
-1
You can enable pooling connection management by implementing the `PoolingConnectionProvider`
interface.
Refer to [Pooling Profiles](https://docs.mulesoft.com/mule-runtime/latest/tuning-pooling-profiles) for more information.
### Cached Strategy
For each configuration instance, a connection is established and cached so that one specific
configuration always gets the same connection. The connection is maintained until the configuration
itself is stopped.
You can enable cached connection management by implementing the `CachedConnectionProvider`
interface.
Refer to [Caching](https://docs.mulesoft.com/mule-runtime/latest/tuning-caching) for more information.
### No Strategy
The runtime adds no additional infrastructure similar to the pooling cases. The `ConnectionProvider`
is responsible for providing the totality of the connection-handling behavior. An operation that
requires a connection calls the `connect()` method each time it needs a connection, and it destroys
the connection once the operation is complete.
Implementing the `ConnectionProvider` interface means no strategy.
## Using Connections
Using connections in Operations and Sources is quite different, see:
- [Using Connections in Operations](https://docs.mulesoft.com/mule-sdk/latest/operations#_using_connections)
- [Using Connections in Sources](https://docs.mulesoft.com/mule-sdk/latest/sources-config-connection)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Mule SDK Development Best Practices
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The purpose of this documentation is to provide users of the Mule SDK with best practices for
building modules and connectors in a way that makes the best use of Mule runtime engine (Mule)
functionality and is consistent with MuleSoft’s UX and quality guidelines.
## Terminology
This documentation uses these special terms:
Connector
A module that establishes connections to an external system. A connector is a module.
Large String
A String larger than 4 KB in size.
Module
A plugin built through the Mule SDK that extends the functionality of Mule 4.
Mule language
The XML-based domain-specific language (DSL) used to write Mule applications and through which a
module is used inside an operation.
Must
The word "must" denotes a hard rule. This means that to be considered compliant with best practices,
a module has to comply with all the practices described with this term.
Should
This word "should" denotes a rule that, although recommended, could be skipped in certain cases and
the module would still be compliant with best practices.
Target system
The resource that a connector accesses.
User
This refers not to the user of the Mule SDK (the one coding the module), but to the end user who
consumes the module that a developer produces. All best practices are ultimately aimed at improving
the end user’s experience.
## MuleSoft Coding Practices
Using the SDK to create a new module or connector **should not** be approached as simply wrapping an
API, library, or piece of functionality into a component that Mule can understand.
Instead, the problem **should** be approached as “extending a programming language called Mule.”
If you were to create a new library for the C programming language or your own Java framework, you
would design library APIs, syntax, and semantics so that a C or Java developer consuming that
library finds it consistent and compliant with all the rules and guidelines inherent to that
ecosystem. Failing to do so results in unhappy consumers with unmet expectations for consistency and
clarity.
The same applies to a custom Mule module or connector, which needs to be approached not as just
creating a Mule bridge, but as an extension to the Mule language that provides additional
functionality in a consistent, usable, and organic way.
## See Also
- [Salesforce Help](https://help.salesforce.com)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk
---
# Mule SDKs Overview
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Use the Mule SDK for Java or XML to extend the Mule 4 Runtime by creating new modules that you can
install in Mule apps. Examples of modules include connectors, such as HTTP, or modules with custom
functionality, such as the Validations Module.
The SDK provides an API that:
- Facilitates faster development of Mule modules than its predecessor, DevKit.
- Decouples modules from the Mule Runtime internals.
- Assures consistency across Mule components and other modules, such as cloud connectors.
You can use either the advanced, feature-rich Java Mule SDK or the simpler XML SDK, which provides
only outbound operations and doesn’t support recursive calls.
## Differences from DevKit
The Mule SDK for Java is the Mule 4 evolution of DevKit. It replaces Devkit and provides the
canonical way of extending the Mule Runtime. DevKit is not available for Mule 4.
Although the SDK builds on the same idea of annotated Java classes, internally it works differently:
- The SDK is not a code generator. The built module does not contain any generated code (not even
the XSD schema). Your module interacts with Mule Runtime through a clearly defined _Extensions
API_. However, you do not need to learn the details of this API because the SDK framework takes
care of that for you.
- Compared to DevKit, the SDK is more powerful and supports more features:
- Transactions
- Request-response message sources
- Dynamic configurations
- Routers
- Non-blocking operations
- Classloading isolation
- Enhanced interoperability with runtime services
## See Also
- [Mule SDK for Java](https://docs.mulesoft.com/mule-sdk/latest/getting-started)
- [XML SDK](https://docs.mulesoft.com/mule-sdk/latest/xml-sdk)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, dependency, inject, registry, service
---
# Mule Services Injection
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## Using Mule Services
When implementing your module, you might need to use some of the services that Mule provides.
Examples of these services include `ObjectStoreManager`, `LockFactory`, and `HttpService`.
To achieve this, there is no need to get them from the registry of the `MuleContext`. You can simply
inject them into your component (such as an operation, source, or configuration) through the
`@Inject` annotation.
Here is a simplified example that injects a service from the registry into a component:
Example: Using the @Inject Annotation
```java
public class ObjectStoreOperations {
// ...
@Inject
private ObjectStoreManager runtimeObjectStoreManager;
// ...
@Throws(StoreErrorTypeProvider.class)
public void store(String key,
@Content TypedValue value,
@Optional @ParameterDsl(allowInlineDefinition = false) ObjectStore objectStore) {
ObjectStore os = objectStore == null ? runtimeObjectStoreManager.getDefaultPartition() : objectStore;
os.store(key, value);
}
// ...
}
```
Here are some common Mule services:
- `LockFactory`: All Mule components that require synchronization to access shared data must be
synchronized using locks from the default implementation of this interface. For more information
regarding `LockFactory`, refer to
[Distributed Locking](https://docs.mulesoft.com/mule-runtime/4.4/distributed-locking).
- `ExpressionManager`: Provides universal access for evaluating expressions embedded in Mule
configurations, such as XML, Java, scripting, and annotations.
- `TransformationService`: Service that tries to transform a value into another given type.
- `HttpService`: Provides both HTTP server and client implementations. Whenever using an HTTP
connection on your connector, you should try to use this service.
- `SchedulerService`: Provides access to the different schedulers and thread pools that exist in the
Mule runtime, allowing you to schedule tasks on those.
- `SoapService`: Service that creates SOAP clients to consume SOAP services.
- `ObjectStoreManager`: Manager in charge of creation and management of `ObjectStore` instances.
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Multi-Level Metadata
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Imagine the case where your end user will use an operation that invokes an action provided by a
service. To know the metadata that the action requires as arguments or the metadata of what it
returns, you need to differentiate the service from the action to be executed. You do this with a
metadata key id. For these cases, the metadata key id does not need to be a single `String`. It can
instead contain multiple parts bundled within a complex parameter that holds the information needed
to resolve the metadata.
## Implementing a Multi-Level Metadata Key
It is necessary to set the order in which parameters of the metadata key are specified, starting
with `1`. Returning to the example above, the end user will first specify the service field, then
the action to invoke. So, the service parameter needs to set `order = 1` and the action parameter
`order = 2`.
All the parameters of the POJO representing the `MetadataKeyId` must be annotated with a
`@MetadataKeyPart` annotation that sets the `order` value for it. These annotated fields must be of
type `String`.
Here is an example of a metadata key id class:
```java
public class ActionIdentifier {
@Parameter
@MetadataKeyPart(order = 1) (1)
private String service;
@Parameter
@MetadataKeyPart(order = 2) (1)
private String action;
public String getService() {
return service;
}
public String getAction() {
return action;
}
public void setService(String service) {
this.service = service;
}
public void setAction(String action) {
this.action = action;
}
}
```
The next example shows an operation that uses a `MetadataKeyId` that is a complex type:
```java
@OutputResolver(output = OutputOperationTypeResolver.class)
public Object invoke( @ParameterGroup(name = "Operation") @MetadataKeyId(OperationTypeKeysResolver.class) ActionIdentifier identifier,
@TypeResolver(InputOperationTypeResolver.class) Map args){
return invokeAction(identifier.getService(), identifier.getAction(), args);
}
```
Next is an example of a `TypeKeysResolver` that returns each available `MetadataKey`:
```java
public class OperationTypeKeysResolver implements TypeKeysResolver {
@Override
public Set getKeys(MetadataContext context) throws MetadataResolvingException, ConnectionException {
Set keys = new HashSet<>();
for(String service : getServices()){
MetadataKeyBuilder key = MetadataKeyBuilder.newKey(service);
for(String action : getActions(service)){
key.withChild(MetadataKeyBuilder.newKey(action).build());
}
keys.add(key.build());
}
return keys;
}
}
```
```java
public class OutputOperationTypeResolver implements OutputTypeResolver{
@Override
public MetadataType getOutputType(MetadataContext context, ActionIdentifier key)
throws MetadataResolvingException, ConnectionException {
// Resolve the output metadata using the ActionIdentifier
}
}
```
```java
public class InputOperationTypeResolver implements InputTypeResolver {
@Override
public MetadataType getInputMetadata(MetadataContext context, ActionIdentifier key)
throws MetadataResolvingException, ConnectionException {
// Resolve the input metadata using the ActionIdentifier
}
}
```
## Partial Fetching
**Available since version 1.1**
The process of getting each `MetadataKey` can be very time consuming. In the example that gets all
the possible services and the actions of each service, the information you are fetching might be on
another server.
Partial fetching enables you to resolve one level of the `MetadataKey` tree at a time.
The `getKeys` method from `TypeKeysResolver` will only return the first level of each tree, not the
complete tree of each `MetadataKey`.
So, the amount of information needed is greatly reduced because you only need to get the possible
services. Once a service is selected, you need to provide the next level of the `MetadataKey` tree.
To make this possible, your key resolver must implement `PartialTypeKeysResolver`, for example:
```java
public class OperationTypeKeysResolver implements PartialTypeKeysResolver {
@Override
public Set getKeys(MetadataContext context) throws MetadataResolvingException, ConnectionException {
Set keys = new HashSet<>();
for(String service : getServices()){ (1)
MetadataKeyBuilder key = MetadataKeyBuilder.newKey(service);
keys.add(key.build());
}
return keys;
}
@Override
public MetadataKey resolveChilds(MetadataContext metadataContext, ServiceOperation key)
throws MetadataResolvingException, ConnectionException {
if(key.getService() == null){
throw new MetadataResolvingException("Missing Service name. Cannot resolve Actions without a service",
FailureCode.INVALID_METADATA_KEY);
}
MetadataKeyBuilder key = MetadataKeyBuilder.newKey(key.getService()); (2)
for(String action : getActions(key.getService())){
key.withChild(MetadataKeyBuilder.newKey(action).build()); (3)
}
return key;
}
}
```
1 Only the services are retrieved. The actions of a service will be retrieved on demand. 2 Build a single MetadataKey tree with a new, complete level of metadata, in this case, the actions level. 3 Add the actions of that service as children.
## Using User Input As Partial Level
**Available since version 1.1**
In some cases, you might not be able to provide the end user with a hint about part of your
MetadataKey. For example, the universe of options might be too big (a dropdown with all the classes
in a classpath makes not sense) or when the starting point of the ID is a free input (for example, a
query).
Imagine a `MetadataKeyId` that has a part that is a `String` representing a Java class. It can be
very time consuming to retrieve all the classes, and it is complicated for the user to have so many
options on a dropdown.
So, you can signal that a `MetadataKeyPart` will not be provided by the resolver and must be
inserted by the user. You do this by setting the `providedByKeyResolver` to `false` value on the
`MetadataKeyPart` annotation.
Here is an example where the POJO representing the `MetadataKeyId` represents a Java method:
```java
public class MethodIdentifier{
@Parameter
@Alias("class")
@MetadataKeyPart(order = 1, providedByKeyResolver = false) (1)
private String clazz;
@Parameter
@Alias("method")
@MetadataKeyPart(order = 2)
private String methodId;
@Override
public String getClazz() {
return clazz;
}
@Override
public String getMethodId() {
return methodId;
}
@Override
public void setClazz(String clazz) {
this.clazz = clazz;
}
@Override
public void setMethodId(String methodId) {
this.methodId = methodId;
}
}
```
1 The clazz field must be inserted by the end user without hints.
In this case, it also means that the `getKeys` method cannot return all the possible classes:
```java
public class MethodTypeKeysResolver implements PartialTypeKeysResolver {
@Override
public Set getKeys(MetadataContext context) throws MetadataResolvingException, ConnectionException {
return emptySet(); (1)
}
@Override
public MetadataKey resolveChilds(MetadataContext metadataContext, MethodIdentifier key)
throws MetadataResolvingException, ConnectionException {
if(key.getClazz() == null){
throw new MetadataResolvingException("Missing Class name. Cannot resolve Methods without a target Class",
FailureCode.INVALID_METADATA_KEY);
}
MetadataKeyBuilder key = MetadataKeyBuilder.newKey(key.getClazz()); (2)
for(String methodId : getMethodIds(key.getClazz())){
key.withChild(MetadataKeyBuilder.newKey(methodId).build()); (3)
}
return key;
}
}
```
1 Return an empty set of MetadataKey because the end user will provide this information. 2 Build a single MetadataKey tree with a new, complete level of metadata, in this case, the methodIds level. 3 Add the methodIds of that class as children.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, operation, non, blocking, non-blocking
---
# Non-Blocking Operations
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The Mule 4 execution engine is based on reactive streams. That means there’s top level support for
non-blocking operations. By default, all operations are blocking. As you probably noticed, the
semantics of all the operation examples you have seen [before](https://docs.mulesoft.com/mule-sdk/latest/operations) are inherently blocking:
the runtime invokes a method and gets a value in response. That is fine for operations that are more
CPU intensive than they are IO intensive, or for operations that consume APIs that cannot be
consumed in a non-blocking way, such as JDBC (the API that powers the Database connector).
HTTP is one of the protocols that does supports this. Being able to perform non-blocking HTTP
request is key for scalability of gateway proxies. Any connector consuming a REST API can also
benefit from this.
This simplified HTTP request example shows how the SDK allows you to develop non-blocking
operations:
```java
public void request(String url, @Connection HttpClient client, @Content InputStream body, (1)
CompletionCallback callback ) { (2)
client.sendAsync(HttpRequest.builder()
.uri(url)
.method("POST")
.entity(new InputStreamHttpEntity(body))
.build()).whenComplete((response, e) -> {
if (e != null) {
callback.error(e); (4)
} else {
callback.success(Result.builder() (3)
.output(response.getEntity().getContent())
.attributes(toAttributes(response))
.build());
}
});
}
```
1 Unlike blocking operations, the return type is not specified through the method’s return type. Non-blocking operations always need to be specified through void methods. 2 An operation becomes non-blocking when it has an argument of type CompletionCallback. This interface uses generics to specify the operation’s return type. The first generic is the type of the output payload, and the second one the type of the output attributes. These generics are mandatory. 3 The return value is passed through the success(Result) method of the CompletionCallback. See Result for more information on the Result object. 4 Non-blocking operations should not throw exceptions. Any errors should be channeled through the error() method in the callback.
> [!TIP] Notice that in this example, the `CompletionCallback` is being consumed from between an
> `HttpResponseCallback`. This second callback is provided by an `HttpClient` that supports
> asynchronous responses. As stated previously, in order to do non-blocking, you need to be
> consuming an API which allows that.
The result of this code is a non-blocking operation that returns an `InputStream` as payload and an
`HttpAttributes` object as message attributes.
## Void Operations
It is possible to have a void non-blocking operation. The use case for that is an IO operation that
does not return anything, such as writing to a file:
```java
public void write(String path, @Content byte[] bytes, CompletionCallback callback) {
writeAsync(result -> callback.success());
}
```
As you can see here, you can use Java’s `Void` type to indicate that the operation is void.
### Gotcha
You can also have an operation that sets the payload (but **NOT** the attributes) like this:
```java
public void foo(CompletionCallback callback) {
...
}
```
## Execution Types
Mule 4 now has a reactive execution engine. The runtime has a few global executors through which all
tasks are run.
To schedule tasks correctly, the runtime needs to know which kind of processing each operation is
going to perform. The different processing types are:
- CPU\_INTENSIVE: Intensive processing, such as a complex, time-consuming calculations or
transformations. Note that the SDK will never infer a `CPU_INTENSIVE` type. See
[Specifying Execution Types](#specify_execution_type).
- CPU\_LITE: Processing that neither blocks nor is CPU intensive, such as message passing,
filtering, routing, or non-blocking IO.
- BLOCKING: Blocking processing that performs blocking IO operations, `Thread.sleep(long)`,
`Lock.lock()`, or any other technique that blocks the current thread during processing. Although
this type includes `Thread.sleep`, using it is a bad practice that you should avoid.
### Inferring Execution Types Automatically
The SDK follows these rules to make a best guess about the execution type so that you don’t have to
specify it explicitly:
- Operation requires connection and is blocking: `BLOCKING`
- Operation requires connection and is non-blocking: `CPU_LITE`
- None of the above: `CPU_LITE`
If the execution type to which your operation corresponds does not match the best guess, you should
specify the correct one. Failing to do so will negatively impact the performance of any app that
uses your module.
### Specifying Execution Types
You can manually specify an operation’s execution type through the `@Execution` annotation, for
example:
```java
@Execution(CPU_INTENSIVE)
public void computeFlightPlan() {
...
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: notification, sdk, operations, sources
---
# Notifications
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
**Available since version 1.1**
Notifications in Mule are a way of communicating actions to other components. They are mostly used
for monitoring.
## Defining Notifications
The first step is to define all the notifications that can be fired by a Module. You do this by
defining an `Enum` that implements the `NotificationActionDefinition` interface. Each value defined
in the `Enum` is considered to be notification action.
Since you can include data within a notification, you must provide each associated `DataType`.
In the example below, `NEW_EVENT` and `FINISHED_EVENT` actions are declared. They have an `Integer`
and a custom object (`SimpleObject`) as data.
```java
public enum SimpleNotificationAction implements NotificationActionDefinition {
NEW_EVENT(DataType.fromType(Integer.class)),
FINISHED_EVENT(DataType.fromType(SimpleObject.class));
private final DataType dataType;
SimpleNotificationAction(DataType dataType) {
this.dataType = dataType;
}
@Override
public DataType getDataType() {
return dataType;
}
}
```
### Registering Notifications in the Module
To identify the notifications that a Module fires, the `@Extension` annotated class should be
annotated with `@NotificationActions`, which references a `NotificationActionDefinition` enum that
contains the defined notifications. Any custom data types you define there will need to be exported,
as well.
```java
@Extension(name = "Foo")
@NotificationActions(SimpleNotificationAction.class)
@Export(classes = {SimpleObject.class})
@Xml(prefix = "test-connector")
public class FooExtension {
// Content
}
```
## Communicating Which Notifications are Fired
After declaring all the possible notifications in a Module, you need to provide the information that
binds the notifications with the Operations and Sources that fire them.
To do that, you need to implement a `NotificationActionProvider` class that identifies the
notifications that are fired by an Operation or Source.
```java
public class ExecuteNotificationActionProvider implements NotificationActionProvider {
@Override
public Set getNotificationActions() {
HashSet errors = new HashSet<>();
errors.add(SimpleNotificationAction.NEW_EVENT);
errors.add(SimpleNotificationAction.FINISHED_EVENT);
return errors;
}
}
```
After defining the `NotificationActionProvider`, you can bind it to the proper Operation or Source
using the `@Fires` annotation:
```java
@Fires(ExecuteNotificationActionProvider.class)
public void execute(){
// operation body
}
```
## Firing Notifications
> [!WARNING] Firing a notification action that is not declared in the `NotificationActionProvider`
> of an Operation or Source will result in a failure. Firing a notification using data that does not
> match the declared type will also result in a failure.
### Operations
To fire a notification from an Operation, you must add a `NotificationEmitter` parameter. You can
then use it to fire notifications with a given `NotificationActionDefinition` and the associated
data, as a `TypedValue`.
```java
@Fires(ExecuteNotificationActionProvider.class)
public void execute(NotificationEmitter notificationEmitter){
notificationEmitter.fire(NEW_EVENT, TypedValue.of(4));
// operation body
notificationEmitter.fire(FINISHED_EVENT, TypedValue.of(new SimpleObject()));
}
```
### Sources
Unlike Operations, Sources not only execute when receiving or generating a new message to be
processed but also when one completes, whether successfully or with a failure.
You can fire notifications from `@OnSuccess`, `@OnError`, and `@OnTerminate` methods by adding a
`NotificationEmitter` parameter, just like you can in Operations.
```java
@OnSuccess
public void onSuccess(@ParameterGroup(name = "Success Info", showInDsl = true) PersonalInfo successInfo,
NotificationEmitter notificationEmitter) {
// on success body
notificationEmitter.fire(FINISHED_EVENT, TypedValue.of(successInfo.getSimpleObject()));
}
```
When receiving or generating a message, however, you can only indicate that you want certain
notifications to be fired once the message is handled by using the `SourceCallbackContext`.
```java
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
// source body
context.fireOnHandle(NEW_EVENT, TypedValue.of(7));
sourceCallback.handle(result, context);
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, annotations, null, safe
---
# Null Safe
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
In some cases, you might want to instantiate a `@Parameter` even though the end user has not
provided a value, for example:
```java
@Parameter
@Optional
private List numbers;
```
While interacting with `numbers` in your code, you will need to check if `numbers == null` at some
point to avoid a `NullPointerException`.
The SDK supports the use of annotations like `@NullSafe`, which can provide an empty list instead of
`null`. When you use it, the SDK can automatically create a value for you if the value was not
configured.
There are many "flavors" of `@NullSafe` annotations. When used with `List` and `Map` interfaces,
`@NullSafe` will provide a default implementation for those collections.
This example shows a POJO as a null safe type:
```java
@Parameter
@Optional
@NullSafe
private Foo foo;
```
As you might expect, the SDK will instantiate `Foo` and assign it to your `foo` parameter so that
you do not have to manually check for null.
Note that if you use `@NullSafe` with a POJO, all the parameters declared inside the POJO must all
be _optional_. If a parameter is required, there is no default value for the SDK to use. So, using
`@NullSafe` to automatically instantiate required parameters makes no sense.
`@NullSafe` can be configured to instantiate a certain class instead of using the parameter’s type.
This can be helpful in the cases where the parameter’s type cannot be instantiated (like an abstract
class or an interface).
You specify the class to be instantiated by setting the `defaultImplementingType` attribute in the
annotation, for example:
```java
@Parameter
@Optional
@NullSafe(defaultImplementingType = Foo.class)
private AbstractFoo foo;
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, security, oauth
---
# OAuth
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 focuses on client developer
simplicity while providing specific authorization flows for web applications, desktop applications,
mobile phones, and livingroom devices. For more information about the OAuth 2.0 protocol, see
[https://oauth.net/2/](https://oauth.net/2/).
The SDK provides support for building modules that are OAuth enabled, which means that they
establish connections that are authorized through the OAuth protocol. This enables you to hide most
of the complexities of the OAuth protocol from the end user and to spare them the requirement of
learning OAuth.
OAuth support provided by the SDK is limited to:
- OAuth version 2.
- [Authorization Code](https://docs.mulesoft.com/mule-sdk/latest/authorization-code) grant type
- [Client Credentials](https://docs.mulesoft.com/mule-sdk/latest/client-credentials) grant type (available since version 1.3)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, streaming, objects, pagination
---
# Object Streaming (Pagination)
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Object streaming is similar to [binary streaming](https://docs.mulesoft.com/mule-sdk/latest/binary-streaming), except that it streams Java
objects, not a raw byte stream.
Here is an example that use object streaming through an oversimplified Select operation from the
Database connector:
```java
public PagingProvider> list(@Text String sql) { (1)
return new PagingProvider>() {
private ResultSet resultSet;
@Override
public List> getPage(DbConnection connection) { (2)
if (resultSet == null) {
resultSet = executeQuery(connection, sql); (3)
}
return extractPageFrom(resultSet);
}
@Override
public java.util.Optional getTotalResults(DbConnection connection) {
return java.util.Optional.empty(); (4)
}
@Override
public void close(DbConnection connection) throws MuleException {
resultSet.close(); (5)
}
}
}
```
1 Two things to notice about the signature of this method:The method returns a PagingDelegate object. PagingDelegate requires two generic types. The first one is the type of connection the delegate will use to get the next pages, and the second is the type of the elements in the page.
The List operation receives the parameters. However, notice that is does not receive a connection object. Paged operations cannot receive connections. Instead, they must always use the connections that the runtime passes to the PagingProvider.
So, this signature means that it will return the results of the query in pages, using a DbConnection object, and each item in the stream will be a Map<String, Object> that represents each row in the result.
2 getPage() fetches the next page and returns it. It receives the connection to use to fetch that page. When the stream is over, this method needs to return an empty List. Implementations should ensure that no empty pages are returned before the stream is finished.3 Depending on the operation’s logic, you might need logic to obtain the first page versus logic to obtain the next pages. 4 Another feature of object streaming is the ability to tell how many objects are actually in the streams. To determine that, you need to implement the getTotalResults() method. The problem is that not all APIs support that. For example, the Salesforce API supports that, but JDBC (the API powering the Database connector) does not. That is why this method returns a Java Optional, in this case, an empty one. Users of your paginated operation can obtain this value through an expression similar to #[payload.size]. 5 Finally, the close() method will be invoked when no more objects are in the stream. This method IS NOT for closing the connection. The SDK will do that automatically. The method is for releasing any resources that this paging delegate might be holding. For example, in this case, the paging delegate has a ResultSet from which each of the page values are extracted. That ResultSet needs to be released.
## Sticky Connections
By default, there is no guarantee that the connection that `getPage()` receives will be the same one
on each invocation. And that is fine. For most APIs (especially Rest APIs), this is not only _not_ a
problem, but in some cases, it is a feature. However, there are other cases (like Database) in which
all pages **MUST** be obtained using the **SAME** connection. This was impossible to do with Devkit.
Mule SDK adds sticky connections, which signal that the runtime must guarantee that the `getPage()`
method is always invoked with the same transaction, for example:
```java
public PagingProvider> list(String sql) {
return new PagingProvider>() {
private ResultSet resultSet;
@Override
public List> getPage(DbConnection connection) {
...
}
@Override
public java.util.Optional getTotalResults(DbConnection connection) {
...
}
@Override
public void close(DbConnection connection) throws MuleException {
...
}
@Override
public boolean useStickyConnections() {
return true;
}
}
}
```
## Configuring Streaming
Just like with binary streaming, auto-paged operations automatically get the streaming configuration
through ` `, ` `, and
` `. For details on these elements, see
[binary streaming](https://docs.mulesoft.com/mule-sdk/latest/binary-streaming). Here is an example that configures custom file store streaming
for the select example above:
```xml
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers, response, output
---
# Obtaining Flow Output and Sending Responses from a Message Source
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
One of the main properties of a Source indicates whether it generates a response or not.
Examples of sources that do not emit a response:
- A File listener
- Salesforce streaming API
- A Scheduler element
- A Source that listens for asynchronous push notifications
Sources that do emit a response:
- A TCP server
- An HTTP server
- A JMS server
As you can see, this classification is highly non-deterministic, for example:
- Although an HTTP server supports sending a response, the user might choose not to do so.
- Although a JMS listener might respond by sending a message to a reply queue, it might not,
depending on the message headers.
Even if a Source can send a response, the Source might not send a response even if the message was
processed successfully. There are logic or configuration circumstances that might skip the process
of sending the response.
To specify that your source can generate the response, it must be annotated with `@EmitsResponse`.
Notice that this simply tells the runtime and tooling that the source has the capability of doing
so.
However, note that the neither the SDK nor the runtime will:
- Validate that a source that emits a response actually emits a response.
- Prevent a source from sending a response even when the source does not declare that it emits
responses.
## Callback Parameters
Each time the flow finishes processing a message generated by the source, the source might need to
obtain the response that the flow has generated. You do this through _callback methods_. Callback
methods are used to tap into the responses generated by the flow that owns the source. You can do
this by declaring methods annotated with `@OnSuccess` , `@OnError`, and `@OnTerminate`. These
methods are declared in a similar fashion as operations, but they need to be void because they
listen for the response but cannot alter it.
Each of the parameters in these callback methods is evaluated in the same manner as operations
(including auto-transformation). Notice, however, that because these callbacks are executed in
response to the runtime processing a message, the callbacks can accept expressions (the default).
> [!TIP] Even if the source does not emit responses, it might need callback methods for releasing
> resources, logging, auditing, and so on.
## Listening for Successful Outputs
The source can declare a method with the `@OnSuccess` annotation so that the method is executed when
the flow successfully processes the message (either because no errors were thrown or because they
were all handled gracefully).
This method can have arguments that are treated as source parameters. Note that the user of the
connector cannot (and does not need to) tell the difference between a regular parameter and a
callback one. For that use, it is all the same, and Studio shows which parameters accept expressions
and which ones do not. The user should not need to worry about anything else.
Another important thing to keep in mind is that the processing of the message once the source has
pushed it to the flow is asynchronous. So the `@OnSuccess` method will also be invoked
asynchronously.
Here is another oversimplified example from the HTTP connector:
```java
@EmitsResponse (1)
public class HttpListener extends Source {
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
httpServer = serverProvider.connect();
httpServer.listen(path).onRequest(request -> {
SourceCallbackContext ctx = sourceCallback.createContext(); (2)
ctx.setVariable("responseContext", new HttpResponseContext(request.getResponseSender())); (3)
Result result = requestToResult(request);
sourceCallback.handle(result, ctx); (4)
});
}
@OnSuccess
public void onSuccess(@Content String responseBody,
@Optional String responseStatusCode,
SourceCallbackContext callbackContext) (5)
throws Exception {
if (hasResponse(responseStatusCode)) { (6)
HttpResponseContext responseContext = callbackContext.getVariable("responseContext"); (7)
responseContext.sendResponse(responseBody, statusCode); (8)
}
}
}
```
1 The example annotates the source with @EmitsResponse because this HttpListener might send a response. 2 Because the @OnSuccess method is invoked asynchronously (and most likely in parallel), it is necessary to communicate state to the callback method. More precisely, it is necessary to provide some kind of reference regarding the actual request to reply into. To accomplish that, the example creates a new SourceCallbackContext using the SourceCallback. 3 The example adds a variable into the context that holds an HttpResponseContext. This is a custom object defined in the connector that knows how to send responses. 4 The example generates and pushes the message through the SourceCallback, using both the Result object and the newly create context. 5 The callback method has two parameters, a @Content one for the body of the response to be sent and the HTTP status code of the response. There is a third argument of type SourceCallbackContext. This is not a parameter but a way to tell the SDK that to recover the same context that was passed to the handle() method. 6 Because the HTTP protocol does not always send a response, the example checks to see if the response status code requires the response to be sent or not. 7 If a response is needed, the example recovers the response context that was originally set on the context. 8 The response is sent.
## Listening for Error Outputs
Similar to `@OnSuccess`, the `@OnError` is executed when an unhandled error is thrown by the flow,
for example:
```java
@OnError
public void onError(@Optional @DisplayName(ERROR_RESPONSE_SETTINGS) @NullSafe HttpListenerErrorResponseBuilder errorResponseBuilder,
SourceCallbackContext callbackContext,
Error error) {
}
```
In this case, the method is very similar to the success example. It also receives parameters and the
callback context, and it sends an error response back to the requester. It can also receive an Error
object. This is the Mule Error object that contains information about the obtained failure.
> [!TIP] The `Error` object is not a Java `java.lang.Error` object but an SDK
> `org.mule.runtime.api.message.Error`.
## Content Parameters
Callbacks accept content parameters just like any operation. In the case of the HTTP connector, the
`HttpListenerResponseBuilder` uses them so that DataWeave can be used to transform the flow’s result
into whatever format the connector intends to return. All the concepts of content and primary
contents apply, as well as their associated restrictions.
## On Terminate
A source does not need to provide `@OnSuccess` or `@OnError` methods. A source can declare the ones
it needs or none at all. However, if at least one of them is defined, then you also need to define
an `@OnTerminate` method.
This is required because the `@OnSuccess` or `@OnError` might fail. If either of them throws an
exception, a remote system might hang as it waits for a response, resources might leak, audit logs
might be left uncompleted, and so on.
Here is an example of an `onTerminate` method:
```java
public void onTerminate(SourceResult sourceResult) {
Boolean sendingResponse = (Boolean) sourceResult.getSourceCallbackContext().getVariable(RESPONSE_SEND_ATTEMPT).orElse(false);
if (FALSE.equals(sendingResponse)) {
sourceResult
.getInvocationError()
.ifPresent(error -> sendErrorResponse(new
HttpListenerErrorResponseBuilder(),
sourceResult.getSourceCallbackContext(),
error,
null));
}
}
```
The method receives a `SourceResult` object that contains optional errors that might have occurred
in either the `onSuccess` or `onError` methods and the associated `SourceCallbackContext`.
In the example above, the method sends a generic error response in case an error was found.
## Next Step
- [Sending asynchronous responses from a Message Source](https://docs.mulesoft.com/mule-sdk/latest/sources-async-response)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers, config, connection
---
# Obtaining the Config and Connection in a Message Source
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## Obtaining the Config Object
Just like operations, a source might reference a configuration to obtain parameters about its
behavior. To obtain such a configuration, a field must be annotated with the `@Config` annotation
(the same used in operation arguments):
```java
public class HttpListener extends Source {
@Config
private HttpListenerConfig config;
}
```
## Obtaining a Connection
If the source requires a connection (and 99% of connectors do unless you are implementing a
Scheduler), you need to obtain a connection. As with operations, the `@Connection` annotation is
used but with two major differences:
- It is used in a field instead of a method argument.
- Instead of the connection object, a `ConnectionProvider` is injected.
```java
public class HttpListener extends Source {
@Config
private HttpListenerConfig config;
@Connection
private ConnectionProvider serverProvider;
@Parameter
@Optional(defaultValue = "/")
private String path;
private HttpServer httpServer;
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
httpServer = serverProvider.connect(); (1)
httpServer.listen(path).onRequest(request -> { (2)
processRequest(request, sourceCallback); (3)
});
}
@Override
public void onStop() {
if (httpServer != null) { (4)
serverProvider.disconnect(httpServer); (5)
}
}
}
```
1 The example uses the ConnectionProvider to obtain an HttpServer. The typical connection provider has already configured the server with the proper host and port. 2 HTTP requests are pushed into the server by the remote clients, and the HttpServer component notifies the source of every request. The source then uses the SourceCallback to push the message into the flow. 3 The source should define the processRequest method to transform the HTTP request into a message that can be pushed to the flow. The documentation will show how to do that later, but to keep the example simple, you can assume that this works. 4 The onStop() method releases resources, in this case, the HttpServer. It checks for null in case the onStart() method fails before the server is created. 5 The example uses the disconnect() method of the ConnectionProvider to release the server.
> [!TIP] The example above is pseudocode. It oversimplifies the real HTTP connector to keep the
> example clear and concise.
## Next Step
- [Pushing Messages to a Flow from a Message Source](https://docs.mulesoft.com/mule-sdk/latest/sources-push-message)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, operation, processor, result, execution, void, payload,
---
# Operations
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Operations are one of the most important Mule concepts because they represent the actions your
module can perform inside a flow. You use them to process incoming messages through business logic
that is implemented in the module.
## Declaring Operations for a Config
Operations must be declared inside a separate class. See [Structure](https://docs.mulesoft.com/mule-sdk/latest/module-structure) to learn how
to correctly organize your module’s code.
> [!TIP] A class is either a Config class or an Operations class. You cannot have both things mixed
> together in the same class.
```java
@Extension(name = "Foo")
@Operations(FooOperations.class)
public class FooModule {
@Parameter
private String fooModuleParameter;
public String getFooModuleParameter() {
return fooModuleParameter;
}
}
```
All the public methods defined in `FooOperations` are going to be considered as our operations. If
you want to have a public method inside your operation class but you don’t want it to be consider as
an operation, you just need to annotate that method with `@Ignore`.
Like this:
```java
public class FooOperations {
public String foo(@Config FooModule config) {
return config.getFooModuleParameter();
}
private String thisIsNotAnOperation() {
return "bar";
}
@Ignore
public String thisIsNotAnOperationEither() {
return "foobar";
}
}
```
In the example above, the operation class is bound to the only config (which is the same as the
extension class). This means that the operations defined in `FooOperations` are only available to be
used with a certain type of configuration (`FooModule`, in this case).
> [!TIP] Remember that you can use your extension as a config _if and only if_ it is the only
> configuration you have.
So, an operation named `foo` is defined. Because **it belongs to the configuration** `FooModule`, it
can receive the configuration class as an argument annotated with the annotation `@Config`.
You cannot annotate the argument annotated as `@Config` with the annotations you use for any
[Parameter](https://docs.mulesoft.com/mule-sdk/latest/parameters) because the config is not a parameter.
## Global Operations
Besides adding operations that are exclusive to a particular config, you can also add operations at
extension level, that is, operations that are global to the module.
Operations at extension level cannot not have a config unless the extension class is the only
config. This means that they are not bound to a config. To define operations at extension level, you
need to annotate the extension class with your `@Operations` while having configurations defined,
rather than using the extension class as your only config.
Take into account that this only makes sense if you have more than just one config. That’s because
if we only have the extension class (our only config), then all the operations we define are bound
to it.
The next example adds two configs and defines operations for each of them. Then it adds some
operations that are global to the module.
```java
@Extension(name = "Foo")
@Operations(GlobalOperations.class)
@Configurations({FooConfig.class, BarConfig.class})
public class FooModule {
}
```
```java
public class GlobalOperations {
public String fooModuleOperation() {
return "this operation is global to the module!";
}
}
```
The example above defines a module with two configurations, `FooConfig` and `BarConfig`, and a set
of operations defined in `GlobalOperations`.
Now, see the configs and their operations:
```java
@Operations({FooConfigOperations.class})
public class FooConfig {
@Parameter
private String fooParameter;
public String getFooParameter() {
return fooParameter;
}
}
```
```java
public class FooConfigOperations {
public String fooConfigOperation(@Config FooConfig config) {
return "this operation receives the FooConfig which has a fooParameter with value: " + config.getFooParameter();
}
}
```
The example above defines a new configuration named `FooConfig` with some exclusive operations
defined in `FooConfigOperations`. Then it defines an operation named `fooConfigOperation`. Because
it belongs to the configuration `FooConfig`, it can receive the configuration class as an argument
annotated with the special annotation `@Config`.
```java
@Operations({BarConfigOperations.class})
public class BarConfig {
@Parameter
private String barParameter;
public String getBarParameter() {
return barParameter;
}
}
```
```java
public class BarConfigOperations {
public String barConfigOperation(@Config BarConfig config){
return "this operation receives the BarConfig which has a barParameter with value: " + config.getBarParameter();
}
}
```
Defining an operation at the extension level (as with the `GlobalOperations` methods above)
represents that the defined operations do not receive (and therefore do not need) any configuration
to operate.
For more information about configurations, see [Configs](https://docs.mulesoft.com/mule-sdk/latest/configs).
## Connected Operations
In addition to receiving a configuration as an argument, you can receive the connection as a
_special_ argument. You do this by defining a [Connection Provider](https://docs.mulesoft.com/mule-sdk/latest/connections) for the
configuration to which this operation belongs.
The next example adds a connection to a [previous example](#example_1).
Suppose that you define a `FooConnectionProvider` elsewhere that provides connections of type
`FooConnection`. (To learn how to define a Connection Provider, see
[Connection Provider](https://docs.mulesoft.com/mule-sdk/latest/connections).)
```java
@Operations({FooConfigOperations.class})
@ConnectionProviders(FooConnectionProvider.class)
public class FooConfig {
@Parameter
private String fooParameter;
public String getFooParameter() {
return fooParameter;
}
}
```
```java
public class FooConfigOperations {
public String fooConfigOperation(@Config FooConfig config){
return "this operation receives the FooConfig!";
}
public String fooConnectedOperation(@Connection FooConnection connection){
return "this operation receives FooConnection!";
}
public String fooConnectedOperation(@Config FooConfig config, @Connection FooConnection connection){
return "this operation receives both config and connection!";
}
}
```
Now, there are three different operations:
- One that receives the config `FooConfig`.
- One that receives the connection `FooConnection`.
- And one that receives the config `FooConfig` and gets a connection of type `FooConnection`
provided by the `FooConnectionProvider` provider class.
## Operation Structure
An operation is defined from a Java method, which makes the mapping of the method’s argument and the
operation parameters straightforward. Following the same logic, the operation’s output type is taken
from the method’s return type.
### Output
The next sections explain how the output of an operation affects what happens in the flow when you
invoke the operation.
#### Payload
The common behavior is to define an operation that returns any type that will be set in the
operation output message’s payload.
```java
public String outputStringPayload(){
return "this string is going directly into the payload!";
}
```
\[TIP\] If an operation specifies **only** a payload, then the message attributes will be set to
`null`.
#### Void
A void operation is an operation that was created from a method that returns `void`. This operation
does not modify the message received but does pass that message to the next component in the flow,
for example:
```xml
```
Here, the message received in `void-operation` is the same as the one received in `other-operation`.
#### Result
If you want to output something more than a simple payload, such as information about the payload
(attributes of the Mule message), you need to use a `Result` as the your method’s return type. See
[Result](https://docs.mulesoft.com/mule-sdk/latest/result-object) for more information.
### Special Arguments
So, you can receive the a configuration and a connection in an operation. Are there other special
arguments other than regular parameters? Yes.
Here are some special things you can receive as an argument in an operation, and Mule will
automatically inject the right value there for you:
- `AuthenticationHandler`: An argument of type `AuthenticationHandler` that allows you to configure
the current context’s authentication. This is used for encryption and inbound authentication.
- `StreamingHelper`: An argument of type `StreamingHelper` with utilities for working with streams.
See [Streaming](https://docs.mulesoft.com/mule-sdk/latest/streaming) for more information.
- `DefaultEncoding`: An argument of type `String` annotated with `@DefaultEncoding` with information
about the Runtime’s default encoding.
```java
public String foo(@DefaultEncoding String encoding) {
return "Mule default encoding is " + encoding;
}
```
## Aliasing an Operation
You can change the name of an operation without having to change the name of the method by using
`@Alias`. You can also alias the operation’s parameters as explained in [Parameters](https://docs.mulesoft.com/mule-sdk/latest/parameters).
```java
@Alias("fooOperation")
public void thisWillNotBeTheOperationName(@Alias("fooParameter") String aliasedParameter) {
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Output Metadata
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Output metadata is the type resolution for the result of a component. Each component can provide
either static or dynamic metadata for the payload and attributes, isolated from each other.
## Declaring an OutputTypeResolver and AttributesTypeResolver
Both `OutputTypeResolver` and `AttributesTypeResolver` implementations handle the requests for
resolving a `MetadataType` based on the information provided by the `MetadataContext` and most
importantly, using the `MetadataKey` to identify the `MetadataType` required by the end user (who is
creating a Mule app). Refer to [What is the Metadata of a Component](https://docs.mulesoft.com/mule-sdk/latest/metadata#component-metadata)
for more information about the `MetadataType`.
The `OutputTypeResolver` and `AttributesTypeResolver` interfaces are parameterized with the
generic `T`, which must match the type of the `MetadataKeyId` parameter. The examples here use type
`String` for the generic because it is the most common `MetadataKeyId` type. (Other documentation
will revisit this generic and go in detail about when the type should change to something other than
`String`.)
```java
public class OutputEntityResolver
implements OutputTypeResolver, AttributesTypeResolver {
@Override
public String getCategoryName() {
return "Records";
}
@Override
public String getResolverName() {
return "OutputEntityResolver";
}
@Override
public MetadataType getOutputType(MetadataContext context, String key)
throws MetadataResolvingException, ConnectionException {
switch (key) {
case "Author_id":
return context.getTypeLoader().load(AuthorResult.class);
case "BookList_id":
return context.getTypeLoader().load(BookListResult.class);
case "Book_id":
return context.getTypeLoader().load(BookResult.class);
default:
throw new MetadataResolvingException("Unknown key:" + key, INVALID_METADATA_KEY);
}
}
@Override
public MetadataType getAttributesType(MetadataContext context, String key)
throws MetadataResolvingException, ConnectionException {
if ("Book_id".equals(key)){
return context.getTypeLoader().load(BookAttributes.class);
}
// Only Books have Attributes information
return context.getTypeBuilder().nullType().build();
}
}
```
The example above uses the `MetadataContext` only to obtain the `typeLoader` for describing a
MetadataType based on a Java class, but it could also use the provided Configuration and Connection
elements.
## Using the OutputTypeResolver
After you have a `TypeKeysResolver` and an `OutputTypeResolver`, you can add output DataSense
support to our Operations and Sources. The main restriction to using an `OutputTypeResolver` with a
given `TypeKeysResolver` is that both must belong to the same `category`, which guarantees that the
`MetadataKey` provided by the `TypeKeysResolver` can be resolved to a `MetadataType` by the
`OutputTypeResolver`:
### Adding DataSense for the Result Payload
```java
public class FetchOperations {
@OutputResolver(output = OutputEntityResolver.class)
public Map get(@Connection MyConnection connection,
@MetadataKeyId(EntityKeysResolver.class) String entityKind){
return connection.getClient().fetch(entityKind);
}
}
```
Above, the MetadataType for the output is resolved dynamically based on the `entityKind` that is
being fetched, so if the `entityKind` is configured with the `Author_id` key provided by the
`EntityKeysResolver`, then the `OutputEntityResolver` will be invoked with that `MetadataKey`, and
the output for the `get` operation will be resolved to an `AuthorResult` ObjectType.
A source can use the same output type resolution for describing the MetadataType of the object being
dispatched to the flow, and its declaration is similar:
```java
@MetadataScope(keysResolver = EntityKeysResolver.class,
outputResolver = OutputEntityResolver.class)
public class ListenerSource extends Source, Void> {
@MetadataKeyId
@Parameter
public String type;
@Connection
private ConnectionProvider connection;
@Override
public void onStart(SourceCallback, Void> sourceCallback) throws MuleException {
//...
}
@Override
public void onStop() {
//...
}
}
```
Both sources and operations have the same lifecycle for resolving the output type. The first step is
to configure the `MetadataKeyId`, and then the `OutputTypeResolver` is invoked with that key in
order to resolve the resulting entity MetadataType.
### Adding DataSense for the Result Attributes
Dynamic metadata resolution takes into account that a component’s full output is a
`Result`, not just the payload.
When an operation or source output has a dynamic attributes structure, you can resolve its
MetadataType by declaring an `AttributesTypeResolver` (already implemented in the
`OutputTypeResolver.java` example) and then adding a reference to it in the operation or source
declaration.
In the next example, the `Book` entity can be divided into the content and attributes of the Book,
each with its own structures. This division is done so the end user can better understand and use
the result of the operation. They can think about the data (which is the content of the Book that
goes in the payload) and the metadata that characterizes the payload (the attributes of the Book):
```java
public class FetchOperationsWithAttributes {
@OutputResolver(output = OutputEntityResolver.class,
attributes = OutputEntityResolver.class)
public Result get(@Connection MyConnection connection,
@MetadataKeyId(EntityKeysResolver.class) String entityKind){
if ("Book_id".equals(entityKind)){
Book book = (Book)connection.getClient().fetch(entityKind);
return Result.builder()
.output(book.content())
.attributes(book.attributes())
.build();
}
return Result.builder()
.output(connection.getClient().fetch(entityKind))
.build();
}
}
```
Sources have a declaration similar to the one used for the payload, but it adds an
`attributesResolver` reference:
```java
@MetadataScope(keysResolver = EntityKeysResolver.class,
outputResolver = OutputEntityResolver.class,
attributesResolver = OutputEntityResolver.class)
public class ListenerSource extends Source, Object> {
@MetadataKeyId
@Parameter
public String type;
//...
}
```
## Output Metadata with a User-Defined MetadataKey
The case for user-defined MetadataKeys also applies for the output of a component. In the case of a
query, you do not have a predefined set of possible MetadataKeys. Instead, you have a parameter with
a value that characterizes the output type or structure.
For example, the Database connector has the `select` operation. Its output depends on what entities
are queried:
```java
@OutputResolver(output = SelectMetadataResolver.class)
public List> select(@MetadataKeyId String sql, @Config DbConnector connector){
// ...
}
```
With the `SelectMetadataResolver` declared as:
```java
public class SelectMetadataResolver extends BaseDbMetadataResolver implements OutputTypeResolver {
@Override
public String getCategoryName() {
return "DbCategory";
}
@Override
public String getResolverName() {
return "SelectResolver";
}
@Override
public MetadataType getOutputType(MetadataContext context, String query)
throws MetadataResolvingException, ConnectionException {
if (isEmpty(query)) {
throw new MetadataResolvingException("No Metadata available for an empty query", FailureCode.INVALID_METADATA_KEY);
}
ResultSetMetaData statementMetaData = getStatementMetadata(context, parseQuery(query));
if (statementMetaData == null) {
throw new MetadataResolvingException(format("Driver did not return metadata for the provided SQL: [%s]", query),
FailureCode.INVALID_METADATA_KEY);
}
ObjectTypeBuilder record = context.getTypeBuilder().objectType();
Map recordModels = resolveRecordModels(statementMetaData);
recordModels.entrySet()
.forEach(e -> record.addField().key(e.getKey()).value(e.getValue()));
return record.build();
}
}
```
## List Metadata Automatic Wrapping
In the `select` example, you can see that the operation returns a `List`. This
makes sense because the result of a select query is multiple record entries, but the
`SelectMetadataResolver` does not describe an ArrayType in the `getOutputType` method. Instead the
returned MetadataType represents a single `record` structure.
Why is that?
As you might know already, the operation is returning an ArrayType (List, PagingProvider, and so
on), so you only need to describe the `generic` type of the array. The output and attributes
TypeResolvers always resolve the MetadataType of _the elements of the collection_ and not the
_collection_ type itself. This allows for greater reuse of the MetadataType resolvers and reduces
the amount of code needed.
Take into account that the resolved attributes will _also_ be the attributes of the _elements_ of
the collection, _not_ attributes of the operation’s `List` output.
## Resolving Dynamic Output Metadata without MetadataKey
As with input, the output of an operation can be resolved without a specific `MetadataKey`, being
the dynamic type affected by the Configuration or Connection of the Component. Again, to declare a
keyless resolver, you simply skip the `MetadataKeyId` parameter and ignore the MetadataKey in the
TypeResolvers:
```java
public class UserTypeResolver implements OutputTypeResolver, AttributesTypeResolver {
@Override
public String getCategoryName() {
return "User";
}
@Override
public MetadataType getOutputType(MetadataContext context, Object key)
throws MetadataResolvingException, ConnectionException {
// The `key` parameter will be `null` if the fetch is performed
// as a `KeyLess` Metadata resolution. We'll just ignore it.
String schema = getUserSchema(context);
return new JsonTypeLoader(schema).load("http://demo.user")
.orElseThrow(() -> new MetadataResolvingException("No Metadata is available for the User",
FailureCode.NO_DYNAMIC_TYPE_AVAILABLE));
}
@Override
public MetadataType getAttributesType(MetadataContext context, Object key)
throws MetadataResolvingException, ConnectionException {
// The `key` parameter will be `null` if the fetch is performed
// as a `KeyLess` Metadata resolution. We'll just ignore it.
String schema = getUserSchema(context);
return new JsonTypeLoader(schema).load("http://demo.attributes")
.orElseThrow(() -> new MetadataResolvingException("No Metadata is available for the User Attributes",
FailureCode.NO_DYNAMIC_TYPE_AVAILABLE));
}
private String getUserSchema(MetadataContext context) throws MetadataResolvingException, ConnectionException {
return context.getConnection()
.orElseThrow(() -> new MetadataResolvingException("A connection is required to resolve Metadata but none was provided",
FailureCode.INVALID_CONFIGURATION))
.describeUser();
}
}
```
```java
public class UserOperations {
@OutputResolver(output = UserTypeResolver.class, attributes=UserTypeResolver.class)
public Result, Object> getUser(@Connection DemoConnection connection){
User user = connection.getUser();
return Result., Object>.builder()
.output(user.personalInfo())
.attributes(user.accountInfo())
.build().
}
}
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, parameter
---
# Parameters
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Parameters are configurable arguments that belong to a given component. [Configurations](https://docs.mulesoft.com/mule-sdk/latest/configs),
[Components](https://docs.mulesoft.com/mule-sdk/latest/module-structure#components), and [Connection Providers](https://docs.mulesoft.com/mule-sdk/latest/connections) are called
_parameterizables_ because they can be configured through their parameters.
Parameters provide the information that the component needs so that it can be configured to work
properly. Each parameter contains the following information:
- A type that restricts the kind of value the parameter can have.
- A name that uniquely identifies it.
Here is a simple example:
```java
@Parameter
private String foo;
```
A parameter can be defined as a field of a class or as a method’s argument, depending on the kind of
component you are dealing with.
For example, an [operation](https://docs.mulesoft.com/mule-sdk/latest/operations) parameter is defined like any argument of the method that
declares the operation. It does not need to be annotated with `@Parameter`.
Take a look at `foo` below.
```java
public void method(String foo){}
```
## Using Complex Types
This example uses more complex parameters instead of simple types like strings and integers.
```java
@Parameter
@Optional
private Options options;
```
Where `Options` is a `POJO Object` defined as:
```java
public class Options {
@Parameter
public String color;
@Parameter
@Optional
public String mode;
public String getColor(){
return color;
}
public void setColor(String color){
this.color = color;
}
public String getMode(){
return mode;
}
public void setMode(String mode){
this.mode = mode;
}
}
```
A few notes about this example:
- The entire parameter `Options` is used as an optional parameter, so if you decide to use it, you
need to ensure that all the required parameters inside `Options` have been set.
- If `Options` is not configured, its value will be `null` (see [NullSafe](https://docs.mulesoft.com/mule-sdk/latest/null-safe) for altering
this behavior).
- `Options` parameters must be Java bean properties (that is, they need to have setters and getters
that match the fields names).
### Complex Type DSL
Complex types should be separated from regular parameters. It does not make sense to merge all the
complex type attributes with the element-specific parameters.
That is why a child definition is created for Complex Types. This example shows the complex
`Options` type in a [Configuration](https://docs.mulesoft.com/mule-sdk/latest/configs):
```xml
```
Note that `module:options` is separated from the parameters `name` and `someConfigAttribute`.
## Modifiers
Parameters are highly customizable. This section identifies a few modifiers you can use when
defining a parameter to specify behavior or restrictions.
### Expression Support
An `ExpressionSupport` describes the parameter’s behavior when the configured value is a DataWeave
expression.
There are three possible values:
- `REQUIRED`: The parameter only accepts expressions.
- `SUPPORTED` (default): The parameter can handle both expressions and simple values.
- `NOT_SUPPORTED`: The parameter requires static values. Expressions are not supported.
These values can be configured simply by adding the `@Expression` annotation.
```java
@Parameter
@Expression(SUPPORTED)
private String foo;
```
The example above defines a parameter named `foo` of type `String` that can have either a static
value (such as `"bar"`) or an expression (such as `"\#[vars.foo]"`).
### Optionality
Parameters can be required or optional.
Sometimes a parameter specifies information that is so crucial to what you are trying to do (for
example, the host name for an HTTP Request) that there is no way to continue without setting it.
Other times, you can operate without that information or simply use a default value (for example,
where a port is 80 in an HTTP listener).
A parameter is required by default unless you annotate it with `@Optional`, for example:
```java
@Parameter
@Optional(defaultValue="80")
private Integer port;
```
Optional parameters can have a default value.
Note that `@Optional` only accepts `String` values, but the SDK will auto-convert it to your
parameter’s type. Additionally, if the parameter supports expressions, you can use one as the
default value.
### Using @Alias
The name of each parameter will be the name given to the field in which it is defined. You can
override this name by using the `@Alias` annotation.
```java
@Parameter
@Optional
@Alias("class")
private String clazz;
```
Notice that the use of `@Alias` makes it possible to use a Java reserved term (such as `class`) to
name the parameter. You cannot use a reserved term to name the field.
### Customizing the Parameter DSL
It is possible to customize how the Parameter looks and behaves in the DSL using the `@ParameterDsl`
annotation. This annotation allows you to set directives regarding syntax and semantics of the
generated XML DSL, and it can be applied to any Parameter in the model.
The `@ParameterDsl` annotation has two configurable elements:
- `allowInlineDefinition`:
Indicates whether the associated Parameter should support inline definition as child element or
not. This is used for customizing the DSL of Complex Type Parameters, especially when you need to
avoid the inline definition because it has illegal fields (like a `name` field) or because the
structure is so complex that makes no sense to represent it inline.
For example, if you use the `Options` type in a [Configuration](https://docs.mulesoft.com/mule-sdk/latest/configs) and declare the Parameter
with `@ParameterDsl(allowInlineDefinition=false)`, you no longer have the child element:
```xml
```
- `allowReferences`:
Indicates whether the associated Parameter should support registry references when receiving an
`String`. This is useful for controlling how the Parameter will behave upon configuration if the
type of the Parameter doesn’t provide enough information to automatically configure the references
support.
For example, in the JMS Connector, if you want to avoid making users inject an object from the
registry as a `ConsumerType` configuration, you declare it as not supporting references:
```java
@Parameter
@Optional
@Expression(NOT_SUPPORTED)
@ParameterDsl(allowReferences = false)
private ConsumerType consumerType;
```
## Parameter Groups
The `@ParameterGroup` annotation allows you to define a group of parameters that share some kind of
special relationship where it makes sense for them to belong to the same group.
How do you spot them? Parameters that should go inside a `@ParameterGroup` are the ones that
**travel together** all the times.
Using `@ParameterGroup` also makes a UI contribution rendering all the `@Parameters` inside the
group together in a box, separating them from other `@Parameters` that don’t belong to that group,
for example:

As you can see in the image above, the `Connection` group contains 4 parameters, and there are
others like `Soap Version` that are not in that group. That is a nice way to separate the concerns
of the `Parameters`.
An simple example could be a parameter group defined as follows:
```java
public class ConnectionProperties {
@Parameter
public String host;
@Parameter
@Optional(defaultValue="80")
public Integer port;
public String getHost(){
return host;
}
public void setHost(String host){
this.host = host;
}
public Integer getPort(){
return port;
}
public void setPort(Integer port){
this.port = port;
}
}
```
The example above could be used like this:
```java
@ParameterGroup("Connection")
private ConnectionProperties properties;
```
`"Connection"` is the name of the `@ParameterGroup` and is the name that will be used in the UI.
The class defining the `properties` `@ParameterGroup` will not have a parameter named `properties`.
Instead, it will contain the parameters that are defined inside `ConnectionProperties`:
- A required parameter named `host`.
- An optional parameter named `port`.
In other words, the class defining the parameter group is augmented with these extra parameters and
will contain the parameters defined inside of `ConnectionProperties` plus all the other parameters
it has declared.
Note that each field annotated with `@ParameterGroup` must be a Java bean property (that is, it
needs to have setters and getters matching the field name).
## POJO vs Parameter Group
`@ParameterGroup` can be configured so it can be written as a child element in the DSL instead of
being spread around the component that declared it.
In other words, assume an operation like this:
```java
public void execute(@ParameterGroup ConnectionProperties properties) { ... }
```
This is the DSL for the operation above:
```xml
```
However, if you configure the parameter group using `@ParameterGroup(showInDsl=true)` instead, the
DSL now looks like:
```xml
```
When a POJO `@Parameter` is defined, you get the same DSL, so you might ask when to use a POJO
instead of using a POJO annotated with `@ParameterGroup`?
There are some subtle differences between these two concepts. You should definitely use a POJO if
you care about the type as a whole and the structure it provides.
For example, `ConnectionProperties` (above) keeps two parameters together because they are always
configured together. In this case, the parameters do not represent an entity in the module’s domain.
The `@ParameterGroup` is simply a handy way of keeping things that are related together and showing
them together in the UI.
However, the `Options` POJO defined above concerns the object itself, not just the parameters it
contains. For instance, it would make sense to have a list of `Options` because each object is
something on its own (in the OOP sense). On the other hand, if you are using a class simply for the
sake of grouping things together, without any particular meaning for your module’s domain, then it
makes sense to have a parameter group.
## Parameter Type Restrictions
You cannot add parameters or POJOs with types `org.mule.runtime.core.api.source.scheduler.Scheduler`
or `org.mule.runtime.api.scheduler.SchedulingStrategy`.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, security, oauth
---
# Performing the OAuth Dance with an OAuth-Enabled Connector or Module
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The final step for using the module is to trigger the OAuth dance.
[Configuring an OAuth-Enabled Connector or Module](https://docs.mulesoft.com/mule-sdk/latest/oauth-configuring) includes a parameter called
`authorizePath` through which the end user configures the path of an automatically created HTTP
endpoint that is needed to hit a browser and start the OAuth dance.
Tip: Remember that the Authorization Code grant type that the SDK supports requires human
interaction through a web browser.
## Multi-Tenancy
Multi-Tenancy for OAuth means being able to perform the OAuth dance multiple times and to associate
each obtained token with a different resource owner ID.
The end user needs to specify the `resourceOwnerId` to assign to the token when the dance is
initiated. For example, if `authorizePath` is set to `/authorize`, and you want to perform a dance
for the user `sdk_demo`, you should hit the following HTTP path:
`/authorize?resourceOwnerId=sdk_demo`.
After the dance is complete, you execute an operation using the access token obtained for that user.
You do that by using an expression on the `resourceOwnerId` parameter of your module’s
configuration. Here is a complete example:
```xml
(1)
(2)
```
1 The resourceOwnerId parameter is set to an expression. Each time an OAuth-protected operation is executed, that expression will be evaluated, and the token associated with that value will be used. 2 The example sets the authorization endpoint authorizePath.
### Invalidating Access Tokens
Multi-tenancy implies the ability to invalidate the access token of a particular `resourceOwnerId`.
Invalidating the token causes the associated token information to be deleted.
To invalidate an access token, the SDK automatically adds an operation called `unauthorize` to every
OAuth-enabled connector or module. Returning to the example above, you might invalidate the obtained
token with any of the following statements:
```xml
```
## Next Step
[Handling Expired Access Tokens](https://docs.mulesoft.com/mule-sdk/latest/oauth-token-expiration)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Polling Sources
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
**Available since version 1.1**
Instead of getting triggered by an external action, Polling Sources are sources that poll items
periodically depending on a given `scheduling strategy` and automatically handle idempotency and
watermarking. On every poll action, many items can be dispatched to the flow, each as a single
`Message`.
## Creating a Polling Source
To create a Polling Source, you need to add the `Source` class to the `@Sources` annotation on the
extension class, just like regular Sources. For a Source to behave as a `PollingSource`, instead of
extending the class `Source`, the class needs to extend from `PollingSource`.
When extending from `PollingSource`, you need to implement the methods `poll` and
`onRejectedItem`.
- `poll` is responsible for obtaining the items to be dispatched and communicating with them through
the `pollContext` using the `accept` method.
- `onRejectedItem` is called when one of the dispatch items was rejected (for example, by
watermarking idempotency or server overload). This method is called to release any resources
associated with the result set for the `PollItem`.
Here is an example of the declaration of these methods on the directory listener implementation for
the FTP connector:
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Override
public void poll(PollContext pollContext) {
// ...
}
@Override
public void onRejectedItem(Result result, SourceCallbackContext callbackContext) {
// ...
}
// ...
}
```
## Implementing the Poll Method
This method gathers all the items to be dispatched and processes them one by one.
The `accept` method from the `PollContext` is in charge of dispatching the polled items into the
flow. It receives `Consumer` as a parameter.
This example shows how to set the Message to dispatch to the flow:
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Override
public void poll(PollContext pollContext) {
if(pollContext.isSourceStopping()){ (1)
return;
}
List attributesList = listFilesAttributes();
for (FtpFileAttributes attributes : attributesList) {
if(pollContext.isSourceStopping()){ (1)
break;
}
pollContext.accept(item -> { (2)
Result result = read(attributes.getPath());
item.setResult(result); (3)
});
}
}
// ...
}
```
1 Note that the pollContext provides information on whether the Source is stopping. This must be taken into account before any time-consuming task. 2 accept dispatches an item to the flow.3 setResult is used to set the Message that is dispatched.
### Idempotency
Idempotency prevents items from getting polled twice. The SDK ensures that no other thread or
cluster node is processing an item of the same ID, which provides processing idempotency. No two
items with the same ID will be processed at the same time. If a node polls an item with the ID of an
item that is being processed, the item will be dropped, and the `onRejectedItem` method will be
called.
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Override
public void poll(PollContext pollContext) {
if(pollContext.isSourceStopping()){
return;
}
List attributesList = listFilesAttributes();
for (FtpFileAttributes attributes : attributesList) {
if(pollContext.isSourceStopping()){
break;
}
pollContext.accept(item -> {
Result result = read(attributes.getPath());
item.setResult(result);
item.setId(attributes.getPath()); (1)
});
}
}
// ...
}
```
1 setId is used to set the ID used for idempotency.
### Watermarking
You can use watermarking when you are polling an incremental source of data and you only want the
new data instead of manually dividing the new data from the old data on each call.
By setting an incrementing value to the item’s watermark, every other poll will drop and call
`onRejectedItem` on any of the item’s watermark values that are lower than the current watermark
value. In the example above, the chosen watermark is the timestamp of the file.
What criteria does the SDK use to compare watermarks?
If the watermarks that you use implement `Comparable`, the natural order of those values will be
used. There is no need to set a criterion.
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Parameter
@Optional(defaultValue = "false")
private boolean watermarkEnabled = false; (1)
// ...
@Override
public void poll(PollContext pollContext) {
if(pollContext.isSourceStopping()){
return;
}
List attributesList = listFilesAttributes();
for (FtpFileAttributes attributes : attributesList) {
if(pollContext.isSourceStopping()){
break;
}
pollContext.accept(item -> {
Result result = read(attributes.getPath());
item.setResult(result);
item.setId(attributes.getPath());
if (watermarkEnabled) { (1)
item.setWatermark(attributes.getTimestamp()); (2)
}
});
}
}
// ...
}
```
1 A typical best practice is to let the user decide whether to use watermarking or not. 2 setWatermark sets the file timestamp as watermark.
What if the watermark values do not implement `Comparable`, or what if I want to use another
criteria that is not the natural order?
You can simply set a `Comparator` to the `PollContext` by calling its method
`setWatermarkComparator`.
> [!NOTE] If the watermark updates are not set before polling is complete, you can add a latch to
> avoid updating the watermark in two iterations.
### PollItemStatus
If you call the `accept` method, you get a `PollItemStatus` in return. This is an `Enum` that can
take the following values:
- ACCEPTED: The item was accepted and has been scheduled for execution.
- FILTERED\_BY\_WATERMARK: The item was rejected because watermarking was enabled, so it was
filtered.
- ALREADY\_IN\_PROCESS: The item was rejected because idempotency was enabled and another thread or
node is already processing this item.
- SOURCE\_STOPPING: The item was rejected because the source has received the stop signal.
You could use this to log the status of each item polled:
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Parameter
@Optional(defaultValue = "false")
private boolean watermarkEnabled = false;
// ...
@Override
public void poll(PollContext pollContext) {
if(pollContext.isSourceStopping()){
return;
}
List attributesList = listFilesAttributes();
for (FtpFileAttributes attributes : attributesList) {
if(pollContext.isSourceStopping()){
break;
}
PollItemStatus status = pollContext.accept(item -> { (1)
Result result = read(attributes.getPath());
item.setResult(result);
item.setId(attributes.getPath());
if (watermarkEnabled) {
item.setWatermark(attributes.getTimestamp());
}
});
if(!status.equals(PollItemStatus.ACCEPTED)){
LOGGER.debug("Item rejected with code: " + status.name());
}
}
}
// ...
}
```
1 Get the PollItemStatus that is logged later.
### Getting the Source Callback Context
If you need to save data to be used on the callback methods, `item` provides the
`SourceCallbackContext` for it.
This example shows how to get the context and then save data in it:
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Parameter
@Optional(defaultValue = "false")
private boolean watermarkEnabled = false;
// ...
@Override
public void poll(PollContext pollContext) {
if(pollContext.isSourceStopping()){
return;
}
List attributesList = listFilesAttributes();
for (FtpFileAttributes attributes : attributesList) {
if(pollContext.isSourceStopping()){
break;
}
PollItemStatus status = pollContext.accept(item -> {
SourceCallbackContext context = item.getSourceCallbackContext(); (1)
context.addVariable("attributes", attributes); (2)
Result result = read(attributes.getPath());
item.setResult(result);
item.setId(attributes.getPath());
if (watermarkEnabled) {
item.setWatermark(attributes.getTimestamp());
}
});
if(!status.equals(PollItemStatus.ACCEPTED)){
LOGGER.debug("Item rejected with code: " + status.name());
}
}
}
// ...
}
```
1 Gets the context from item. 2 Saves data on the SourceCallbackContext.
## Implementing the OnRejectedItem Method
This method is called when one of the dispatched items was rejected. It should release any resource
associated with the result set for the `PollItem`.
This example shows how to implement it:
```java
public class FtpDirectoryListener extends PollingSource {
// ...
@Override
public void onRejectedItem(Result result, SourceCallbackContext callbackContext) {
closeFileStream(result);
}
// ...
}
```
## How to Use Polling Sources in a Flow
The SDK automatically adds a `scheduling strategy` parameter to the source, enabling the user to
provide any strategy (like `fixed-frequency`) to handle the polling executions. The runtime will use
that strategy to automatically schedule executions of the `poll` method.
Here is an example of the FTP directory listener that uses the polling source:
```xml
```
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Publishing Connectors to Exchange
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Starting August 1, 2026, publishing connectors and Mule plugins to Exchange requires Java
compatibility metadata in `mule-artifact.json` when publishing new versions that change supported
Java compatibility.
Exchange reads Java compatibility from `mule-artifact.json` during publication.
> [!NOTE] Update your connector configuration before publishing a new connector version. This change
> doesn’t affect connectors that are already published to Exchange.
## Update Your Connector
Use the requirements that match your connector type:
- Java connectors: Include the `@JavaVersionSupport` annotation when changing supported Java
compatibility.
- XML connectors: Update to `mule-extensions-maven-plugin` so Java compatibility metadata is
generated at build time.
For XML connectors, choose the approach that matches your development setup:
- If you use the parent POM, update to a parent version that includes `mule-extensions-maven-plugin`
1.9.0 or later.
```xml
org.mule.connectors
mule-modules-parent
1.9.0
```
- If you use Mule SDK, upgrade to a version that includes `mule-extensions-maven-plugin` 1.9.0 or
later.
- If you configure Maven plugins manually, update your POM file to reference
`mule-extensions-maven-plugin` 1.9.0 or later.
```xml
org.mule.runtime.plugins
mule-extensions-maven-plugin
1.9.0
```
## Build Prerequisites
- Maven 3.8.0 or later (3.9.8+ recommended)
- JDK 17+ in the build pipeline
## Verify Your Configuration
After updating your connector configuration:
1. Build your connector locally.
```console
mvn clean install
```
2. Verify that `mule-artifact.json` contains Java compatibility information.
In your connector JAR file, confirm that `mule-artifact.json` includes the
`supportedJavaVersions` attribute.
3. Test publishing to Exchange.
Publish to a test environment before publishing to production.
## Troubleshooting
Publishing Fails After August 1, 2026
If Exchange rejects your connector with an error about missing Java compatibility information,
verify your `mule-extensions-maven-plugin` version:
1. Check your POM file for `mule-extensions-maven-plugin`.
2. Ensure the version is 1.9.0 or higher.
3. Rebuild and republish your connector.
The Build Fails After You Update the Plugin
If the Maven build fails after you update to `mule-extensions-maven-plugin` 1.9.0 or later, use
Maven 3.8.0 or later (3.9.8+ recommended) and JDK 17+ in your build pipeline.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers, generate, push, message
---
# Pushing Messages to a Flow form a Message Source
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
After generating a piece of information for the flow, the source uses the `SourceCallback` to send
the information to the flow. Returning to the minimalistic HTTP listener example:
```java
public class HttpListener extends Source {
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
httpServer = serverProvider.connect(); (1)
server.listen(path).onRequest(request -> { (2)
Result result = requestToResult(request); (3)
sourceCallback.handle(result); (4)
});
}
}
```
1 The example uses the ConnectionProvider to obtain an HttpServer. The typical connection provider most already configured the server with the proper host and port. 2 HTTP requests are pushed into the server by the remote clients, and the HttpServer component will notify the source of every request. The source then uses the SourceCallback to push the message into the flow. 3 The message is represented by leveraging the same Result object that operations use to communicate complex outputs. See Result for more information. 4 The example uses the handle(Result) method in the SourceCallback to pass the message.
## Threading Model
Once the `Result` object is passed to the `SourceCallback` through the `handle(Result)` method,
message processing occurs asynchronously in a different thread than the one invoking the method.
The next step explains how to catch the result of the Flow processing and optionally send a
response.
## Next Step
- [Obtaining Flow output and Sending responses from a Message Source](https://docs.mulesoft.com/mule-sdk/latest/sources-response)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: anypoint, studio, reconnection strategies, reconnection strategy, retry policies, retry
---
# Reconnection on Connectors
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The SDK and Mule provide out-of-the-box reconnection strategies to be applied to all connectors that
work with connections. This support is generic, so the experience of configuring and adjusting
reconnection rules is the same across connectors.
> [!IMPORTANT] HTTP Requester does not use the reconnection strategy for retries. See
> [HTTP Request Configuration Reference](https://docs.mulesoft.com/http-connector/1.5/http-request-ref#retry-mechanisms)
> for additional information.
## How the SDK Knows When to Trigger a Reconnection
The SDK and Mule provide the reconnection engine, but the connector is responsible for communicating
when a reconnection should occur, when a connection is down, and when a new connection is required.
## What is a Connection Error?
A reconnection mechanism can obtain a new, valid connection when the existing one does not work
anymore and does not allow the connector to execute its business logic. These errors are connection
or connectivity errors.
It is very important to understand when an error is a connectivity one and when it is not. Some
examples follow below.
### Examples of Connection Errors
- Connection Timeout
- Invalid Credentials
- Token Expired
### Examples of Non-connection Errors
- Missing required HTTP Query Param when doing a HTTP request
- Directory does not exist when trying to copy a file
- Publish a Null message to Slack
- Syntax error when executing a Database Query
## How to Trigger a Reconnection
The main thing on reconnection is to be able to communicate correctly when a connectivity error
occurred and is required to reconnect. How to communicate the error might differ depending on the
component where the error has been detected.
The sections below explain how to trigger a reconnection for each component of a connector.
### Connection Provider
#### Creating Connection
Connection Providers are the first moments of a connection life. At this moment, the connection
provider can fail to create a connection because of several problems, so in this moment, the
Connection Provider is able to communicate the connectivity error and trigger a reconnection, which
means try to create the connection again.
When creating the connection, `connect()` method, to declare a connection problem and is required a
reconnection a [`ConnectionException()`](#connection-exception) should be thrown.
```java
@Override
public Connection connect() throws ConnectionException {
Connection connection;
try {
connection = new Connection();
} catch (Exception e) {
throw new ConnectionException("Error occurred trying to connect.", e);
}
return connection;
}
```
#### Validating Connection
To check that a connection is still valid, the SDK can grab a live connection at any time and
validate it against the Connection Provider that created it.
To validate the connection, `validate(Connection)` is invoked, and the connection provider should
check if the given connection is valid or not. If the Connection Provider detects that the
Connection is not valid anymore, it should communicate a
[connection validation result](https://docs.mulesoft.com/mule-sdk/latest/connections#connection-validation-result) with a failure result
`ConnectionValidationResult.failure(Cause, Exception)`. This will disconnect and invalidate the
current connection, if possible, and a new connection will be created again.
Example: Validation Over Connection
```java
@Override
public ConnectionValidationResult validate(Connection connection) {
if(connection.isValid()){
return ConnectionValidationResult.success();
} else {
return ConnectionValidationResult.failure("Connection Problem", new RuntimeException());
}
}
```
### Operations
Operations can fail due to multiple causes, such as bad parameters values and unexpected errors.
Errors can also be due to connectivity errors. To indicate that the error comes from a non-working
connection, a [`ConnectionException()`](#connection-exception) is thrown. This exception **triggers
the reconnection, and the operation is executed again**.
#### Operation Example
Example
```java
public void operationTriggersReconnection(@Connection Connection connection, boolean connectionException){
if(connectionException){
throw new ConnectionException("Connection Error"); (1)
} else {
throw new RuntimeException(); (2)
}
}
```
1 If a ConnectionException is thrown, the used connection will be invalidated. The connection provider will try to create a new valid connection, and if a connection is available, the operation will be executed again. 2 If any other exception is thrown, the error will be considered as a business error, the connection will not be invalidated, and the operation will not be executed again.
### Sources
Because a
[Sources are responsible of creating their own Connections](https://docs.mulesoft.com/mule-sdk/latest/sources-config-connection#obtaining-a-connection),
the way a Source triggers reconnections differs somewhat from Operations. If a successfully created
connection is later disconnected, the source should communicate the connection failure:
[`ConnectionException(Exception, Connection)`](#connection-exception) .
Sources have two stages, when they are [starting](#starting-source) and when they are
[running](#running-source). Each moment has to communicate their connectivity failures in different
ways.
> [!WARNING] Not communicating the Connection failure in the `ConnectionException` could make the
> reconnection mechanism fail to work properly.
#### Starting Source
A source is in the starting source stage when the `onStart()` method executes. Connection errors
must be communicated through the `SourceCallback` using the `onConnectionException()` method. The
source stops and attempts to reconnect.
Example
```java
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
Connection connection = connectionProvider.connect();
try {
connection.startStreaming();
} catch(Exception e){
sourceCallback.onConnectionException(new ConnectionException(e, connection));
}
}
```
#### Running Source
When the Source starts correctly, it means that the `onStart()` method finishes correctly, and the
remaining logic is running on other threads.
When running on other threads, the SDK is unable to detect any kind of error raised with a `throw`
statement. So the errors must be communicated through the `SourceCallback`, using the
`onConnectionException()`.
Example
```java
@Connection
ConnectionProvider connectionProvider;
@Inject
SchedulerService schedulerService;
private Scheduler scheduler;
@Override
public void onStart(SourceCallback sourceCallback) throws MuleException {
Connection connection = connectionProvider.connect();
scheduler = schedulerService.ioScheduler(); (1)
scheduler.execute(() -> {
while (true) {
try {
connection.receiveMessage();
} catch (Exception e){
sourceCallback.onConnectionException(new ConnectionException(e, connection)); (2)
}
}
});
}
```
1 Creating a scheduler to run the Source logic in a new Thread. 2 Communicating to the SourceCallback the ConnectionException containing the failure connection that should be replaced.
#### Accessing the Retry Policy Template from Within an Operation
Available since version 1.3.
There are advanced cases in which an operation might need to access the `RetryPolicyTemplate` object
that has been configured for it. For example, an operation might be leveraging an existing library
that handles retries independently, or your use case might require applying retries without
necessarily reconnecting.
To support these cases, operations can request that the effective `RetryPolicyTemplate` instance be
used by adding it as an operation parameter. Consider this example from Anypoint Connector for
WebSockets (WebSockets Connector):
```java
public void send(String socketId,
@Content TypedValue content,
@Connection WebSocketConnection conn,
CompletionCallback callback,
RetryPolicyTemplate retryPolicyTemplate) {
}
```
The retryPolicyTemplate argument is not translated into an operation parameter, but it is injected
with the effective value upon execution.
> [!NOTE] This feature is intended for advanced scenarios only. Typically, you should throw a
> ConnectionException and allow Mule to handle reconnection and retries automatically. Use this
> feature only when absolutely necessary.
## Connection Exception
A `ConnectionException` can be built with the following properties:
- **Message** : String that describes the current error.
- **Cause** : If present, Throwable indicates the cause the current error.
- [**ErrorType**](https://docs.mulesoft.com/mule-sdk/latest/errors) : If present, ErrorType describing the current error.
- **Connection** : If present, Object representing the connection failure. This will be used to
disconnect and destroy it.
### See Also
- [Sources Configuration and Connections](https://docs.mulesoft.com/mule-sdk/latest/sources-config-connection)
- [Sources Lifecycle](https://docs.mulesoft.com/mule-sdk/latest/sources-lifecycle)
- [Errors on Modules](https://docs.mulesoft.com/mule-sdk/latest/errors)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Sample Data
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Sample data enables operations and sources to provide examples of the output they produce. These
examples show information obtained from a live system through a connection or the output format from
a connectionless example.
Sample data is supported by Mule 4.4.0 or later. However, all Anypoint Connectors can use this
feature, regardless of their Mule version.
With sample data, you can:
- Implement SDK APIs
- Provide examples using operation parameters
- Provide examples using configuration and connection
## SDK APIs
Use SDK APIs to provide sample data, communicate errors, and enhance components.
### SampleDataResolver
Implement this API to enhance operations and message sources with sample data that is representative
of the data the component outputs in real production scenarios.
Implementations must:
- Provide a default constructor.
- Provide samples for both the payload and the message attributes, which return a Result
object.
Generic types always match the return types of the enhanced component. For components that return
dynamic types, each implementation returns instances of the correct dynamic type. If the operation
does not return attributes, use Result.
- Guarantee that fetching sample data does not generate any significant side effects on the target
system.
- Not be used to return large objects or data streams. The data should fit into the memory of a
small worker instance.
Implementations can access parameters, configurations, and connections to generate the sample data
through the `@Parameter`, `@Config`, and `@Connection` annotations.
For connectors, implementations are most valuable when returning real data from the system they
connect to instead of returning hard-coded values.
The following example illustrates a SampleDataResolver API:
```java
/**
* [...]
*
* @param the generic type of the output value
* @param the generic type of the message attributes
* @since 1.4
*/
@MinMuleVersion("4.4")
public interface SampleDataProvider {
/**
* An ID that identifies each implementation of this interface. It must be unique among implementations in the same
* extension. Subsequent invocations must always return the same fixed value.
*
* @return the resolver's id
*/
String getId();
/**
* Obtains and returns the sample information.
*
* @return a {@link Result} object
* @throws SampleDataException if the sample cannot be obtained
*/
Result getSample() throws SampleDataException;
}
```
Streaming is not supported for:
- Operations or sources that return an InputStream value.
The resolver always returns implementations that do not require a connection, such as a
ByteArrayInputStream value or any other offline implementations that have already procured the
entire data stream before returning the getSample() method, because the InputStream value is fully
consumable even after the underlying connection is closed. Avoid using temporal buffer files as
well.
- Operations that return a PagingProvider value, because they are considered streaming. The
limitations explained in the previous bullet apply. In these cases, a List value of the same
item type is returned instead.
### SampleDataException
This class communicates errors while fetching sample data so that the runtime can handle those
errors accordingly. Use the predefined failure code messages described in this class if necessary.
The following example illustrates a SampleDataException class:
```java
/**
* {@link Exception} to indicate that an error occurred fetching sample data through a {@link SampleDataProvider}.
*
* @since 1.4.0
*/
public class SampleDataException extends MuleException {
/**
* Signals an unexpected exception
*/
public final static String UNKNOWN = "UNKNOWN";
/**
* Indicates that the {@link SampleDataProvider} didn't return any information
*/
public final static String NO_DATA_AVAILABLE = "NO_DATA_AVAILABLE";
/**
* Indicates that a connection couldn't be established
*/
public final static String CONNECTION_FAILURE = "CONNECTION_FAILURE";
/**
* Indicates that Sample Data resolution was attempted on a {@link Location} that doesn't exist
*/
public final static String INVALID_LOCATION = "INVALID_LOCATION";
/**
* Indicates that the Sample Data resolution was attempted but the underlying {@link SampleDataProvider} has required parameters
* that weren't supplied
*/
public final static String MISSING_REQUIRED_PARAMETERS = "MISSING_REQUIRED_PARAMETERS";
/**
* Indicates that Sample Data resolution was attempted on a component that doesn't support that capability
*/
public final static String NOT_SUPPORTED = "NOT_SUPPORTED";
/**
* Indicates that Sample Data resolution was attempted on an unregistered Extension
*/
public final static String INVALID_TARGET_EXTENSION = "INVALID_TARGET_EXTENSION";
private final String failureCode;
public SampleDataException(String message, String failureCode) {
super(createStaticMessage(message));
this.failureCode = failureCode;
}
public SampleDataException(String message, String failureCode, Throwable cause) {
super(createStaticMessage(message), cause);
this.failureCode = failureCode;
}
public SampleDataException(I18nMessage message, String failureCode) {
super(message);
this.failureCode = failureCode;
}
public SampleDataException(I18nMessage message, String failureCode, Throwable cause) {
super(message, cause);
this.failureCode = failureCode;
}
/**
* @return The failure code of the error that produced the error
*/
public String getFailureCode() {
return failureCode;
}
}
```
### @SampleData
This annotation associates a resolver to the enhanced component. It is applied at the type level in
sources and at the method level for operations.
The following example illustrates a `@SampleData` annotation:
```java
/**
* Associates a {@link Source} class or operation method with a {@link SampleDataProvider}.
*
* @since 1.4.0
* @see SampleDataProvider
*/
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Documented
public @interface SampleData {
/**
* @return the associated {@link SampleDataProvider}
*/
Class extends SampleDataProvider> value();
/**
* @return bindings between parameters in the {@link SampleData#value()} to extraction expressions.
*/
Binding[] bindings() default {};
}
```
## Sample Data Examples
Obtain sample data through an operation or through configuration and connection.
### Obtain Sample Data Through a Direct Operation
Use this example to provide static sample data through an operation without using a connection.
Imagine there is a new GitHub connector that contains an operation that retrieves information in
JSON format. However, you do not want to consume an API call while providing sample data to consume
one of a limited number or costly API calls, so you directly implement the operation.
The following example illustrates a definition of the operation with the provider attached through
the `@SampleData` annotation:
```java
@SampleData(JsonSampleDataProvider.class)
public Result getUserInfo(String username, @Connection GitHubConnection connection) {
// operation code...
}
```
The following example illustrates the sample data provider implementation, which uses the
implementation shown previous to this to inject parameters. The `@Parameter` annotation has the same
name and type as the operation’s parameter, which is `username`:
```java
public class JsonSampleDataProvider implements SampleDataProvider {
private static JsonObject sampleJson = new JsonObject();
public JsonSampleDataProvider() {
sampleJson.add("company", "Mulesoft");
sampleJson.add("email", "maxmule2007@mulesoft.com");
sampleJson.add("repositories", new JsonArray("mule-api", "data-weave-2"));
}
@Parameter
private String username;
@Override
public Result getSample() throws SampleDataException {
sampleJson.addFirst("username", username);
String body = sampleJson.getBody();
return Result.builder()
.output(new ByteArrayInputStream(body.getBytes()))
.mediaType(MediaType.APPLICATION_JSON)
.length(body.length())
.build();
}
@Override
public String getId() {
return "jsonResolver";
}
}
```
Imagine the value for the `username` parameter is `John Doe`. The provider returns the following
JSON:
```json5
{
username: "John Doe",
company: "Mulesoft",
email: "maxmule2007@mulesoft.com",
repositories: ["mule-api", "data-weave-2"],
}
```
### Obtain Sample Data Using Configuration Values and a Connection
Use this example to provide dynamic sample data according to parameter and configuration values,
while also requiring a connection.
Imagine there is a new GitHub connector that contains both an operation and source that:
- Have an **objectType** parameter that controls the type of entity retrieved, with possible values
such as `pullRequest`, `issue`, or `commit`
- Have an optional **status** parameter that filters the results
- Use a connection for the GitHub API
- Return a Result object
The following example illustrates the operation definition:
```java
@SampleData(ObjectSampleDataProvider.class)
public Result getObject(String objectType, @Optional String status, String anotherParameter, @Connection GitHubConnection connection, @Config GitHubConfig config) {
// operation code...
}
```
The following example illustrates the source definition:
```java
@SampleData(ObjectSampleDataProvider.class)
public class OnNewThingTrigger extends Source {
@Parameter
private String objectType;
@Parameter
@Optional
private String status;
@Parameter
private String extraParameter;
@Config
private GitHubConfig config;
@Connection
private ConnectionProvider connection;
// source code...
}
```
The following example illustrates the SampleDataProvider implementation that serves both cases. It
uses the **objectType** and **status** parameters, as well as connection and configuration:
```java
public class ObjectSampleDataProvider implements SampleDataProvider {
@Parameter
private String objectType;
@Parameter
@Optional
private String status;
@Connection
private GitHubConnection connection;
@Config
private GitHubConfig config;
@Override
public Result getSample() throws SampleDataException {
String query = "objectType=" + objectType;
if (status != null) {
query += "; status=" + status;
}
query += ";organization=" + config.getOrganization();
List jsonDocs = connection.query(query);
if (jsonDocs.isEmpty()) {
throw new SampleDataException("No data available", NO_DATA_AVAILABLE);
}
GitHubObject sample = jsonDocs.get(0);
String body = sample.getBody();
return Result.builder()
.output(new ByteArrayInputStream(body.getBytes()))
.mediaType(MediaType.APPLICATION_JSON)
.length(body.length())
.attributes(sample.getMetadata())
.attributesMediaType(MediaType.APPLICATION_JAVA)
.build();
}
@Override
public String getId() {
return "objectResolver";
}
}
```
Both components have the same type signature as the sample data provider. They define the same
parameters required by the resolver, but each has its own parameters that are not required by the
resolver. The resolver accesses the parameters, connection, and configuration the same way a value
provider does.
If no data is available, the resolver throws a `SampleDataException` error with a defined failure
code.
## OAuth Token Refresh
If your operation or source uses an OAuth connection, trigger a token refresh in the provider by
throwing an `AccessTokenExpiredException` error inside the getSample() method, as done for
[operations or sources](https://docs.mulesoft.com/mule-sdk/latest/oauth-token-expiration).
The following example illustrates a token refresh:
```java
public class RefreshedOAuthSampleDataProvider implements SampleDataProvider {
public static final String SAMPLE_PAYLOAD_VALUE = "Sample payload!";
public static final String SAMPLE_ATTRIBUTES_VALUE = "Sample Attributes!";
@Connection
private TestOAuthConnection testOAuthConnection;
@Override
public String getId() {
return "OAuth sample data";
}
@Override
public Result getSample() throws SampleDataException {
if (!testOAuthConnection.getState().getAccessToken().contains("refresh")) {
throw new AccessTokenExpiredException();
}
return builder()
.output(SAMPLE_PAYLOAD_VALUE)
.attributes(SAMPLE_ATTRIBUTES_VALUE)
.build();
}
}
```
## Aliases and Acting Parameters
You can resolve parameters in the same way you resolve value providers. You can define aliases
similar to defining an acting parameter as part of a parameter.
## Error Conditions
During compilation, a series of validations check that the sample data provider complies with some
of the restrictions described previously:
- Output and Attributes Type Check
The SDK validates that the provider is applied over components whose output and attributes types
match the ones declared on its generic tuple. A validation error is thrown otherwise.
- Parameters Usage Check
The SDK validates that if a sample data provider uses a parameter, the related component also
declares it as a parameter, while also checking that in both declarations the parameters are of the
same type. A validation error is thrown otherwise.
- Connection and Configuration Usage Check
The SDK validates that if a sample data provider uses a connection or configuration, the related
component also uses them. A validation error is thrown otherwise.
- Instantiation Check
The SDK validates that each provider is instantiable, which is a required condition. A validation
error is thrown otherwise.
- No Void
A sample data provider cannot be placed on a void operation. A validation error is thrown otherwise.
- Streaming
Although streaming is not supported, this is not enforced. Your extension developer should follow
best practices and comply with the contract.
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, forward compatibility, minMuleVersion, versioning
---
# SDK Forward Compatibility
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
In traditional SDK development, each SDK version is strictly tied to a specific Mule runtime
version. Using any new SDK feature requires bumping the SDK version, which automatically increases
your module’s minimum Mule version (`minMuleVersion`). This forces application developers to upgrade
their entire Mule runtime engine just to use a newer version of your module.
Starting with Mule 4.11.0 and using the new `mule-java-extension-parent`, the SDK introduces forward
compatibility, which decouples the SDK version you compile against from the minimum Mule version
your module requires. This enables your module to offer new features for later runtimes while
continuing to support earlier runtimes with existing functionality.
## How Forward Compatibility Works
Forward compatibility relies on a new artifact: `org.mule.sdk:mule-sdk-api`. This artifact can be
bundled as a dependency of your module, unlike the traditional
`org.mule.runtime:mule-extensions-api` and `org.mule.runtime:mule-api`. The new artifact contains
all SDK annotations, interfaces, and classes, each annotated with the minimum Mule version it
requires.
When you build your module, the SDK tooling analyzes which APIs each component uses and calculates
the minimum Mule version for each operation, source, and configuration. This information is stored
in the Extension Model, making it available to design-time tools like Anypoint Studio and Anypoint
Code Builder. These tools can then filter components or display warnings based on the application’s
target Mule version.
## Benefits of Implementing Forward Compatibility
Forward compatibility provides the following advantages:
- Flexibility
Introduce new features leveraging newer runtime capabilities while maintaining existing
functionality on older runtimes. Application developers who don’t need the new features can
continue using your module on their current runtime, while those who want them can target a newer
runtime.
- Simplified maintenance
No need to maintain separate module versions for different runtimes—a single release serves all
supported Mule versions.
## Getting Started With Forward Compatibility
You can enable forward compatibility when creating a new module or by upgrading an existing one.
### Create a New Module With the Maven Archetype
To create a new module with forward compatibility enabled, use the Maven archetype:
mvn org.mule.extensions:mule-extensions-archetype-maven-plugin:generate
When prompted, select a parent POM version of 1.11.x or later. The generated project will be
configured for forward compatibility.
### Upgrade an Existing Module
To enable forward compatibility in an existing module, change the parent POM in your `pom.xml` to
use `mule-java-extension-parent` version 1.11.0 or later. See
[Upgrading Existing Modules](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-setup#upgrading-existing-modules) for detailed
instructions and considerations.
## Next Steps
- See [Setting Up Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-setup) for instructions to configure
your project for forward compatible development.
- See [Working with Minimum Mule Versions](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-min-mule-version) to understand how
minimum versions are determined and controlled.
- See [Forward Compatibility Patterns](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-patterns) to learn common patterns for
writing forward compatible code.
## See Also
- [Choosing the SDK Version](https://docs.mulesoft.com/mule-sdk/latest/choosing-version)
- [Module Structure](https://docs.mulesoft.com/mule-sdk/latest/module-structure)
---
product: Mule SDK
version: 1.13
is-latest-version: true
---
# Security
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The module **must** follow all standard security best practices.
In particular, the following **should** be given special consideration:
- Protect against XXE attacks
- Always sanitize information from untrusted sources
- When reading files from the local file system, make sure not to access secrets of the host
environment nor enable path traversal
- When possible, use CSRF tokens
- When executing queries to a database, make correct use of PreparedStatement class to avoid SQL
injection attacks.
## See Also
- [Salesforce Help](https://help.salesforce.com)
- [Mule SDK Development Best Practices](https://docs.mulesoft.com/mule-sdk/latest/best-practices)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, security, tls, oauth
---
# Security
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
The service to which the connector you are creating will connect probably enforces some kind of
security for apps to talk to on behalf of a user.
The SDK provides different two ways for end users of your connector to secure their connections.
- [Adding TLS](https://docs.mulesoft.com/mule-sdk/latest/tls)
- [Adding OAuth Authentication](https://docs.mulesoft.com/mule-sdk/latest/oauth)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, sources, listener, triggers, response, output, asynchronous
---
# Sending Asynchronous Responses from a Message Source
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Sources can send responses in an asynchronous way. Some of the main uses cases for asynchronous
sources are:
- The response operation is non-blocking.
- The response operation is blocking, but it is asynchronously executed in a thread other than the
one that initiates it (most typically, the thread executing a method annotated with `OnSuccess` or
`OnError`).
- The source will perform asynchronous auditing for which it needs to consume a response stream in a
separate thread.
In these cases:
- The runtime needs to know that the response will be asynchronous. Otherwise, there will be a race
condition between the thread emitting the response and the runtime that is trying to free up
resources associated with the message that is getting a response.
- Methods annotated with `OnSuccess` or `OnError` must have an argument of type
`SourceCompletionCallback`. That is enough to signal the runtime that the source is asynchronous.
The runtime will not finish the associated event until either the `success()` or `error(Throwable)`
methods are invoked. Note that this is a very strong contract. A source that requests a
`SourceCompletionCallback` without properly notifying the runtime is one likely to freeze the entire
runtime eventually.
Here is an example:
```java
@OnSuccess
public void onSuccess(@Content String response, SourceCompletionCallback callback) {
asyncResponder.sendResponse(response, new ResponderCallback() {
void onSuccess() {
callback.success();
}
void onFailure(Throwable t) {
callback.error(t);
}
};)
}
```
## Next Step
[Transactional Message Sources](https://docs.mulesoft.com/mule-sdk/latest/sources-transactions)
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, forward compatibility, setup, mule-sdk-api, parent pom
---
# Setting Up Forward Compatibility
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
Configure your module project for forward compatibility by updating the parent POM and using the new
SDK API artifact.
## Configure the Parent POM
To enable forward compatibility, your module must use the new `mule-java-extension-parent`:
```xml
org.mule.extensions
mule-java-extension-parent
1.11.0
```
This parent POM includes the `mule-sdk-api` artifact and configures the build tooling for forward
compatibility.
## Upgrade Existing Modules
> [!IMPORTANT] All forward compatible APIs in `org.mule.sdk.api` require Mule 4.5.0 or later. Before
> upgrading, consider whether having 4.5.0 as your module’s Minimum Mule Version is acceptable. If
> your module must support runtimes older than 4.5.0, you can’t use forward compatibility.
To upgrade an existing module, change the parent POM in your `pom.xml` to use
`mule-java-extension-parent` version 1.11.0 or later.
The new parent POM removes provided-scope dependencies on `org.mule.runtime` modules. Possible
issues appear as compilation errors, resolve them by replacing `org.mule.runtime` imports with their
`org.mule.sdk.api` counterparts.
## Include the SDK API Artifact in Your Module
The `org.mule.sdk:mule-sdk-api` artifact provides a new package namespace: `org.mule.sdk.api`. This
package contains all the SDK annotations, interfaces, and classes needed for module development.
The key difference from traditional `org.mule.runtime` artifacts is that `mule-sdk-api` can be
bundled with your module. This enables your module to compile against newer SDK features while still
supporting older Mule Runtime versions.
When writing new code or migrating existing code, use APIs from the `org.mule.sdk.api` package. For
example:
- `org.mule.sdk.api.annotation.param.Parameter`
- `org.mule.sdk.api.runtime.streaming.StreamingHelper`
- `org.mule.sdk.api.metadata.MetadataContext`
## Configure the Minimum Mule Version
Unlike previous SDK versions, the parent POM version and the `mule-sdk-api` version don’t directly
determine your module’s minimum Mule version. Instead, the minimum Mule version is calculated per
component based on the APIs it uses.
### Baseline Minimum Mule Version
When creating a new module with the archetype, the `min.mule.version` property is added to your POM
with `4.11.0` as the default:
```xml
4.11.0
```
See [Working with Minimum Mule Versions](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-min-mule-version) for details on how
versions are calculated.
## See Also
- [SDK Forward Compatibility](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility)
- [Working with Minimum Mule Versions](https://docs.mulesoft.com/mule-sdk/latest/forward-compatibility-min-mule-version)
- [Getting Started with the Mule SDK for Java](https://docs.mulesoft.com/mule-sdk/latest/getting-started)
- [HTTP-Based Connectors](https://docs.mulesoft.com/mule-sdk/latest/http-based-connectors) for the forward-compatible `org.mule.sdk.api.http`
client API
---
product: Mule SDK
version: 1.13
is-latest-version: true
keywords: mule, sdk, operation, source, MIME, MIME Type, Encoding, Typed Value, Parameter Resolver, literal
---
# Special Parameters
> For the full documentation index, see: https://docs.mulesoft.com/llms.txt
## TypedValue
A common use case for [Operations](https://docs.mulesoft.com/mule-sdk/latest/operations) and [Sources](https://docs.mulesoft.com/mule-sdk/latest/sources) is to receive Media Type
information along with the value of the parameter, for example:
Example: Operation
```java
public void receiveContent(InputStream content) {
// operation logic
}
```
In the Mule app example below, you can see that you are receiving a `JSON` value, but the
operation’s code above does not indicate the MIME Type or encoding of the `content` parameter.
Example: Mule app
```xml
```
To retrieve Media Type information (MIME Type and encoding), you simply need to wrap the parameter
type into a `TypedValue`.
This example use the same Mule app above with the `TypedValue` parameter:
Media-Type-Friendly Parameter
```java
public void receiveContent(TypedValue content) {
DataType dataType = content.getDataType();
MediaType mediaType = dataType.getMediaType();
boolean streamType = dataType.isStreamType();
Long length = content.getLength().orElse(-1L);
InputStream theContent = content.value(); // The proper value
System.out.println(mediaType); // application/json; UTF-8
System.out.println(streamType); // true
System.out.println(length); // 18
}
```
Use of `TypedValue` parameters is highly recommended for use cases where the `MIME Type` information
is required to communicate with other systems that rely on this or to be able how to handle the
parameter value.
## Literal
`Literal` parameters allow you to get values as they were written in the Mule app. This means
that if the end user writes an expression such as `#[attributes.queryParams]`, the operation will
able to retrieve a `String` with the expression `#[attributes.queryParams]`. This prevents Mule
runtime from resolving expressions or applying any transformations. This is useful when the
evaluation needs to be performed by a third party.
In the case of configurations and connection providers, using literal parameters
[allows the configuration to be treated as a static one, instead of a dynamic one](https://docs.mulesoft.com/mule-sdk/latest/static-dynamic-configs).
This is because the literal value is constant even if that literal is an expression. The runtime
will not evaluate it automatically, so it is treated a static value by the extension.
If the value was provided as an expression, the class will provide the expression but offer no way
to evaluate it. You need to use [parameter resolvers](#parameter-resolver) for that.
```xml
```
Literal Parameter
```java
public void literalValue(Literal literal) {
System.out.println(literal.getLiteralValue().get()); // #[payload]
System.out.println(literal.getType()); // java.io.InputStream
}
```
> [!IMPORTANT] You need to consider the generic type. A parameter derived from uses of this
> interface will have its type set according to the generic type. The generic is not optional.
## ParameterResolver
`ParameterResolver` allows you to defer the resolution of an expression on an operation. This
is useful when a parameter that takes an expression as a value is not required. You can improve
performance by resolving such an expression on demand from within the connectors’s code instead of
resolving it automatically.
Compared to [`Literal`](#literal) parameters, a `ParameterResolver` parameter with an
expression continues to be treated as a dynamic parameter whether the value is resolved or not.
> [!NOTE] You cannot use `ParameterResolver` inside of configurations or connection providers.
### Resolving Expressions
When a `ParameterResolver` is received to resolve the expression value, the `resolve()` method
must be called to return the result of the expression.
> [!WARNING]
>
> - Expression resolution is deferred until it is required, so `resolve()` can fail due to an
> invalid expression.
>
> - Parameter resolvers are allowed only in operations. As such, you cannot use parameter resolvers
> in configurations.
### Getting the Expression Value
`ParameterResolver` parameters can communicate the expression used for the parameter. It
returns an `Optional` because the parameter can be configured with an expression or not. If
it is not configured with an expression, `Optional.empty()` will be returned.
#### Example: With Expression
Configured With an Expression
```xml