MidPoint 4.3 and later
This feature is experimental. It means that it is not intended for production use. The feature is not finished. It is not stable. The implementation may contain bugs, the configuration may change at any moment without any warning and it may not work at all. Use at your own risk. This feature is not covered by midPoint support. In case that you are interested in supporting development of this feature, please consider purchasing midPoint Platform subscription.
See Asynchronous (Messaging) Outbound Resources for an introduction to the topic.
The following text will be a combination of a documentation with a simple tutorial on how to configure an asynchronous resource.
Before configuring asynchronous resource, we need to have a target where it will send messages to. The target can be a messaging queue or topic, REST endpoint, or something like that. However, the support in midPoint is currently limited to Apache ActiveMQ Artemis queues and topics (speaking in JMS language). Therefore, before we start, we need to have Apache ActiveMQ Artemis 2.x installed and running. In our example we have chosen a default implementation on the local host, with enabling the security - using
secret as the credentials.
We will use
ProvisioningQueue queue as a mechanism for communication between midPoint and (fictitious) target system. So the queue should exist. This can be ensured by including the following into
broker.xml configuration file:
Please see ActiveMQ Artemis documentation for more information.
Objects in JMS (connection factories, queues, topics, and so on) are typically configured via JNDI. ActiveMQ does not have a full JNDI server. Its JMS client is configured using JNDI property files. Therefore we have to prepare one.
Let's create the following
The file has to be on the classpath. The easiest way is to wrap it into JAR file and place that file in
lib directory in midPoint home (for standalone deployments) or into Tomcat lib directory (for explicit Tomcat deployments; but these are deprecated since midPoint 4.2).
You have to run the script from the directory where
jndi.properties file is stored:
jar command is part of Java Development Kit.)
The resource object should then look like this:
Let us describe individual parts of the resource definition.
We have to tell the connector two things:
- Where it should send asynchronous operation requests to.
- How to constructs these requests.
As for the former, we use
targets element to specify one or more targets. (Yes, it is possible to specify more than one target. This is to ensure high availability or load balancing at the application level. But this feature is really highly experimental, and is there mainly as a placeholder for future implementation. Do not use it. Specify only a single target for now.)
Target types available:
|JMS 2.0 or 1.1 targets.||Tested with JMS 2.0.|
|Target communicating using Apache ActiveMQ Artemis Core protocol.||Not much tested. Experimental.|
|Custom implementation of target connection code.||Not much tested. Experimental.|
Configuration properties for JMS target:
|Connection factory name. It is looked up via JNDI.||localhostConnectionFactory|
|User name used to authenticate to JMS broker (if needed).||admin|
|Password used to authenticate to JMS broker (if needed).||secret|
|Destination (queue or topic) to send messages to. It is looked up via JNDI.||ProvisioningQueue|
Our sample configuration is the following:
We give the
localhostConnectionFactory value for the name of the connection factory to use. It is pointing to the following entry in
It says that midPoint will try to reach the broker using TCP protocol on the local host, at default port 61616.
When installing ActiveMQ, we chose
admin as the administrator's user name and
secret as the password. So we have to specify them in the configuration.
Finally, the queue we use to send messages to is
ProvisioningQueue. (The name is, of course, arbitrary. But it should exist on the broker, and the target system should read messages from it.)
ProvisioningQueue is JNDI name. ActiveMQ expects entry of the form
topic.NAME to exist in
jndi.properties file. That's why we have the following line there:
Please see ActiveMQ Artemis documentation for detailed information on using JNDI properties.
MidPoint represents operations that are to be executed on the target as internal Java objects of
OperationRequested class. In order to send them to the target, they have to be transformed into text or binary form. There are a couple of predefined transformations; or we can create our own.
The predefined ones are:
|Creates JSON representation of the ||This is the most comprehensive representation of the request, but requires rather sophisticated client to parse it. The usual way of reading this structure is to use |
|This is a variant of the above that omits current resource object shadow from the message (because it is usually not needed).||The messages are shorter than in |
|Creates simplified JSON representation of the request. The structure is described by the ||This is probably the best generic request serialization to start with. There is one limitation, though: because namespaces are not used, it is not possible to have more attributes with the same local name, but different namespace (like |
|Creates simplified JSON representation, but with qualified names of attributes and object class.||It is more complex than |
In our example we will use
MidPoint usually determines schema for resource objects (accounts, groups, and so on) by querying the resource. However, in this case it is not possible to do that, because the resource is not directly reachable.
So, in a way similar to manual resources, we have to define the schema ourselves. An example:
This means that accounts on the target resource have three properties:
This is a standard definition of how resource objects are created or interpreted. It is the same as for regular (connected) resources. In this particular case, it says that:
loginwill be set to the value of user's
fullNamewill be set to the value of user's full name;
descriptionwill be constructed as a string in the form
This is '$name' called '$fullName'e.g. "This is 'jack' called 'Jack Sparrow'".
In order for the resource to work correctly, it must do attribute caching. It is enabled by specifying the following capabilities:
Testing the configuration
Importing and testing the resource definition
After everything is in place (broker is running,
jndi-config.jar was created and put into
lib subdirectory in midPoint home directory, midPoint was started) we can import the resource definition.
After importing let us test it. The successful result looks like this:
And the log file should contain something like the following:
(Or an error description if the test is not successful.)
Creating a user and his account
Let us create a user with an account on the asynchronous resource.
If we give the user a name
jack, full name
Jack Sparrow and a resource assignment to our resource, and click on Save button, the user will be created in midPoint.
The user will have one account. The account can be displayed when opening the user.
Of course, midPoint does not know if the account was really created on the target resource. (In reality, it wasn't.) But it assumes so; and shows the values of the attributes as they should be.
Inspecting the message queue
Using Artemis console we can have a look at
ProvisioningQueue. There should be a single message with the following content:
This is a request to create an account with specified attributes (login, fullName, description).
Now we can play with the user, e.g. change his name or full name, unassigning the resource or even deleting the user. Corresponding requests should be placed into
ProvisioningQueue at the broker.
For example, after changing full name to
Jack SPARROW, the following message is produced:
We see that
description attributes are affected. The
login is unchanged, so it is not mentioned among the changes.
Some resources require that they receive full object state instead of relative changes. In the example above, the resource would require getting values of all three attributes:
description - not only changed ones.
This can be ensured by setting the following capability:
Then the changes will look like this (now changing full name back to Jack Sparrow):
Using custom transformation
It is possible to specify custom transformation expression. An example:
Because the (universal) construction of the JSON change requests is quite laborious, midPoint provides a helper
requestFormatter. It operates on the standard structure of "simplified JSON" (i.e.
JsonAsyncProvisioningRequest) but allows the script to configure formatting process by e.g. setting various formatting options as well as directly supplying parts of the resulting request.
In the above example we set
changeMapAsAttributes option that causes formatting REPLACE-style changes with a simple list of attribute values. It is to be used in connection with the absolute changes mode described above.
The resulting request message looks like this:
Note: For a description of individual items in this structure, please see
Custom transformation script can expect the following variables:
|The abstract operation that is being requested by midPoint.|
|Helper methods. Please see javadoc for the class.|
|Creates requests and optionally serializes them into JSON.|
Using Apache Velocity
When creating custom text messages, Apache Velocity can help a lot. An example:
This script expects single-valued attributes
description, and creates text messages like these:
The template works like this:
$request = $requestFormatter.changeMapAsAttributes().identifiersAsAttributes().createRequest()configures a formatter to represents both changes and identifiers as regular attributes, and then creates a request object (without serialization into JSON). So the
$requestvariable will contain a reference to
JsonAsyncProvisioningRequestwith attributes filled-in for all three kinds of operations (add, modify, delete).
$attrs = $request.attributesSimplifiedobtains a simplified version of the attributes to the variable
attrs. The simplification means that we get a map where single-valued attributes will not be represented as collection of values (as is the case of
request.attributes), but as simple values instead.
- Therefore, expressions like
$!attrs["login"]return single values of specified attributes – or null, if the given attribute has no value.
Please see Velocity User Guide for more information. (MidPoint currently uses Velocity 1.7.)