Table of Contents
Functions can be added to nodes, builders and clouds and can be defined in three locations:
<mm:node number="default.mags"> <mm:field name="gui()" /> </mm:node>
<mm:node number="default.mags"> <mm:function name="gui" /> </mm:node>
<mm:function classname="org.mmbase.util.functions.ExampleBean" name="stringFunction" />
package org.mmbase.util.functions; public final class ExampleBean { private String parameter1; private String parameter3 = "Default value"; public void setParameter1(String hoi) { parameter1 = hoi; } public void setAnotherParameter(String a) { parameter3 = a; } public String stringFunction() { return "[[" + parameter1 + "/" + parameter3 + "]]"; } }
As you would expect this example function returns '[[null/Default value]]'.
<mm:functioncontainer> <mm:param name="parameter1">foo</mm:param> <mm:param name="anotherParameter">bar</mm:param> <mm:function classname="org.mmbase.util.functions.ExampleBean" name="stringFunction" /> </mm:functioncontainer>
<mm:function (String) <mm:booleanfunction (boolean) <mm:voidfunction (no return value) <mm:listfunction (list) <mm:nodefunction (a MMBase node or a virtual MMBase node) <mm:nodelistfunction (a list of nodes or virtual nodes)
<mm:functioncontainer> <mm:param name="template">AASSHHM</mm:param> your random new password might be : <mm:function set="utils" name="generatePassword" /> </mm:functioncontainer>
Each of the defined parameters will be added to every function within the functioncontainer.
<mm:import externid="template">AASSHHM</mm:param> Your random new password might be: <mm:function name="getPassword" referid="template" />
<functionlist> <function key="stringFunction" name="bbb"> <class>org.mmbase.util.functions.ExampleBean</class> </function> </functionlist>
You can use the following in a template:
<mm:node number="default.mags"><mm:function name="bbb" /></mm:node>
This example uses the method stringFunction from ExampleBean (see above). It returns '[[null/default]]'.
Another example uses a class while including the class 'org.mmbase.util.functions.ExampleBuilder' in the class element of the 'news' builder.
<class>org.mmbase.util.functions.ExampleBuilder</class>You can use the following function in a template:
<ol> <mm:listnodes type="news"> <li> number: <mm:field name="number" /> title: <mm:field name="title" /> predecessor: <mm:function name="predecessor" /> </li> </mm:listnodes> </ol>
It returns the nodenumbers preceding the current one. The complete code of this example method can be found in the example class.
As should be clear from the above examples it is not especially necessary to define a function in a special builder class. Allthough because the function is only defined in the builder of the nodetype 'magazines', it only works on nodes of type 'magazines'. When you want your functions to be used by every type of node you better define a functionset.
You can check whether a node supports a certain function with the tag <mm:hasfunction />.
<mm:hasfunction name="index"> <mm:function name="index" /> </hasfunction>
Unlike Module or NodeManagers related functions the set functions are aimed for a global use.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE functionsets PUBLIC "-//MMBase//DTD functionsets config 1.0//EN" "http://www.mmbase.org/dtd/functionsets_1_0.dtd"> <functionsets> <functionset name="utils" resource="utils.xml" /> </functionsets>The set itself (in this case 'config/functions/utils.xml') defines the mapping, names, classes and methods to be called:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE functionset PUBLIC "//MMBase - functionset //" "http://www.mmbase.org/dtd/functionset_1_0.dtd"> <functionset> <description> Some util functions from org.mmbase.util, made accessible through the function-framework. </description> <function name="generatePassword"> <description> Generates a password. Using a template (chain of characters A (random letter) C (random alphanumeric) H (random hex) S (random syllable) 6 (random dice) 9 (random digit)). Default template: SSSSSS. </description> <type>class</type> <class>org.mmbase.util.PasswordGenerator</class> <method>getPassword</method> <param name="template" type="String">SSSSSS</param> </function> <function name="randomLong"> <description> Generates a random long integer. </description> <type>class</type> <class>org.mmbase.util.RandomPool</class> <method>value_and_stir</method> </function> <function name="filename"> <description> Makes filename of commons file upload's FileItem.getName. </description> <type>class</type> <class>org.mmbase.util.functions.Utils</class> <method>getFileItemName</method> <param name="filename" type="String" /> </function> </functionset>
As you can see the 'utils' functionset defines three functions that can be accessed using functiontags. For example like <mm:function set="utils" name="generatePassword" />.
The most important classes are 'Function', and 'Parameter'.
Function nodeFunction = node.getFunction("myfunction"); Parameters parameters = nodeFunction.createParameters();And then you have to set the parameters:
parameters.set("foo", "bar"); parameters.set(Parameter.REQUEST, request);You can only set parameters wich are defined for the function. Failing to do that results in exceptions. You can also fill this parameters object as a List (because it is a list). So you could have done this too:
parameters.add("bar"); parameters.add(request);or
parameters.set(0, "bar"); parameters.set(1, request);but then you have to remember the exact order of the parameters. It is recommended to set them by name.
When ready, you can obtain the function value:
Object value = function.getFunctionValue(parameters);
If the function does not need any parameters, you can skip the parameters part and simply provide null to getFunctionValue.
<mm:functionnode set="util" name="getRandomNode"> object number : <mm:field name="number" /> object type : <mm:field name="otype" /> object owner : <mm:field name="owner" /> </mm:functionnode>Java snippet:
public MMObjectNode getRandomNode() { return cloud.getRandomNode(randomnumber); // none working code }
The same is possible with lists :
<mm:functionnodelist set="util" name="getRandomNodes"> object number : <mm:field name="number" /> object type : <mm:field name="otype" /> object owner : <mm:field name="owner" /> </mm:functionnodelist>Again in Java the method could look like this :
public List getRandomNodes() { List list = new ArrayList(); list.add(cloud.getRandomNode(randomnumber)); // none working code list.add(cloud.getRandomNode(randomnumber2)); // none working code list.add(cloud.getRandomNode(randomnumber3)); // none working code return list; }
Its also possible to use virtual nodes in functions, this opens up a interesting uses in that it allows you to return any information in the form of MMBase objects. The main advantage of this that the frontend programmers can use the tools they already know for handling nodes, fields and lists for example we could return some information as a mmbase node like this :
public MMObjectNode getOSInfo() { Cloud cloud = LocalContext.getCloudContext().getCloud("mmbase"); MMObjectNode virtual = builder.getNewNode("admin"); virtual.setValue("hardware", System.getProperty("os.arch"); virtual.setValue("os", System.getProperty("os.name"); virtual.setValue("version", System.getProperty("os.version"); return virtual; }We can access methods using the MMBase taglib and handle the returns values like lists, nodes or fields.
<mm:nodefunction set="mySet" name="getOSInfo"> So you use <mm:field name="hardware" /> <mm:field name="os"> <mm:compare value="osx"> and i guess you don't like Bill Gates. </mm:compare> <mm:compare value="windowsxp"> and i guess you don't like Steve Jobs. </mm:compare> </mm:field> </mm:nodefunction>
We can also create lists. For example we could make a list of accounts from a LDAP server that acts like any normal MMBase list (made up code for the ldap parts).
public List getAccounts(String searchkey) { Cloud cloud = LocalContext.getCloudContext().getCloud("mmbase"); List list = new ArrayList(); // fill the list from the ldap server, using a while Iterator i = ldap.getAccounts(searchkey); while (i.hasNext()) { NextLDAP user = (NextLDAP)i.next(); MMObjectNode virtual = builder.getNewNode("admin"); virtual.setValue("account", user.getAccount(); virtual.setValue("firstname", user.getFirstName(); virtual.setValue("surname", user.getSurName(); list.add(virtual); } }From the taglib we can work with this list like we can work with any other nodelist :
<mm:nodelistfunction set="mySet" name="getUsers" referid="searchkey"> <mm:first>The first user found</mm:first> <mm:last>The last user found</mm:last> <mm:field name="account" /> (<mm:field name="firstname" /> <mm:field name="surname" />)<br /> </mm:nodelistfunction>As you can see all the normal MMBase tags can be applied. The frontend programmer doesn't have to know the content is not coming from MMBase at alle but from an LDAP server.
This is part of the MMBase documentation.
For questions and remarks about this documentation mail to: documentation@mmbase.org