Saturday, March 10, 2012

wsadmin: build a parameter string from list with the help of functional programming


Task at hand
    I would like to 'safely' build a string of key-value pairs list of the form below 
'[-key1 value1 -key2 value2 ... -keyN valueN]'

    Several wsadmin AdminTask methods such as createSSLConfig() or createWMQActivationSpec() allow us to use either a string of key value pair list in the form above or a list of hyphen-preceded key-value pair strings in the form below.
['-key1','value1','-key2','value2', ..., '-keyN','valueN']
    Problem is ... both forms of parameter list are prone to error. Sometimes, you forgot to prefix a minus(-) sign in front of a certain key. keyN then becomes part of valueN-1. Worse, you may not know it unless the server does not behave as you intend.

    Wouldn't it be better if we take advantage of python language list and use a bracket a placeholder of each key value pair. This will allow python interpreter to verify if we miss a closing bracket. I also would like to automatically add a minus-sign to each key. We no longer forget to prefix a minus(-) sign simply because we don't need it at all.
    In short, I prefer this kind of input ...
[['key1', 'value1'], ['key2', 'value2'], ..., ['keyN','valueN']]

    It may look longer but it is easier to your eyes and we can have python interpreter check the validity of the list.
    That is it. I would like to convert a list of list of key-value strings to a string which AdminTask accepts.

Introduction to functional programming in python

In python, function is the first class citizen. You could pass a function as a parameter just like any other valid types.

In python, there are a few built-in functions that also take function as one of the input. Notable ones are map(function, list, ...), filter(function, list) and reduce(function, sequence[, initializer]).

Map applies a function to each element of the list. It returns a list of mapped elements.
Filter shortens the list by only allowing elements whose application of the given function returns true.
Both map and filter functions return a list.
Reduce function on the other hand collapses the list by applying the function to the first pair of list elements. The return value of the function then becomes the first element of the list until we reach the end of the list.
For example, we can define a factorial function like this
def fac(n):
    return reduce(lambda x,y: x*y, range(1,n+1))
 Please also note an anonymous function using a notion of lambda keyword which returns a multiplication of x and y.


How I do it?
    My plan is a two-steps process.
Step 1: Convert a list of list ...
[['key1', 'value1'], ['key2', 'value2'], ..., ['keyN','valueN']]
to a list of string
['-key1 value1', '-key2 value2', ..., '-keyN valueN'] 
We use a map function to map each list element to a string of concatenated key pair and prefix each with a minus sign.
list2 = map(lambda x: '-' + ' '.join(x), list)
Step 2: Collapse the list of string by concatenating each of them and wrap it with a bracket sign.
result = '[' + reduce(lambda x,y: x + ' ' + y, list2) + ']'
So here comes the two-lines function ...
def buildParamStringFromList(kvList):
    # precede a hyphen (-) to each element
    # each element will be converted from a list of element to string
    l = map(lambda x: '-' + ' '.join(x), kvList)
    # collapse the list and wrap it with the blacket
    return '[' + reduce(lambda x,y: x + ' ' + y, l) + ']'
References
    Andrew Simms: developerWorks article - Using the full potential of Jython to build compact and maintainable wsadmin scripts - http://www.ibm.com/developerworks/websphere/library/techarticles/0801_simms/0801_simms.html

No comments:

Post a Comment