Extending Butterfly Container Script With Functions
Jakob Jenkov |
Since it is possible to call any method, instance or static, in Butterfly Container Script, it is possible to extend Butterfly Container Script with simple functions. The methods defined as functions can be either static methods or instance methods.
Static Methods as Functions
The simplest way to add a function is to create a static method in a Java class that performs the logic for the function. Adding and using a static method as a custom function in BCS is done in three easy steps:
- Create a static method that performs the needed function.
- Define a factory which calls that method. Use the desired
function name as factory name.
- Call the factory from other factories.
The following functions are examples of static method functions:
Instance Methods as Functions
Sometimes you may need to create an instance of some class and call a method on that instance. This can still be wrapped in a custom function though. Adding and using an instance method as a function in BCS is done in 4 easy steps:
- Create the class with a method performing the needed function logic.
- Define an instance of this class as a singleton in your script.
- Define a factory that calls the singleton factory and calls the desired method.
Give this factory the desired function name.
- Call the function factory from other factories.
Function Examples
The following functions are examples of instance methods being defines as functions:
default()
Here is an example of a function that takes two input parameters. If the first parameter is not null it returns that parameter. Else it returns the second parameter. This function is used to provide a default value for some input parameter for some factory. Here is the static method:
package com.myapp.util; public class Util { public static Object default(Object p1, Object p2){ if(p1 != null) return p1; return p2; } }
Here is how you would use it in a script:
beanA = * com.myapp.SomeObject($0); beanB = * beanA(com.myapp.util.Util.default($0, "default value"));
The beanA factory creates a SomeObject instance and injects input parameter 0 into its constructor. The beanB factory will call the beanA factory with the parameter returned from the static default() method. If input parameter 0 passed to the beanB factory is null, then the default() method will return the default value "default value". It is then the default value that will be passed to the beanA factory and injected into the SomeObject constructor.
If you need to call the default() method more than once you can simplify the script a bit by mapping the default method to a factory, and then call this factory whenever the function is needed. Here is how that looks:
default = * com.myapp.util.Util.default($0, $1); beanA = * com.myapp.SomeObject($0); beanB = * beanA(default($0, "default value"));
The default() method has been mapped to a factory called "default". This default factory is then called from the beanB factory instead of calling the static default() method directly. The end result is the same, but the script is a bit easier to read and write. There is no package and class name to disturb you when reading the script, and whenever you need the default function all you need to write is "default(a, b)", instead of "com.myapp.util.Util.default(a, b)".
max()
This example shows a function that returns the maximum of two values. Defining the static max() method as a factory (and thereby a function) is done like this:
max = * java.lang.Math.max((int) $0, (int) $1);
This little script defines the "max" factory as a call to the static max() method with input parameter 0 and 1 passed to the max() method. Using the function inside the script is done like this:
max = * java.lang.Math.max((int) $0, (int) $1); beanA = * com.myapp.SomeObject(max($0, 1));
The beanA factory definition calls the max factory with its input parameter 0 and the value 1. The max factory will call the max() method and return the value that is largest of either the input parameter 0 passed to the beanA factory, or the hard coded value 1.
toDate()
This example uses the java.text.SimpleDateFormat class and defines its instance method parse() as a function called "toDate". First an instance of SimpleDateFormat is defined as a singleton in the script:
toDateTarget = 1 java.text.SimpleDateFormat("yyyy-MM-dd");
Second the toDate factory is defined as a call to the toDateFactory and then a call to the parse() method on the instance returned from the toDateFactory. The toDate factory takes a single parameter which is the string to parse into a java.util.Date instance.
toDateTarget = 1 java.text.SimpleDateFormat("yyyy-MM-dd"); toDate = * toDateTarget.parse($0);
Third you call the toDate factory from other factories like this:
toDateTarget = 1 java.text.SimpleDateFormat("yyyy-MM-dd"); toDate = * toDateTarget.parse($0); beanA = * com.myapp.SomeObject(toDate("2008-12-24"));
Tweet | |
Jakob Jenkov |