This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative.
The license (Mozilla version 1.0) can be read at the MMBase site. See http://www.mmbase.org/license
Table of Contents
The MMBase 'Function Framework' allows you to add functions or methods to different layers of MMBase. You can access them using the taglib function tags or the bridge. This tag <mm:function set="utils" name="generatePassword" /> returns a random password like 'zyrentu'.
Functions can be added to nodes, builders and clouds and can be defined in three locations:
The nodemanager (or builder) of a certain nodetype
These functions are methods in the Java code belonging to a builder. Some examples of such functions these can be found in org.mmbase.util.functions.ExampleBuilder.
As a functionset
A functionset are functions which are grouped together in a set. Normally such a set belongs to one application. With it developers can make rather complicated functionality available to templaters. Functionsets are defined in 'config/functions/functionsets.xml'.
A specific classname
It is also possible to directly acces a specific method in a JSP using the function tags. See for example org.mmbase.util.functions.ExampleBean
Each having their own backend implementation but they all share a common way to use them from inside Java or JSP. This document shows some examples of the use of functions, more information can be found in the API documentation at org.mmbase.util.functions and the taglib reference documentation.
Allmost everybody who is bit familiar with the taglib knows that you can get the gui value of a node in MMBase 1.7 and former versions with a few simple lines of code.
<mm:node number="default.mags"> <mm:field name="gui()" /> </mm:node>
This functionality is deprecated. The equivalent method of getting the gui value of a node in MMBase 1.8 is the following and as such is a method defined in MMObjectbuilder.
<mm:node number="default.mags"> <mm:function name="gui" /> </mm:node>
Another simple example of a function is made available by the class org.mmbase.util.functions.ExampleBean and could look like this. It accesses the method stringFunction which uses no arguments and returns an arbitrary String.
<mm:function classname="org.mmbase.util.functions.ExampleBean" name="stringFunction" />
ExampleBean contains multiple methods that can be accessed using functions. ExampleBean.java contains a lot more lines of code of but when you strip it down to the bare minimum that is needed to execute the above example, the following lines of code remain.
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]]'.
A more exiting example would use the the set-methods defined in this bean by using parameter tags. These parameters need to be grouped with the functioncontainer tag.
<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>
The above example returns '[[foo/bar]]'.
The class ExampleBean has several examples all with different return types. Multiple return types are defined by the way you call them. The taglib contains the following function tags to accommodate them.
<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)
Functions can have parameters. The functioncontainer tag is designed to group functions and parameters. It also provides you with a way to group several functions together.
<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.
It is also possible to add parameters using MMBase referids, this can come in handy when a variable is already present in your page and you want to access it.
<mm:import externid="template">AASSHHM</mm:param> Your random new password might be: <mm:function name="getPassword" referid="template" />
Functions can be added to the builder configuration. This is especially usefull for methods related to a certain nodetype, allthough the following example is generic and can be added to every builder and thus every type of node.
To specify a function in a builder you should include a functionlist element defining a function with its 'name', a 'key' the method and a 'class' being the class of the method. The functionlist should be at the end of the builder configuration, after the fieldlist. The list can include of course multiple functions.
Adding a function to a builder of course limits the use of that function to only that nodetype. While defining functions in a functionset makes them available to all kinds of nodes.
<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.
You can for example define a set 'utils' or 'statistics' or even map to external application 'lucene'. The set 'utils' is already definied in MMBase. Defining sets is done in a two xml files. The first in 'config/functions/functionsets.xml' defines what sets there are:
<?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" />.
Its also possible to define functions in MMBase Modules see e.g. the MMAdmin module and its jsp pages in mmbase/mmadmin/. Also e.g. the crontab and clustering applications ship with modules (CrontabModule, ClusteringModule), which define 'functions' which are used in admin pages.
The classes and interfaces of the function framework are in the org.mmbase.util.functions package. The bridge classes will return object from this package.
The most important classes are 'Function', and 'Parameter'.
The Function object represents the piece of functionality. You must start by somehow getting a Function object. Several bridge objects like Node, NodeManager and Module have their 'getFunction' methods, but you can also call the static methods from FunctionFactory from the org.mmbase.util.functions package.
The most important methods of the function object are 'createParameters' and 'getFunctionValue(Parameters)'. You'd normally start with calling 'createParameters':
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.
The 'Parameter' class of org.mmbase.util.functions defines one parameter. So, it contains e.g. a name, a type and a default value. Don't be confused with the 'Parameters' class, which contains actual parameter values. A complete argument definition is represented with an array of Parameter objects.
Many functions have similar arguments. Like 'cloud', 'request' or 'locale'. For these kind of parameters some static constants in the Parameter class are present. These constants can be used to deal with parameters object without knowing very much about it. You can e.g. fill a cloud parameter if there is one:
if (parameters.containsParameter(Parameter.CLOUD)) { parameters.set(Parameter.CLOUD, cloud); }or:
parameters.setIfDefined(Parameter.CLOUD, cloud);
This is e.g. used by MMBase taglib to automaticly set some parameters (like cloud, request, node etc).
One of the advantages of the function framework is that you can not only return objects like booleans or strings but also MMBase nodes or lists of nodes. In this way you can make functions that work like a <mm:node /> or <mm:nodelist /> but have their own selection method. For example we could make a function like:
<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: [email protected]