11 December 2010

Convert a List<String> to a List<DateMidnight>

Valid since: op4j 1.1

Description
Convert a List<String> where each string represents a date in the format MM/dd/yyyy to a List<DateMidnight>

Scenario
Our List<String> list variable contains strings in the format MM/dd/yyyy:

List<String> list = new ArrayList<String>();
list.add("12/24/2000");
list.add("02/02/2010");
list.add("04/04/2002");
list.add("11/22/2005");
list.add("02/07/2005");
list.add("03/05/2005");
list.add("09/13/2006");
list.add("12/29/2007");

We want to create a List<DateMidNight> with the strings in our list converted
to DateMidnight:

List<DateMidnight> result = new ArrayList<DateMidnight>();
result.add(new DateMidnight(2000, 12, 24));
result.add(new DateMidnight(2010, 2, 2));
result.add(new DateMidnight(2002, 4, 4));
result.add(new DateMidnight(2005, 11, 22));
result.add(new DateMidnight(2005, 2, 7));
result.add(new DateMidnight(2005, 3, 5));
result.add(new DateMidnight(2006, 9, 13));
result.add(new DateMidnight(2007, 12, 29));

Recipe
Steps:
1. Iterate the list and convert each string to DateMidnight.

op4j-jodatime functions involved:
  • FnDateMidnight.strToDateMidnight(pattern): it converts the input string to DateMidnight using the given pattern

Let's see it coded with op4j:

String pattern = "MM/dd/yyyy";
List<DateMidnight> datemidnights = Op.on(list).forEach()
.exec(FnDateMidnight.strToDateMidnight(pattern)).get();

05 December 2010

Create a map from a List with the valid and invalid percentages

Valid since: op4j 1.1

Description
Given a List, create a map with two keys: "VALID" with the strings valid as a percentage between 0 and 100 and "INVALID" with the not valid ones

Scenario
Our List<String> list variable contains some strings that, in some cases, represent valid percentages:

List<String> list = new ArrayList<String>();
list.add("5");
list.add("3.4");
list.add("-13");
list.add("0");
list.add("5k7");
list.add("ten");
list.add("32");
list.add("1,2");

Some of the strings in the list, do not represent valid percentages and we want to create a map with two keys: INVALID whose value will be a list with the invalid strings and VALID which will have a list with the valid ones as its value:

Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
result.put("VALID", Arrays.asList(new String[] {"5", "3.4", "0", "32", "1,2"}));
result.put("INVALID", Arrays.asList(new String[] {"-13", "5k7", "ten"}));

Recipe
Steps:
1. Create a map from the input list with two keys: VALID and INVALID. Depending on whether a string in the input list represents a valid percentage or not, put it into the list of VALID or INVALID values.

op4j funcions involved:
  • FnString.isInteger(decimalPoint): returns whether the input is valid as an integer or not based on the given decimal point. It does not check the string represents a non decimal number that fits in an Integer number but that FnString.toInteger can be executed correctly.

  • FnString.toInteger(decimalPoint): converts the input value into an integer based on the given decimal point.

  • FnNumber.between(min, max): returns wether the input number is between min and max or not

Let's see it coded with op4j:

Map<String, List<String>> validInvalidPercentages = Op.on(list).zipAndGroupKeysBy(
new IFunction<String, String>() {
public String execute(String input, ExecCtx ctx) throws Exception {
return Op.on(input).exec(FnString.isInteger(DecimalPoint.IS_POINT))
.get().booleanValue()
&& Op.on(input).exec(FnString.toInteger(DecimalPoint.IS_POINT))
.exec(FnNumber.between(0, 100)).get().booleanValue()
? "VALID" : "INVALID";
}
}).get();

Comments
We are supposing the valid decimal point is IS_POINT though, if it were COMMA, it would be the same but using DecimalPoint.COMMA instead

Create a map from a List and generate a List with the strings convertible to Integer

Valid since: op4j 1.1

Description
For a given List<String>, create a Map with two keys: "VALID" with the strings valid as integer and "INVALID" with the not valid ones. Convert the valid strings to integer.

Scenario
Our List<String> list variable contains some strings that, in some cases, represent integer numbers:

List<String> list = new ArrayList<String>();
list.add("5");
list.add("3.4");
list.add("89.7");
list.add("-13.999");
list.add("5f7");
list.add("537");
list.add("323a");
list.add("3,23");

Some of the strings in the list, do not represent valid integers and we want to create a map with two keys: INVALID whose value will be a list with the invalid strings and VALID which will have a list with the valid ones as its value:

Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
result.put("VALID", Arrays.asList(new String[] {"5", "3.4", "89.7", "-13.999", "537", "3,23"}));
result.put("INVALID", Arrays.asList(new String[] {"5f7", "323a"}));

The items in the VALID list, will be converted into integer...and that List<Integer> will be the output we want.

Recipe
Steps:
1. Create a map from the input list with two keys: VALID and INVALID. Depending on whether a string in the input list represents a valid integer or not, put it into the list of VALID or INVALID values.
2. Iterate the list of valid strings and convert them into integer numbers.

op4j funcions involved:
  • FnString.isInteger(decimalPoint): returns whether the input is valid as an integer or not based on the given decimal point. It does not check the string represents a non decimal number that fits in an Integer number but that FnString.toInteger can be executed correctly.

  • FnString.toInteger(decimalPoint): converts the input value into an integer based on the given decimal point.

Let's see it coded with op4j:

Map<String, List<String>> validInvalidIntegers = Op.on(list).zipAndGroupKeysBy(
new IFunction<String, String>() {
public String execute(String input, ExecCtx ctx) throws Exception {
return Op.on(input).exec(FnString.isInteger(DecimalPoint.IS_POINT))
.get().booleanValue()? "VALID" : "INVALID";
}
}).get();

List<Integer> asIntegerIfPoint = Op.on(result.get("VALID")).forEach()
.exec(FnString.toInteger(DecimalPoint.IS_POINT)).get();

Comments
We are supposing the valid decimal point is POINT though, if it were COMMA, it would be the same but using DecimalPoint.IS_COMMA instead

28 June 2010

Build a map of lists of calendar from a list of strings

Valid since: op4j 1.0

Description
Convert a List<String> to a List<Calendar>, filter the result by keeping only the elements belonging to the year 2010 and, finally, create a Map<Integer,List<Calendar>> with the month as key. Finally, what we get are the dates belonging to 2010 grouped by month.

Scenario
Our List<String> asString variable contains some strings representing dates:

asString == {"20100505", "20100614", "19980407",
"20100209", "20100215", "20110101",
"20100620", "20100301"}

Some of the dates represented by these strings do not belong to the year 2010 so, once they are converted to Calendar, we'll have to filter them in order to keep only the 2010 dates. With these filtered results we'll create the Map<Integer,List<Calendar>> result variable which will be:

Map<Integer, List<Calendar>> result ==
[{1, {20100209, 20100215}},
{2, {20100301}},
{4, {20100505}},
{5, {20100614, 20100620}}]

Recipe
Steps:
1. Iterate the list and, for each element, create the Calendar it represents (we assume all of the elements are convertible to Calendar, otherwise, we should filter them).
2. Filter the List<Calendar> by removing all the dates not between January, 1st and December, 31st.
3. Create a Map<Integer, List<Calendar>> with the 2010 dates using the date month as the key.

op4j funcions involved:
  • FnString.toCalendar(pattern): converts a String into a Calendar.

  • FnObject.lessThan(object): compares two comparable elements and returns true if the target is less than the object passed.

  • FnObject.greaterOrEqTo(object): compares two comparable elements and returns true if the target is greater or equal to the object passed.

  • Call.methodForInteger(method, parameters, ...): calls a method on the target element and returns the result of that call.

Let's see it coded with op4j:

Map<Integer, List<Calendar>> result = Op.on(asString).forEach()
.exec(FnString.toCalendar("yyyyMMdd")).endFor()
.removeAllTrue(FnObject
.lessThan(new DateTime(2010, 1, 1, 0, 0, 0, 0)
.toCalendar(Locale.getDefault())))
.removeAllTrue(FnObject
.greaterOrEqTo(new DateTime(2011, 1, 1, 0, 0, 0, 0)
.toCalendar(Locale.getDefault())))
.zipAndGroupKeysBy(Call
.methodForInteger("get", Calendar.MONTH)).get();

31 May 2010

Converting the keys in a map

Valid since: op4j 1.0

Description
Convert all the keys in a map without changing its corresponding values.

Scenario
Our Map<String,String> map variable contains some numbers (as keys) along with their names in English language (as values):
// map == MAP [ {"1", "one"}, {"2", "two"}, {"3", "three"} ]
...but notice that keys are Strings, not real Integer objects, and that is precisely what we want to obtain, a Map<Integer,String> newMap variable like:
// newMap == MAP [ {1, "one"}, {2, "two"}, {3, "three"} ]

Recipe
Using op4j, we can iterate on the map entries, select the keys of these entries to operate on, and then execute a function that will convert the entries from String to Integer:

Map<Integer,String> newMap = 
    Op.on(map).forEachEntry().onKey().exec(FnString.toInteger()).get();

Comments
The onKey() action has of course a value counterpart, onValue(), which you can use just like:
Map<String,String> newMap = 
    Op.on(map).forEachEntry().onValue().exec(FnString.toUpperCase()).get();

Checking if all the members of an array meet a specific condition

Valid since: op4j 1.0

Description
Check whether all the elements in an array meet a specific condition, obtaining a TRUE if they do, or a FALSE if they don't.

Scenario
Our Integer[] values variable contains some numbers:
// values == ARRAY [ 100, 23, 587 ]
...and we want to know whether all the numbers are less than 800 or not, obtaining a Boolean object representing the result.

Recipe
Just use operate on the array and use the all action, applying the conditional "lessThan" function:

Boolean result = 
    Op.on(values).all(FnInteger.lessThan(800)).get();

Comments
The all action is also available for lists and sets.

There is also an any action, which returns true if any of the elements meets the specified condition.

04 May 2010

Modifying some elements in a list (depending on a specific condition)

Valid since: op4j 1.0


Description
Given a list (or array, or set) with several elements, modify some of them by executing a function. The elements to be modified will be determined based on a condition.


Scenario
Our List<String> herbs variable contains some of the spices offered at our online shop, which are stored somewhere in our databases:
herbs == LIST [ "*parsley*", "BASIL", "*Coriander*", "Spearmint" ]
Some of the names are stored between asterisks, and that means that the product has been completely sold out. Also, case is not homogeneous, and some names are in upper case, some others in small case, etc.

We want to process that list so that the names are capitalised (first letter in upper-case) and that sold out products are marked with a text, like:
herbs == LIST [ "Parsley (sold out!)", "Basil", 
                "Coriander (sold out!)", "Spearmint" ]


Recipe
Lots of work to do here. Step by step:
  1. Iterate the list, and for each element...
    1. If the herb name matches a pattern indicating it is surrounded by asterisks:
      1. Extract the name (remove the asterisks).
      2. Add the " (sold out!)" suffix.
    2. Capitalise the herb name (will involve converting first to lower case).

op4j functions involved will be:
  • FnString.matches(regex): returns true if the target String matches the regular expression.
  • FnString.matchAndExtract(regex, group): Similar to matches(regex), but allows the extraction of one of the groups defined in the regular expression as a substring.
  • FnOgnl.evalForstring(expression): Executes an OGNL expression. This will be our chosen way to reshape the String.
  • FnFunc.chain(fn1, fn2): Chains the execution of two functions. Equivalent to exec(fn1).exec(fn2), but used here for the sake of example.
  • FnString.toLowerCase() and FnString.capitalize(): String-related functions for reshaping Strings.
And here it goes:
herbs = 
    Op.on(herbs).forEach().
        ifTrue(FnString.matches("\\*.*?\\*")).
            exec(FnString.matchAndExtract("\\*(.*?)\\*",1)).
            exec(FnOgnl.evalForString("#target + ' (sold out!)'")).
        endIf().exec(FnFunc.chain(FnString.toLowerCase(),FnString.capitalize())).get();
As usual, almost harder to explain than to really code.


Comments
We could have created an equivalent piece of code using the execIfTrue(condition, then) action:
herbs = 
    Op.on(herbs).forEach().
        execIfTrue(
            FnString.matches("\\*.*?\\*"),
            FnFunc.chain(
                FnString.matchAndExtract("\\*(.*?)\\*",1),
                FnOgnl.evalForString("#target + ' (sold out!)'"))).
        exec(FnFunc.chain(FnString.toLowerCase(),FnString.capitalize())).get();
...which would not be as pretty as the first option, but would allow us to specify an else function by using the execIfTrue(condition, then, else) variant:
herbs = 
    Op.on(herbs).forEach().
        execIfTrue(
            FnString.matches("\\*.*?\\*"),
            FnFunc.chain(
                FnString.matchAndExtract("\\*(.*?)\\*",1),
                FnOgnl.evalForString("#target + ' (sold out!)'")),
            FnOgnl.evalForString("#target + ' (on sale)'")).
        exec(FnFunc.chain(FnString.toLowerCase(),FnString.capitalize())).get();
And finally, being this a quite complex process.. why don't we create a function we can carry around and use when we please, instead of the operation expression we just defined?:
Function<List<String>,List<String>> processHerbNames = 
    Fn.onListOf(Types.STRING).forEach().
        execIfTrue(
            FnString.matches("\\*.*?\\*"),
                FnFunc.chain(
                FnString.matchAndExtract("\\*(.*?)\\*",1),
                FnOgnl.evalForString("#target + ' (sold out!)'")),
            FnOgnl.evalForString("#target + ' (on sale)'")).
        exec(FnFunc.chain(FnString.toLowerCase(),FnString.capitalize())).get();
...
// Just execute it whenever you want!
herbs = processHerbNames.execute(herbs);

22 April 2010

Building a map from a list by executing functions on its elements

Valid since: op4j 1.0

Description
Build a map by iterating the elements of a list and executing two functions on each of them: one for obtaining the key of the corresponding entry, and another one for obtaining the value.

Scenario
Our Country class looks like this:
public class Country {
    private final String name;
    private final Integer population;
    ...
    public String getName() {
        return this.name;
    }
    public Integer getPopulation() {
        return this.population;
    }
}
And we have a List<Country> countries variable containing data about some countries:
// countries == LIST [
//                     COUNTRY [ "Spain"; 45989016 ],
//                     COUNTRY [ "France"; 65447374 ],
//                     COUNTRY [ "Portugal"; 10707924 ],
//                     COUNTRY [ "United Kingdom"; 62041708 ],
//                     COUNTRY [ "Ireland"; 4459300 ],
//                   ]
...which we want to transform into a Map<String,Integer> containing the population of each country, indexed by the country name:
// populationByCountry == MAP [
//                              {"Spain": 45989016},
//                              {"France": 65447374},
//                              {"Portugal": 10707924},
//                              {"United Kingdom": 62041708},
//                              {"Ireland": 4459300},
//                            ]

Recipe
The toMap(keyFunction, valueFunction) action, applied on the list, will let us specify two functions: one for obtaining map keys out of the original list elements, and another one for obtaining their corresponding values. We will use getters for both:

Map<String,Integer> populationByCountry =
    Op.on(countries).
        toMap(Get.attrOfString("name"), Get.attrOfInteger("population")).get();

Comments
And what if we wanted the result map to be ordered by population, from the highest to the lowest figure? Something like:
// populationByCountry == MAP [
//                              {"France": 65447374},
//                              {"United Kingdom": 62041708},
//                              {"Spain": 45989016},
//                              {"Portugal": 10707924},
//                              {"Ireland": 4459300},
//                            ]
We could solve it in two ways:
  1. First sorting the list by population, then creating the map.
  2. First creating the map, then sorting its entries by value.
Let's try ordering the list first:
// INCORRECT: Order will be ascending!
Map<String,Integer> populationByCountry =
    Op.on(countries).
        sortBy(Get.attrOfInteger("population")).
        toMap(Get.attrOfString("name"), Get.attrOfInteger("population")).get();
There is a problem there: sortBy will use the specified function for sorting, but sorting will be made according to natural order, and this will mean that less-populated countries will come first (opposite to what we want). So we will have to reverse the list once sorted:
Map<String,Integer> populationByCountry =
    Op.on(countries).
        sortBy(Get.attrOfInteger("population")).reverse().
        toMap(Get.attrOfString("name"), Get.attrOfInteger("population")).get();
Now it is correct. Finally, let's try the create map first, then sort approach. This time we will have to sort the map by its entry values...
Map<String,Integer> populationByCountry =
    Op.on(countries).
        toMap(Get.attrOfString("name"), Get.attrOfInteger("population")).
        sortBy(Get.attrOfInteger("value")).reverse().get();

21 April 2010

Executing an op4j function directly (without an expression)

Valid since: op4j 1.0

Description
Execute an op4j predefined function (or any other org.op4j.functions.Function<T,R> object) without having to create an operation or function expression.

Scenario
Our value String contains some accented characters, escaped for HTML:
// value == "Saint-&Eacute;tienne est une ville de France"
...and we want to unescape it so that we obtain a String like:
// value == "Saint-Étienne est une ville de France"

Recipe
Of course we could create an operation expression for executing the FnString.unescapeHTML function:

value = Op.on(value).exec(FnString.unescapeHTML()).get();

But, if we prefer, we can directly execute the function on the target String:

value = FnString.unescapeHTML().execute(value);

This is because the function object returned by FnString.unescapeHTML() is Function<String,String> so, in fact, if we look at it step by step:

Function<String,String> fn = FnString.unescapeHTML();
value = fn.execute(value);


Comments
All Function objects in op4j allow direct execution by means of their execute(...) method.

18 April 2010

Grouping a list of objects by the value of one of their attributes

Valid since: op4j 1.0

Description
Group a list of objects by the value one of their attributes, effectively creating a Map<?,List<?>> containing the distinct values for that attribute as keys, and the objects returning the same value for that attribute in the corresponding value lists.

Scenario
Our City class looks like this:
public class City {
    private String country;
    private String name;
    ...
    public String getCountry() {
        return this.country;
    }
    public String getName() {
        return this.name;
    }
}
And we have a List<City> cities variable containing some City objects:
// cities == LIST [
//                  CITY [ country="Spain";name="Santiago" ],
//                  CITY [ country="France";name="Marseille" ],
//                  CITY [ country="Portugal";name="Porto" ],
//                  CITY [ country="Spain";name="Barcelona" ],
//                  CITY [ country="Portugal";name="Lisboa" ],
//                  CITY [ country="Portugal";name="Viseu" ]
//                ]
Which we want to group by country, so that we get a Map<String,List<City>> just like:
// citiesByCountry == 
//           MAP [
//                 {
//                   "Spain" : 
//                   LIST [
//                     CITY [ country="Spain";name="Santiago" ],
//                     CITY [ country="Spain";name="Barcelona" ]
//                   ]
//                 }
//                 {
//                   "France" : 
//                   LIST [
//                     CITY [ country="France";name="Marseille" ]
//                   ]
//                 }
//                 {
//                   "Portugal" : 
//                   LIST [
//                     CITY [ country="Portugal";name="Porto" ],
//                     CITY [ country="Portugal";name="Lisboa" ],
//                     CITY [ country="Portugal";name="Viseu" ]
//                   ]
//                 }
//               ]

Recipe
What we need to do is create a map from our list by zipping the map keys (our existing cities will be the values) and then grouping values with the same keys into lists.

So the action we will execute is zipAndGroupKeysBy(function), and the function we will use to obtain the map keys will be an attribute getter, provided by the Get function hub:

Let's see it in action:

Map<String,List<City>> citiesByCountry =
    Op.on(cities).zipAndGroupKeysBy(Get.attrOfString("country")).get();


Comments
Let's have a look at the equivalent non-op4j Java code:
Map<String,List<City>> citiesByCountry =
    new LinkedHashMap<String,List<City>>();
for (City city : cities) {
    List citiesForCountry = citiesByCountry.get(city.getCountry());
    if (citiesForCountry == null) {
        citiesForCountry = new ArrayList<City>();
        citiesByCountry.put(city.getCountry(), citiesForCountry);
    }
    citiesForCountry.add(city);
}

Executing an OGNL expression on an array of Strings

Valid since: op4j 1.0

Description
Execute an OGNL (Object-Graph Navigation Language) expression on each of the elements of an array, obtaining another array with the results of these executions.

Scenario
Our String[] riverNames variable contains the names of several rivers in a remote part of the world:
// riverNames == ARRAY [ "Eume", "Ulla", "Tambre" ]
But we want to display these rivers in our interface with the "River" prefix, so we need to create another array containing Strings like:
// rivers == ARRAY [ "River Eume", "River Ulla", "River Tambre" ]

Recipe
We can execute an OGNL expression on each array element in order to create the Strings we really want. This can be easily done by mapping a function from the op4j-ognl extension:

String[] rivers = 
    Op.on(riverNames).map(FnOgnl.evalForString("'River ' + #target")).get();

When executing an OGNL expression, FnOgnl sets the target object as the root of the expression, but it also makes it available at the predefined #target variable (as you can see above). If the expression needed any parameters, the #param array variable would have contained them. Finally, an #index variable contains the iteration index in case you need it.

Comments
But let's go further... what if we wanted to convert this expression we have just created into a function called riverize so that we can apply it to any array of river names we might get?

Easy. Let's first create the river function by using a function expression (as opposite to the usual operation expressions):
Function<String[],String[]> riverize = 
    Fn.onArrayOf(Types.STRING).
        map(FnOgnl.evalForString("'River ' + #target")).get();
Our riverize function is of type Function<String[],String[]>, which means that it receives a String[] input (first type parameter) and returns another String[] object as a result (second type parameter). Let's execute it:
// moreRiverNames == ARRAY [ "Eo", "Sil" ]
String[] moreRivers = riverize.execute(moreRiverNames);
// moreRivers == ARRAY [ "River Eo", "River Sil" ]
Perfect!

op4j 1.0 RELEASED

Big news! The op4j project has today published its first stable version: op4j 1.0.

The new distribution is already downloadable from both Sourceforge and the Maven central repositories.

Get all the info at the project's home page at: http://www.op4j.org

The team wish to thank all the people who have been testing the 3 beta versions released during the last weeks. We hope this first stable version meets the expectations of everyone!

17 April 2010

Creating a list with the results of calling a method on each element of another list

Valid since: op4j 1.0

Description
Extract one attribute from each of the objects in a list and create another list with the results.

Scenario
Our User class is a value object class like:
public class User {
    private String name;
    ...
    public String getName() {
        return this.name;
    }
}
Given the List<User> users variable, containing:
// users == LIST [ 
//                 USER [ ...; name="James Cheddar"; ...]
//                 USER [ ...; name="Richard Stilton"; ...]
//                 USER [ ...; name="Bernard Brie"; ...]
//                 USER [ ...; name="Antonio Cabrales"; ...]
//               ]
...we want to obtain a List<String> with all the names of the users, like:
// users == LIST [ "James Cheddar", "Richard Stilton", 
//                 "Bernard Brie", "Antonio Cabrales" ]

Recipe
Map (iterate + execute) a Get function, which will call the getName() method:

List<String> names =
    Op.on(users).map(Get.attrOfString("name")).get();

Get.attrOfString(...) allows you to call the getter method for the name attribute (which is a String), and is equivalent in fact to calling the getName() method using a Call function:

List<String> names =
    Op.on(users).map(Call.methodForString("getName")).get();

Comments
Of course, mapping is equivalent to iterating and executing, so this will be equivalent to:
List<String> names =
    Op.on(users).forEach().exec(Get.attrOfString("name")).get();
Now, let's see the equivalent non-op4j Java code:
List<String> names = new ArrayList<String>();
for (User user : users) {
    names.add(user.getName());
}

But... what if users had been an array instead of a list? Well, because arrays need to be instantiated using their specific class in Java (and not a generic one like java.util.List<?>), our map action will need to specify the type of the result coming from the Get function, like:
...map(Types.STRING, Get.attrOfString("name"))...
}
And also, because of User not being a standard basic Java class like String or Integer, but instead a user-defined one, if we create our operation expression with:
Op.on(userArray)...
// User is not a basic Java class, so our operator will be limited!
...we will get a limited operator, which will let us do some things (like converting to a list or set, for instance), but not iterating or executing functions on its elements. For that, instead, we will need to specify the Type of the array's elements as a javaRuntype type (similar to that Types.STRING, but for our own User class):
Type<User> userType = Types.forClass(User.class);
Op.onArrayOf(userType, usersArray)...
Finally, putting it all together:
Type<User> userType = Types.forClass(User.class);
String[] names =
    Op.onArrayOf(userType, usersArray).
        map(Types.STRING, Get.attrOfString("name")).get();
Which compares to the equivalent non-op4j Java code:
List<String> namesList = new ArrayList<String>();
for (User user : usersArray) {
    namesList.add(user.getName());
}
String[] names = namesList.toArray(new String[namesList.size()]);

10 April 2010

Creating a map from its elements

Valid since: op4j 1.0

Description
Create a map given its keys and values as separate objects.

Scenario
We want to create a Map<String,String> peopleDept variable containing some people names as keys, and the departments they work for in our company as values:
// peopleDept == MAP [
//                   [ key="James Cheddar"; value="Finance" ]
//                   [ key="Richard Stilton"; value="Engineering" ]
//                   [ key="Bernard Brie"; value="Marketing" ]
//                   [ key="Antonio Cabrales"; value="Sales" ]
//                 ]

Recipe
We can just create a map operator by building the map on an entry-by-entry basis, and return it with get() before executing any other operation:

Map<String,String> peopleDept =
    Op.onMapFor("James Cheddar", "Finance").
            and("Richard Stilton", "Engineering").
            and("Bernard Brie", "Marketing").
            and("Antonio Cabrales", "Sales").get();

This looks good. But instead, as already mentioned in other recipes, because of the fact that this map holds keys and values of the same type (String), we could have created a list with all they keys and values in key, value, key, value, key, value... order and executed the couple() action to create the map:

Map<String,String> peopleDept =
    Op.onListFor(
        "James Cheddar",  "Finance",   "Richard Stilton",  "Engineering",
        "Bernard Brie",   "Marketing", "Antonio Cabrales", "Sales").
        couple().get();

Comments
The difference between these two methods is that the entry-by-entry map building method can be used always (whichever the key and value types), while the coupling method requires the resulting map to hold the same key and value types.

As an example, we could create a Map<String,Integer> peopleYearsInCo containing the relation between these persons and the number of years they have been working for the company:

Map<String,Integer> peopleYearsInCo =
    Op.onMapFor("James Cheddar", 12).
            and("Richard Stilton", 2).
            and("Bernard Brie", 7).
            and("Antonio Cabrales", 9).get();

09 April 2010

Extract some text from a String using a regular expression

Valid since: op4j 1.0

Description
Given a String, apply a regular expression (containing some group definitions) to it and, if it matches, extract one of the matched groups into a different String.

Scenario
Our books variable is an array containing some data about books, extracted from a text file. Our data look like this:
// books == ARRAY [ "Title=The Origin of Species; Price=24.90EUR",
//                  "Title=Odyssey; Price=13.50EUR",
//                  "Title=A Midsummer Night's Dream; Price=18.20EUR" ]
But we are only interested on the titles of those books, and we would like to create a String[] titles variable containing:
// books == ARRAY [ "The Origin of Species",
//                  "Odyssey",
//                  "A Midsummer Night's Dream" ]
For doing so, we define the following regular expression:
// regex == "Title=(.*?); Price(.*)"

Recipe
We should iterate on our books array and apply on each element the FnString.matchAndReplace(...) function, which will apply our regular expression and let us decide which group we want to extract from it (in this case, group number 1):

String[] titles = 
    Op.on(books).forEach().exec(FnString.matchAndExtract(regex, 1)).get();

...which is in fact equivalent to:

String[] titles = 
    Op.on(books).map(FnString.matchAndExtract(regex, 1)).get();


Comments
Let's look instead at a much more complex (and powerful) example: Imagine that we did't need only the book titles, but instead we wanted to create a map for each book containing an entry for each piece of data ("Title" and "Price"). Something like this:
// bookInfo == LIST [ 
//                    MAP [
//                          "Title"="The Origin of Species"
//                          "Price"="24.90EUR"
//                        ],
//                    MAP [
//                          "Title"="Odyssey"
//                          "Price"="13.50EUR"
//                        ],
//                    MAP [
//                          "Title"="A Midsummer Night's Dream"
//                          "Price"="18.20EUR"
//                        ]
//                  ]
What would we need to get this starting from our books variable? First, define a new regular expression able to extract both keys and values:
// regex == "(.*?)=(.*?); (.*?)=(.*?)"
And now let's see the steps:
  1. Convert the array into a List.
  2. Iterate it. For each element:
    1. Apply regular expression and extract groups 1, 2, 3 and 4 into a List<String>.
    2. Couple the four elements in the resulting list into two map entries each so that element 1 is key for the first entry, 2 is value for the first entry, 3 is key for the second entry and 4 is value for the second entry.
The functions involved will be:
// FnString.matchAndExtractAll(String regex, int... groups) : Function<String, List<String>>
// FnList.ofString().couple() : Function<List<String>, Map<String, String>>
Let's have a look at the resulting code:
List<Map<String,String>> bookInfo = 
    Op.on(books).toList().forEach().
        exec(FnString.matchAndExtractAll(regex, 1,2,3,4)).
        exec(FnList.ofString().couple()).get();
Much easier to write than to think of!

Creating a Calendar from day, month and year

Valid since: op4j 1.0

Description
Create a java.util.Calendar object containing a specific date from its components (day, month and year) in a simple way.

Scenario
We want to create a variable called date, of type java.util.Calendar, containing the following date:
// date == CALENDAR: 12 October, 1492. 00:00:00:000

Recipe
The FnCalendar function hub class from op4j provides us with a useful fieldIntegerListToCalendar() function, which we could use for solving our scenario in a very elegant way, just creating a list with the date components (year, month, day), and then applying the function:

Calendar date = 
    Op.onListFor(1492, 10, 12).exec(FnCalendar.fieldIntegerListToCalendar()).get();

Comments
Let's see the equivalent non-op4j Java code for this:
Calendar date = Calendar.getInstance();
date.clear();
date.set(Calendar.DAY_OF_MONTH, 12);
date.set(Calendar.MONTH, Calendar.OCTOBER);
date.set(Calendar.YEAR, 1492);

And... what if we wanted to be more specific and set the hour and minutes like:
// date == CALENDAR: 12 October, 1492. 02:34:00:000
Easy:
Calendar date = 
    Op.onListFor(1492, 10, 12, 2, 34).exec(FnCalendar.fieldIntegerListToCalendar()).get();

08 April 2010

Removing all accents (and other diacritics) from a String

Valid since: op4j 1.0

Description
Remove all diacritics common in European languages from the characters in a String, converting the text into an ASCII-compatible String. A common operation, for example, in text search comparison scenarios.

Scenario
Our conts variable is an array containing the names of the Earth's continents in Castilian Spanish language:
//conts == ARRAY [ "África", "América", "Antártida", "Asia", "Europa", "Oceanía" ]
...and, knowing that our users might forget to input accents in our application, we need to strip all the accents from those texts so that searches are not influenced by their bad ortography:
//conts == ARRAY [ "Africa", "America", "Antartida", "Asia", "Europa", "Oceania" ]

Recipe
Use the op4j asciify() function in the FnString function hub class, which is able to transform accented characters(and also other diacritics) into their non-accented equivalents.

Also, this function will have to be applied to each element of the array, and so a map(..) action will be needed for executing the function.

conts = Op.on(conts).map(FnString.asciify()).get();

This will be of course less verbose -but equivalent- than:

conts = Op.on(conts).forEach().exec(FnString.asciify()).get();

Comments
But, what if we also wanted an uppercase output? Well, just throw in the FnString.toUpperCase() function:
conts = 
    Op.on(conts).forEach().exec(FnString.asciify()).exec(FnString.toUpperCase()).get();
Or equivalently, we could chain both functions into one:
conts = 
    Op.on(conts).map(FnFunc.chain(FnString.asciify(), FnString.toUpperCase())).get();

[NEWS] op4j 1.0-beta3 RELEASED!

Version 1.0-beta3 of op4j has just been released!

This version adds two new extensions: op4j-ognl and op4j-jodatime, new optimizations and hundreds of new functions and useful actions for your operators.

See the CHANGELOG
Or go to the Project site.

29 March 2010

Adding an element to an array at a specific position

Valid since: op4j 1.0

Description
Insert a new element into an array at a specific position.

Scenario
Our minerals variable, of type String[], contains:
// minerals == ARRAY [ "Talc", "Quartz", "Diamond" ]
...and we want to add "Fluorite" at the second position of the array, as it is harder than talc but softer than quartz:
// minerals == ARRAY [ "Talc", "Fluorite", "Quartz", "Diamond" ]

Recipe
Use the insert(...) action on the array, specifying the position at which the new element will be added to the array. Positions start with zero.

minerals = Op.on(minerals).insert(1 ,"Fluorite").get();

Comments
This recipe is also valid for lists, maps and sets.

If we wanted to add more than one element, we could have done:
minerals = 
    Op.on(minerals).insertAll(1, "Fluorite", "Apatite").get();

Let's see the equivalent non-op4j Java code:
minerals = Arrays.copyOf(minerals, minerals.length + 1);
for (int i = (minerals.length - 1), z = 1; i > z; i--) {
    minerals[i] = minerals[i - 1];
}
minerals[1] = "Fluorite";

Adding an element to an array

Valid since: op4j 1.0

Description
Add a new element at the end of an array. This will mean resizing the array.

Scenario
Our ingredients variable, of type String[], contains:
// ingredients == ARRAY [ "Lettuce", "Tomato", "Onion" ]
...and we would like to add a new ingredient, Olive Oil, so that we get:
// ingredients == ARRAY [ "Lettuce", "Tomato", "Onion", "Olive Oil" ]

Recipe
Just use the add(...) action on the array:

ingredients = Op.on(ingredients).add("Olive Oil").get();

Comments
This recipe is also valid for lists, maps and sets.

If we wanted to add more than one element, we could have done:
ingredients = 
    Op.on(ingredients).addAll("Olive Oil", "Balsamic Vinegar").get();

And finally, let's look at the non-op4j Java equivalent code:
ingredients = Arrays.copyOf(ingredients, ingredients.length + 1);
ingredients[ingredients.length - 1] = "Olive Oil";

28 March 2010

Sorting an array

Valid since: op4j 1.0

Description
Sort an array using the natural order of their elements.

Scenario
Our oceans variable contains an unordered array of Strings with the names of the Earth's oceans:
// oceans == ARRAY [ "Pacific", "Atlantic", "Indian", "Arctic", "Southern" ]
...and we want to order it by Strings' natural order, which is alphabetic:
// oceans == ARRAY [ "Arctic", "Atlantic", "Indian", "Pacific", "Southern" ]

Recipe
Just apply the sort() action to the array:

oceans = Op.on(oceans).sort().get();

Comments
This sort() action can also be applied to lists or sets, and there are variants to sort using a comparator (sort(Comparator)) or even sort by the result of executing a function on the elements (sortBy(IFunction)). Maps can also be ordered by their keys.

Let's have a look at the equivalent non-op4j Java code:
List<String> oceansList = Arrays.asList(oceans);
Collections.sort(oceansList);
oceans = oceansList.toArray(new String[oceansList.size()]);

Removing duplicates from an array (or list)

Valid since: op4j 1.0

Description
Remove duplicate elements from an array (or list).

Scenario
We have a String[] capitals variable, such as:
// capitals == ARRAY [ "Lisboa", "Madrid", "Paris", "Lisboa", "Bruxelles" ]
...and we want to remove duplicate elements in order to get:
// capitals == ARRAY [ "Lisboa", "Madrid", "Paris", "Bruxelles" ]

Recipe
Operate on the array and use the distinct() action:

capitals = Op.on(capitals).distinct().get();

Comments
If we had a list instead of an array, our code would have been just the same:
// capitalList == LIST [ "Lisboa", "Madrid", "Paris", "Lisboa", "Bruxelles" ]
capitalList = Op.on(capitalList).distinct().get();

Finally, let's compare with the equivalent non-op4j Java code:
Set<String> capitalSet = new LinkedHashSet<String>();
for (String capital : capitals) {
    capitalSet.add(capital);
}
capitals = capitalSet.toArray(new String[capitalSet.size()]);

27 March 2010

Converting a list into an array

Valid since: op4j 1.0

Description
Convert a list of objects (List<T>) into an array of the same type (T[]).

Scenario
We have a List<String> variable called elementList, containing:
// elementList == LIST [ "earth", "air", "fire", "water" ]
...and we want to convert this variable into a String[] object.

Recipe
Execute the toArrayOf(Type) action on the list:

String[] elementArray =
    Op.on(elementList).toArrayOf(Types.STRING).get();


Comments
In the example above, it was necessary to specify the type of the array elements (String) with a javaRuntype Type because Java does not create arrays by instantiating a generic class like java.util.List or java.util.Set, but rather by creating an instance of a specific String[] class. This is why op4j needs the class to be used for creating the new array in the form of an org.javaruntype.type.Type object.

This would not be needed, for example, if we wanted to create a set:
Set<String> elementSet =
    Op.on(elementsList).toSet().get();

Let's look at the equivalent non-op4j Java code for the List-to-Array conversion:
String[] elementArray = 
    elementList.toArray(new String[elementList.size()]);

Filtering numbers greater than a value out of a list

Valid since: op4j 1.0

Description
Given a list of numbers, remove all elements greater than a specified value.

Scenario
We have List<Integer> variable called values containing some integer numbers:
// values == LIST [ 6641, 53, 430, 1245 ]
...and we want to remove all the elements greater than 500, so that values looks like this:
// values == LIST [ 53, 430 ]

Recipe
Execute the removeAllTrue(IFunction<T,Boolean>) action, which will remove from the list all the elements for which the specified function returns true. The specified function will be FnNumber.greaterThan(...):

values =
    Op.on(values).removeAllTrue(FnNumber.greaterThan(500)).get();


Comments
op4j includes many boolean comparison function like "eq", "notEq", "greaterThan", "greaterOrEqTo", "lessThan", "lessOrEqTo", etc. They can be applied to a variety of objects like Integers, Longs, BigDecimals, Strings, etc.

Converting an array of Strings into a null-free array of Integers

Valid since: op4j 1.0

Description
Convert an array of String objects representing valid integer numbers into an array of Integer objects, having filtered all null values out of the array.

Scenario
We have a String[] like:
// strArray == ARRAY [ "431", null, "94", "398" ]
And we want to convert it into an Integer[] containing no null elements.

Recipe
Two actions will be needed:
  • First, execute the conversion from String to Integer.
  • Second, remove all nulls from the resulting array.
Integer[] values =
    Op.on(strArray).map(Types.INTEGER, FnString.toInteger()).removeAllNull().get();


Comments
Note that because arrays are not collections, and instantiating them requires creating an instance of a specific class (instead of a generic class like java.util.List or java.util.Set), executing a function that changes the type of the elements of an array requires specifying the new type, which is done with that Types.INTEGER parameter seen above. This is an org.javaruntype.type.Type object, from the javaRuntype library.

Mapping (executed here via a map(...) action) is equivalent to iterating, executing a function, and then ending the iteration. So, the code above is equivalent to:
Integer[] values =
    Op.on(strArray).
        forEach().exec(Types.INTEGER, FnString.toInteger()).endFor().
        removeAllNull().get();

Let's see the equivalent non-op4j Java code:
List valuesList = new ArrayList();
for (String element : strArray) {
    if (element != null) {
        valuesList.add(Integer.parseInt(element));
    }
}
Integer[] values = valuesList.toArray(new Integer[valuesList.size()]);

Parsing a String number into a BigDecimal (no matter the decimal separator)

Valid since: op4j 1.0

Description
Parsing a String containing a decimal number, without having to specify the symbol (comma or point) that has been used as a decimal separator.

Scenario
A form on a web page allows users to input a decimal number. We have two of these numbers in String variables strValue1 and strValue2, and we want to parse these strings into java.math.BigDecimal objects.

But these two numbers have been input by users coming from different countries, and they have used their own different ways of specifying the decimal separator:
// strValue1 == "871,21"
// strValue2 == "421.441"

Recipe
The FnString.toDouble(...) function provides the means of specifying the decimal point being used by using the DecimalPoint enum, one of which values allows both point and comma:

Double value1 =
    Op.on(strValue1).exec(FnString.toDouble(DecimalPoint.CAN_BE_POINT_OR_COMMA)).get();
Double value2 =
    Op.on(strValue2).exec(FnString.toDouble(DecimalPoint.CAN_BE_POINT_OR_COMMA)).get();



Comments
This method can also be used for obtaining Double or Float objects.

Also, note that this method will not work correctly if thousands separators are used, like in "1,423,243.87", because if decimal separators are not used but thousands separators are (like "1,423,243"), the system will not be able of determining which was the decimal separator being used.

26 March 2010

Parsing a String decimal number into a Double (using locale)

Valid since: op4j 1.0

Description
Obtaining a Double object from a String containing a decimal number written in a locale-specific manner.

Scenario
We have a String variable called value which contains a decimal number written by a Frenchman:
// value == "34,59"
French use the comma sign (",") as a decimal separator, contrary to most English-speaking people and also contrary to the standard way to represent numbers as Strings in Java (which is American English). We will need a locale-sensitive conversion then.


Recipe
Use a version of the FnString.toDouble(...) function that allows a locale to be specified:

Double value =
    Op.on(strValue).exec(FnString.toDouble("fr")).get();


Comments
op4j's number conversion functions come in many flavours, including specifying locales, scales and rounding modes for Integer, Longs, BigDecimals, Doubles, etc.

Equivalent non-op4j Java code:
NumberFormat numberFormat = 
    NumberFormat.getInstance(new Locale("fr"));
Double value = (Double) numberFormat.parse(strValue);

Filtering nulls from an array

Valid since: op4j 1.0

Description
Given an array (or list, or set), remove all its null elements.

Scenario
We have an Integer[] variable called values, like:
// values == ARRAY [ null, 12, 43, 92, null, 34 ]
...and we want to easily remove all null elements from it.

Recipe
Just execute the removeAllNulls() action on the array and return the result:

Integer[] filteredValues =
    Op.on(values).removeAllNull().get();


Comments
There are many remove methods, like for example removeAllTrue(function), which determines whether an element has to be removed or not depending on the result of executing a function passed as a parameter.

Equivalent non-op4j Java code:
List<Integer> filteredValuesList = new ArrayList<Integer>();
for (Integer value : values) {
    if (value != null) {
        filteredValuesList.add(value);
    }
}
Integer[] filteredValues = 
    filteredValuesList.toArray(new Integer[filteredValuesList.size()]);

25 March 2010

Converting a list of Strings into a list of Calendars (using a pattern and a locale)

Valid since: op4j 1.0

Description
Create a List<Calendar> object from a List<String>, by applying a standard Java locale-dependent pattern to each String.

Scenario
We need to build a List of Calendar objects from the values in our dates variable, which contains a couple of Strings representing dates:
// dates == LIST ["12 de octubre, 1492", "06 de diciembre, 1978"]
A valid Java pattern for parsing these dates is "dd 'de' MMMM, yyyy", and we must tell the parser that month names (in long format) are in Spanish.

Recipe
Iterate the list of Strings and execute the FnString.toCalendar(...) function on each element to obtain a Calendar.

As our pattern ("dd 'de' MMMM, yyyy") makes use of textual month names (like jan, may, december...), this function requires a locale to be specified so that the names of the months are correctly understood. In this case, we will specify the Spanish locale (es):

List<Calendar> cals =
    Op.on(dates).map(FnString.toCalendar("dd 'de' MMMM, yyyy", "es")).get();

Comments
This recipe involved mapping (map(...) action), which is equivalent to iterating, then executing, and then ending iteration on an array, list or set. This makes the above example equivalent to:
List<Calendar> cals =
    Op.on(dates).forEach().exec(FnString.toCalendar("dd 'de' MMMM, yyyy", "es")).get();

Let's compare with non-op4j normal Java code:
SimpleDateFormat dateFormat = new SimpleDateFormat(("dd 'de' MMMM, yyyy", "es"));
List<Calendar> cals = new ArrayList<Calendar>();
for (String date : dates) {
    Date dDate = null;
    try {
        dDate = dateFormat.parse(date);
    } catch (ParseException e) {
        throw SomeException(e);
    }
    Calendar cal = Calendar.getInstance();
    cal.setTime(dDate);
    cals.add(cal);
}

Converting a String into a Calendar (using a pattern)

Valid since: op4j 1.0

Description
Create a java.util.Calendar object from a String, by applying a standard Java pattern to this String.

Scenario
Our date variable contains a String in the "dd/MM/yyyy" format, like:
String date = "06/12/1978";
...and we want to obtain a java.util.Calendar for this date.

Recipe
Operate on the String, and apply one of the FnString.toCalendar() variants (specifically, the one receiving a pattern).

Calendar cal =
    Op.on(date).exec(FnString.toCalendar("dd/MM/yyyy")).get();


Comments
This function creates truncated calendar objects, which means that all fields less significant than the least-significant of the specified fields are set to zero. In the example, the least-significant field in the pattern is day, and so hour, minute, second and millisecond are set to zero.

Let's compare with non-op4j normal Java code:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date dDate = null;
try {
    dDate = dateFormat.parse(date);
} catch (ParseException e) {
    throw SomeException(e);
}
Calendar cal = Calendar.getInstance();
cal.setTime(dDate);

Creating maps by coupling elements

Valid since: op4j 1.0

Description
Create a java.util.Map object by specifying all its keys and values, alternating them into an array, list or set, and then performing the couple action which will consider all even elements as keys and odd elements as values (starting with 0).

Scenario
We want to create a map relating some countries to their capital cities. Like: {{"Spain"="Madrid"}, {"United Kingdom"="London"}, {"France"="Paris"}}.

Recipe
First specify all the keys and values (alternating them in key-value order) and then execute the couple action:

Map<String,String> capitals =
    Op.onListFor("Spain", "Madrid", "United Kingdom", "London", "France", "Paris").couple().get();


Comments
Coupling needs the resulting map to specify the same type for keys and values (e.g. Map<String,String>, Map<Integer,Integer>, etc.).

Comparing it with non-op4j code...
Map<String,String> capitals = new LinkedHashMap<String,String>();
capitals .put("Spain", "Madrid");
capitals .put("United Kingdom", "London");
capitals .put("France", "Paris");

Creating maps by zipping keys and values

Valid since: op4j 1.0

Description
Create a java.util.Map object by zipping keys and values. Zipping involves having an array, list or set of objects which we want to consider either keys or values for the new map, and then specify another sequence of objects (same number of them as the existing array, list or set) that will be paired one-to-one with the elements of the existing structure so that, either the original element is considered key and the new object is considered value (zip values), or the contrary (zip keys).

Scenario
We want to create a Map<String,Integer> of person names (keys) and ages (values). Specifically we want: {{"John"=27}, {"Mary"=49}, {"Derek"=19}}.

Recipe
We will zip the values (ages), so we will start by creating a list on the keys and then we will zip the corresponding ages:

Map<String,Integer> agesByName =
    Op.onListFor("John", "Mary", "Derek").zipValues(27, 49, 19).get();


Comments
We could have zipped the keys instead (althought it would have been less natural in this specific case):

Map<String,Integer> agesByName =
    Op.onListFor(27, 49, 19).zipKeys("John", "Mary", "Derek").get();

Remember that all maps created by op4j are ordered (java.util.LinkedHashMap), and thus the new map will keep the order of the original list when iterated.

Let's have a look at the equivalent Java code:
Map<String,Integer> agesByName= new LinkedHashMap<String,Integer>();
agesByName.put("John", 27);
agesByName.put("Mary", 49);
agesByName.put("Derek", 19);

24 March 2010

[NEWS] op4j 1.0-beta2 RELEASED!

Version 1.0-beta2 of op4j has just been released!

Lots of new features have been added in this new version, focusing
effort on creating many new useful functions and simplifying
behaviours.

See the CHANGELOG
Or go to the Project site.

23 March 2010

Creating a set from its elements

Valid since: op4j 1.0

Description
Easily create a set containing some objects.

Scenario
Having some objects of type User called user1, user2 and user3, we want to create a Set<User> object containing them.

Recipe
Create a set operator on the objects and don't execute any action on it, just return the result:

Set<User> users = 
    Op.onSetFor(user1, user2, user3).get();

Comments
Sets created by op4j are always ordered sets (java.util.LinkedHashSet).

Compare this to the the non-op4j Java equivalent:

Set<User> users= new LinkedHashSet<User>();
users.add(user1);
users.add(user2);
users.add(user3);

Creating a list from its elements

Valid since: op4j 1.0

Description
Easily create a list containing some objects.

Scenario
Having the strings "hello", "hola", "ola" and "olá", we want to create a List<String> object containing them.

Recipe
Create a list operator on the strings and don't execute any action on it, just return the result:

List<String> stringList = 
    Op.onListFor("hello", "hola", "ola", "olá").get();

Comments
Compare this to the the non-op4j Java equivalent:

List<String> stringList = new ArrayList<String>();
stringList.add("hello");
stringList.add("hola");
stringList.add("ola");
stringList.add("olá");

[NEWS] Welcome to Bending the Java spoon!

This blog is intended for publishing news about the op4j library as well as recipes for its use.

Recipes will come in the form of small practical scenarios solved with code examples, in order to show the power and versatility of op4j.

This is an official blog, published and maintained by the op4j project members and contributors.