This post outlines one way of using F# in IBM Integration Bus (IIB). F# gives you another option for writing intuitive and maintainable code for message processing.
What is F# ?
F# is a .NET programming language, incorporating functional programming concepts similar to those found in languages such as Haskell. F# can allow a programmer to express their intentions more directly, resulting in maintainable and reliable code. You can use F# to create a .NET assembly that you invoke from a .NETCompute node or from ESQL.
What do I need?
– a Windows installation that includes Microsoft .NET Framework V4 or later
– IBM Integration Bus / WebSphere Message Broker V8 or later
– Microsoft Visual Studio 2010 (Express Edition or Professional Edition) or later
This is not an introduction to functional programming or to using .NET in IIB. These are explained really well elsewhere, for example in the following developerWorks articles:
F# message processing example
The IIB flow we’re going to create is simply:
Input(XMLNSC domain)¬†¬† -¬†¬† .NETCompute¬†¬† -¬†¬† Trace¬†¬† -¬†¬† Output
You can use any supported transport – for example, HTTPInput / HTTPReply for the input and output nodes. The Trace node is not essential, but just allows you to check the logical tree structure generated by your F# code.
For development and testing we can specify the location of our .NET assembly (dll) directly as a property on the .NETCompute node. This has the advantage that when we rebuild the Visual Studio project, the modified assembly is immediately picked up by the IIB flow. To gain more control in a production environment you can use a configurable service to specify the location of the assembly.
The flow takes an XML message containing a set of stock prices for a company, and adds a <summary> folder with various metrics calculated from the raw data.
Here is an example input message. Each <data> element is a comma delimited list giving the data, then the opening, highest, lowest and closing stock index:
<dataset> <data>30 Sep 2014, 189.
64,1 90.8 5,18 9.15 ,189 .83< /dat a> <data>29 Sep 2014, 188. 51,1 89.9 6,18 8.12 ,189 .64< /dat a> <data>26 Sep 2014, 188. 93,1 90.3 3,18 8.61 ,190 .06< /dat a> <data>25 Sep 2014, 192. 05,1 92.5 0,18 8.97 ,189 .01< /dat a> <data>24 Sep 2014, 191. 00,1 92.4 5,18 9.88 ,192 .31< /dat a> </dataset>
If you use aggregation in IIB, you could imagine receiving an aggregated message with multiple sets of data like this.
How should we handle the comma delimited data in each element? Complex delimited data formats are usually best handled by DFDL. In this case, however, the data is quite simple and we’ll ‘parse’ it in the F# code. First we need to create an F# project in Visual Studio.
Using Visual Studio
When IIB is installed on Windows, a number of broker-specific templates are made available to your Visual Studio installation.
To create your F# project, open a New Project.
Under Templates, select Visual F# and IBM Integration [or Message Broker], then select the template to Modify an IBM Integration [or Message Broker] message.
Open the source file created (e.g. ModifyNode.fs) and edit the Evaluate method to build the required output message.
The F# Code
Here is the outline F# code, showing the Evaluate method that will process the stock data and update the output message. The code is explained in the comments.
type ModifyNode() = inherit NBComputeNode() override this
.Eva luat e(in putA ssem bly) =
initialize the output message from the input message
¬†¬†¬†¬†¬† let outTerminal = this// create output message as copy of the input message use outputMessage = new NBMe
.Out putT ermi nal( "Out ") let inputMessage = inpu tAss embl y.Me ssag e ssag e(in putM essa ge) let outAssembly¬†¬† = new NBMe ssag eAss embl y(in putA ssem bly, outputMessage) let inputRoot¬†¬†¬†¬† = inpu tMes sage .Roo tEle ment let outputRoot¬†¬†¬† = outp utMe ssag e.Ro otEl emen t // locate the parent dataset element let ds = outp utRo ot.F indO rCre ate( "XML NSC" ).Fi ndOr Crea te(" data set" ) // get a list of all the <data> child elements let dataArray = ds.Children("data")
calculate some metrics from the raw data
// build a new list of the data element values - this is the raw stock data let dailyTradingData = [ for i in dataArray do yield (i.ValueAsString) ] // declare a helper function to split up the data into an array based on the comma delimiters let split(x:string) = x.Split([|','|]) // apply the split function to give us a list of String arrays // This illustrates the pipeline syntax |> that allows you to cleanly express functional composition, // as well as a simple example of using the extensive built-in list processing capabilities of F# let splitData = dailyTradingData |> List.map split // identify <data> entries with specific characteristics, for example the maximum gain in one day // This illustrates the use of 'anonymous' functions' (fun ...) instead of named helper methods like split let maxRise¬† = splitData |> List.maxBy (fun list -> (float list. - float list.)) let maxFall¬† = splitData |> List.maxBy (fun list -> (float list. - float list.)) let maxSwing = splitData |> List.maxBy (fun list -> abs(float list. - float list.)) // as a further example, filter the data to select entries where there was a gain (or a fall) // on that day. The length of the resulting list gives us the number of such days. For upDays // we use a named sub function declared in the scope of the expression itself. For downDays we // use an equivalent 'anonymous' style function. let upDays = let isUp(list: string ) = float list. > float list.¬†¬†¬†¬† // define "isUp" as a sub function splitData |> List.filter isUp |> List.length let downDays = splitData |> List.filter (fun list -> (float list. < float list.)) |> List.length
complete the output message and propagate it
// add summary information to the output logical tree let summary = ds.CoutT
reat eLas tChi ld(" summ ary" ) summ ary. Crea teLa stCh ild( 0x03 0000 00," maxR iseD ate" ,max Rise . ) summ ary. Crea teLa stCh ild( 0x03 0000 00," maxF allD ate" ,max Fall . ) summ ary. Crea teLa stCh ild( 0x03 0000 00," maxS wing Date ",ma xSwi ng.[ 0]) summ ary. Crea teLa stCh ild( 0x03 0000 00," upDa ys", upDa ys) summ ary. Crea teLa stCh ild( 0x03 0000 00," down Days ",do wnDa ys) ermi nal. Prop agat e(ou tAss embl y )
The output message will be a copy of the input message, with the addition of a new <summary> folder, incorporating the metrics explained in the code.
What sets this apart from other IIB transformation options is the way we can use the built-in F# support for lists and functional composition to process the data. Whether you find this code intuitive may depend on your programming background, but I hope you’d agree that it is concise and should be easy to maintain and modify.
I’ve discussed one way of using F# in IIB. I hope you’ve found this very brief introduction useful. It would be interesting to know if you have seen any real-world use of IIB yourself where this style of coding could be useful. Thanks for reading!