Extending Mule with DevKit – the LDAPConnector
Join the DZone community and get the full member experience.
Join For FreeMule’s extension capabilities multiply its power as an integration platform and range from simple expressions to custom cloud connectors: wherever a configuration value is expected, expressions can be applied in various languages, including our new Mule Expression Language, so that the same value is calculated at run-time; our Scripting processors allow you to execute custom logic in Groovy, Python, Ruby, JavaScript, PHP and indeed any language which implements the JSR-223 scripting spec for the JVM; and of course Java components can be invoked too. Our extensible platform goes even further with the addition of custom Cloud Connectors with already over a hundred to choose from. These greatly simplify any interaction with a public API whether it be exposed on the cloud or on-premise. They come with connection-pooling and automated reconnection strategies.
To make the development of new Connectors extremely easy, MuleSoft provides you with the DevKit which guided by just a few annotations, will compile a Java POJO into a Connector by way of a Maven build. With this blog, we wish to give you a deep overview of the essentials of the DevKit.
Use Case
We’ll show you the main ingredients needed in the development of a new Connector by walking you through the code of our LDAP Connector. This will allow you to connect to any LDAP server and perform every LDAP operation:
- bind: Authenticate against the LDAP server. This occurs automatically before each operation but can also be performed on request
- search: Perform a LDAP search in a base DN with a given filter
- lookup: Retrieve a unique LDAP entry
- add: Creates a new LDAP entry
- add attribute/s: Add specific attributes to an existing LDAP entry
- modify: Update an existing LDAP entry
- modify attribute/s: Update specific attributes of an existing LDAP entry
- delete: Delete an existing LDAP entry
- delete attribute/s: Delete specific attributes of an existing LDAP entry
Annotations
There are just a handful of fundamental Annotations to take note of:
- @Connector, to mark a class as a Connector
- @Configurable, to involve a field in configuration
- @Connect, to establish connection to the Service
- @Processor, to mark a method as an operation
- @Disconnect, invoked when as part of the maintenance of the Connection Pool
- @ValidateConnection, invoked before the invocation of an operation
Each of these must be present in order for DevKit to compile your POJO into a fully-fledged Connector which can be made available over an Eclipse update-site for inclusion in the Studio pallette and thus re-usable across multiple projects. Each of them in turn can be helped by some auxilliary Annotations which we will discuss along the way. LDAPConnector also makes use of the following:
- @ConnectionIdentifier, invoked for logging purposes
- @Transformer, which marks a method as a Transformer of data-types / data formats in the context of the Connector
Let’s look at each of these in detail.
@Connector
- name: The name of the connector. This is a simple string value which should not contain any spaces in it, it will be used to generate the namespace of the connector.
- schemaVersion: The version of the generated schema. This usually should match Mule’s schema version, so for Mule 3.3.1 use schemaVersion=”3.3.1″. Keep in mind that if you add or change methods marked as @Processors or add @Configurable fields the generated schema will change and you should bump the version to avoid compatibility issues.
- friendlyName: This is the name of the connector and is meant to be used only in Studio. This name will appear as the module name in the palette. Contrary to the name parameter, this field can contain spaces.
- minMuleVersion: The minimum version of Mule that this connector supports. A check will be generated for runtime verification that the Mule version this connector is running on is the correct one.
@Connector(name = "ldap", schemaVersion = "3.3", friendlyName="LDAP", minMuleVersion="3.2.0", description="LDAP Connector that allows you to connect to any LDAP server and perform every LDAP operation")
@Configurable
This field-level annotation marks a field on your POJO as a configurable field which can appear in the xml-schema in your Mule Configuration as an attribute on the <config/> element. In Studio it will appear as an item in the visual dialog. You can mark the same field as @Optional and supply a @Default value when the user doesn’t supply a value. The @FriendlyName and @Placement Annotations can also help Studio decide how to label the field and where to group the same in the configuration dialog./** * The connection URL to the LDAP server with the following syntax: ldap[s]://hostname:port/base_dn. */ @Configurable @Placement(group = "Connection", order = 0) @FriendlyName("URL") private String url;
@Connect
This annotation, in collaboration with the @Configurable annotation, provides an extremely powerful mechanism to configure the Connector. It marks a method for invocation at server startup and effectively creates a pool of Connections using the username and password parameters to connect to the provider service.
The @ConnectionKey annotated parameter is used as the key to the pool. Thus, the Connector can be invoked using a number of different credentials. In this case the dn is the connection key and can be decided at runtime. The instance of the Connector which corresponds to the key will be retrieved from the pool when an operation on the Connector is invoked. The @Optional and @FriendlyName annotations described above can also be used to add further semantics to the parameters.
The parameters you need to pass to the @Connect annotated method are obviously those which are relevant to the establishment of a new connection, as in this case we use the dn, the password and a value to represent that an anonymous bind to the LDAP server is requested (DevKit doesn’t support null values passed to the @Connect method).
An alternative to the @Connect annotation is worth a mention here. If you don’t want to exploit the connection pool facility you can use the @Start annotation instead. This will mean you can have a single instance per configuration. If you need to use more than one instance of your Connector, then you should manually configure the extra instances in the Mule Configuration.@Connect public void connect(@ConnectionKey @FriendlyName("Principal DN") String authDn, @Optional @FriendlyName("Password") String authPassword, @Optional String authentication) throws ConnectionException {
@Disconnect
This method is invoked as part of the maintenance of the Connection
Pool. The pool is configured with a max idle time value. When a
connection lies in the pool without use for more than the configured
time, then the method annotated with @Disconnect is invoked and
subsequently the @Connect method. Also, when the @InvalidateConnectionOn
annotation is used on a method to catch Exceptions, then the
@Disconnect method will likewise be invoked with the subsequent
reconnect.
@Disconnect public void disconnect() throws LDAPException { ...
@ValidateConnection
Prior to each invocation of the operations exposed by the @Processor annotation, the method annotated by @ValidateConnection will be invoked.@ValidateConnection public boolean isConnected() throws LDAPException {
@ConnectionIdentifier
This is used purely for logging purposes.
@ConnectionIdentifier public String connectionId() {
@Processor
This annotation marks a method to expose it as an operation on your Connector. Any parameters it accepts will be exposed as attributes in the generated schema. Studio will also provide inputs for each of these in the configuration dialog. The LDAP operations highlighted above have each been implemented by @Processor annotated methods in the LDAPConnector class.@Processor public void addFromMap(@Optional @FriendlyName("DN") String dn, @Optional @Default("#[payload:]") Map<String, Object> entry) throws Exception { ...
@Transformer
This annotation marks a method as a Transformer of data-types / data formats in the context of the Connector
@Transformer(sourceTypes = {LDAPEntry.class}) public static String ldapEntryToLdif(LDAPEntry entry) { ...
Documentation
It´s true to say that every experienced engineer knows that he or she ought to document the code. It´s also true that we are rather lazy in producing this essential part of our engineering product! True to Mule´s glorious goal of making integration easy, DevKit doesn´t stop at making the development of new Connectors easy, but does the same for their documentation, by way of a simple set of tags (the presence of which is obligatory by default!) and produces an elegant tab-based web-site complete with Installation Guide, JavaDocs and example code.
There are several parts to the documentation:
Module Overview Section
This is produced by the JavaDocs before the Class definition upto the first </p> paragraph ending and produces links for each operation as we have listed them under Use Case above.
Summary Section
Takes the first sentence of the JavaDocs for each @Processor and
@Transformer and the @Connect annotated methods in the Connector.
Configuration Section
Creates standard content describing the connection pool configuration followed by each {@sample.config } reference before the Class definition.
Connection Pool Section
Creates standard content describing the connection pool configuration followed by the JavaDocs for the @Connect annotated method.
Reconnection Strategies Section
Creates standard content describing the criteria governing decisions made when connections fail.
Message Processors Section
Lists each @Processor annotated method together with the JavaDocs for that method and the {@sample.config } reference listed there.
Sample.config
We should focus a little on this powerful tag which is embedded inside the JavaDocs for the class and methods. The search() method, for example uses the {@sample.xml ../../../doc/mule-module-ldap.xml.sample ldap:search-1} to reference the example configuration in mule-module-ldap.xml.sample underneath the doc/ directory. This file should contain all of the samples which will be surfaced by DevKit in the generated web-site.
Importing Connector into Studio
DevKit needs your connector to be part of a Maven project. You can create one for it like so:
mvn archetype:generate -DarchetypeGroupId=org.mule.tools.devkit -DarchetypeArtifactId=mule-devkit-archetype-generic -DarchetypeVersion=3.0.1 -DarchetypeRepository=http://repository.mulesoft.org/releases/ -DgroupId=org.mule.module.ldap -DartifactId=ldap-connector -Dversion=1.0 -DmuleVersion=3.3.1 -DmuleModuleName=LDAPConnector
It generates an Eclipse update site as part of its Maven build. All you need do is go to Help > Install New Software
Thus, our new LDAPConnector is ready for action in Studio
Example Configuration
So, how does our new LDAPConnector look in action? Well, take a look at the following config which exposes our Connector over http passing in the value of the cn attribute taken from the url. The flow will return an LDIF of the search results:
<ldap:config name="Ldap" authDn="${ldap.userDn}" authPassword="${ldap.password}" authentication="simple" url="${ldap.url}" doc:name="LDAP" /> <flow name="search" doc:name="search"> <http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="ldapSearch" doc:name="HTTP" /> <ldap:search config-ref="Ldap" doc:name="search" baseDn="ou=People,dc=muleforge,dc=org" filter="(objectclass=person)" scope="SUB_TREE" pageSize="500" maxResults="200"> <ldap:attributes> <ldap:attribute>#[message.inboundProperties['http.query.params'].cn]</ldap:attribute> </ldap:attributes> </ldap:search> <collection-splitter doc:name="Split Result Set"/> <ldap:ldap-entry-to-ldif doc:name="to LDIF"/> <collection-aggregator failOnTimeout="true" doc:name="Aggregate entries"/> <object-to-string-transformer doc:name="Object to String"/> </flow>
And there’s more…
We haven’t covered all of the annotations which you can use to enhance the power of your Connector. We’ll cover those in another post!
Published at DZone with permission of Nial Darbey, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments