some time ago I posted a how-to in openoffice format to the list. Now i got it docbooked, so it can be assimilated into the mmbase documentation on mmbase.org.
Michiel was wondering if it should be made part of the backend developers or frontent developers documentation. To be honest I cant really define the line between the two as well, as a matter of fact, since it has a close realtion to the builder configuration file, it could as easily be made part of the Information Analyst documentation, since that is where the builder configuration file is introduced. So i havent got a clue of where it should reside either, maybe there could be created a special how-to section as well.
Anyway, I feel this how to is a useful addition to the current MMBase documentation, therefor i throw it at the community for them to do as they like with it :)
Willem
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"> <article> <articleinfo> <title>HOW TO: Add a custom function to a nodebuilder</title> <date>2004-04-15</date> <edition></edition> <authorgroup> <author> <firstname>Willem</firstname> <surname>Voogd</surname> </author> </authorgroup> <revhistory> <revision> <revnumber>0.1</revnumber> <date>2004-04-15</date> <revremark>First draft</revremark> </revision> </revhistory> <abstract> <para>This How To provides information on how to specialize the MMObjectBuilder class so that custom functionality for a builder can be implemented.</para> <para>This How-To is based on functionality provided by MMBase 1.7.0</para> </abstract> </articleinfo> <section> <title>Introduction</title> <para>We are going to implement the 'Hello World' paradigm. Our implementation will take a person object, which has a name, and say 'Hello' to it. </para> <para>This means we will need an object called Person, which has one attribute called name. Then we want to create a custom function for the builder that greets the person it is called upon.</para> <para>To implement this functionality we are going to create three files: <itemizedlist> <listitem> <para>person.xml</para> </listitem> <listitem> <para>PersonBuilder.java</para> </listitem> <listitem> <para>helloperson.jsp</para> </listitem> </itemizedlist> </para> </section> <section> <title>Implementation</title> <section> <title>The node builder</title> <para>First we are going to take a look at the implementation of our node builder, person.xml</para> <para> <programlisting format="linespecific"><![CDATA[ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE builder PUBLIC "-//MMBase//DTD builder config 1.1//EN" "http://www.mmbase.org/dtd/builder_1_1.dtd">
<builder name="persons" maintainer="thedutchrepublic.com" version="0" extends="object">
<status>active</status>
<classfile>org.mmbase.examples.howtos.builders.PersonBuilder</classfile>
<names>
<singular xml:lang="en">Person</singular>
<singular xml:lang="nl">Persoon</singular>
<plural xml:lang="en">Persons</plural>
<plural xml:lang="nl">Personen</plural>
</names>
<descriptions>
<description xml:lang="en">A Person</description>
<description xml:lang="nl">Een Persoon</description>
</descriptions>
<fieldlist>
<field>
<descriptions>
<description xml:lang="en">The name of the person</description>
<description xml:lang="nl">De naam van de persoon</description>
</descriptions>
<gui>
<guiname xml:lang="en">Name</guiname>
<guiname xml:lang="nl">Naam</guiname>
<guitype>string</guitype>
</gui>
<editor>
<positions>
<input>2</input>
<list>2</list>
<search>2</search>
</positions>
</editor>
<db>
<name>name</name>
<type state="persistent" size="255" notnull="false" key="false">STRING</type>
</db>
</field>
</fieldlist>
</builder>
]]></programlisting>
</para>
<para>In this builder a person object is specified, with just one
attribute, the persons name. Of course there are much more attributes
possible for a person object, such as different fields for surname and
familyname, infixes, birth date and stuff like that. For this how to
however, we just need to know a persons name.</para>
</section>
<section>
<title>The Java Class</title>
<para>We want a function on the person object that greets the person,
when called. This will be just a simple message as “Hello
[NameOfPerson]”.</para>
<para>We will call the file PersonBuilder.java so that it is evident to
which builderfile it is related.</para>
<para>
<programlisting format="linespecific"><![CDATA[
/* PersonBuilder.java
* Created on Apr 8, 2004
*
* Reviewed By | Review date |Modified By | Modified date | Modification
* - - - - - - + - - - - - + -- - - - - -+ - - - - - - - + - - - - - - - -
* | |Willem Voogd | Apr 8, 2004 | Initial Creation
*/
package org.mmbase.examples.howtos.builders;
import java.util.List;
import org.mmbase.module.core.MMObjectBuilder;
import org.mmbase.module.core.MMObjectNode;
import org.mmbase.util.functions.Parameter;
/**
* PersonBuilder
* @author willem
*
* The PersonBuilder is the source class voor the Person builder.
* It suplies a function that says Hello to the person.
*/
public class PersonBuilder extends MMObjectBuilder {
public static final String F_GREETING="hello";
/**
* Says hello.
*
* @param node, the node (menuitem) for which the string must be build.
* @return helloString, the greeting.
*/
protected String getGreeting(MMObjectNode node) {
String helloString = "Hello ";
helloString += node.getStringValue("name");
return helloString;
}
/**
* overridden from MMObjectBuilder
*
* Gets the parameters for the functions.
* We only have one custom function w/o parameters, so we need an empty array.
*/
public Parameter[] getParameterDefinition(String function) {
if (function.equals(F_GREETING)) return new Parameter[0];
return null;
}
/**
* overridden from MMObjectBuilder
* executes a given function and returns the result of that particular function.
*
* @param node
* @param function
* @param arguments
*/
protected Object executeFunction(MMObjectNode node,String function,List arguments) {
if (function.equals(F_GREETING)) {
return getGreeting(node);
} else {
return super.executeFunction(node,function,arguments);
}
}
}
]]></programlisting>
</para>
</section>
<section>
<title>The JSP file</title>
<para>In order to call the function we have to use the <computeroutput>
<mm:function /></computeroutput> tag inside the jsp. When you are
already in a node it can be done by just calling the name for the
function, as it is wrapped by executeFunction.</para>
<para>
<programlisting format="linespecific"><![CDATA[
<[EMAIL PROTECTED] uri="http://www.mmbase.org/mmbase-taglib-1.0" prefix="mm" %>
<[EMAIL PROTECTED] session="false" %>
<html>
<body>
<mm:import externid="person">johndoe</mm:import>
<mm:cloud name="mmbase">
<mm:node number="$person">
<mm:function name="hello" />
</mm:node>
</mm:cloud>
</body>
</html>
]]></programlisting>
</para>
</section>
<section>
<title>The Application</title>
<para>
Hello.xml:
<programlisting format="linespecific"><![CDATA[
<?xml version="1.0"?>
<!DOCTYPE application PUBLIC "-//MMBase/DTD application config 1.0//EN" "http://www.mmbase.org/dtd/application_1_0.dtd">
<application name="Hello" maintainer="mmbase.org" version="0" auto-deploy="true">
<neededbuilderlist>
<builder maintainer="mmbase.org" version="0">persons</builder>
</neededbuilderlist>
<neededreldeflist>
</neededreldeflist>
<allowedrelationlist>
</allowedrelationlist>
<datasourcelist>
<datasource builder="persons" path="Hello/persons.xml" />
</datasourcelist>
<relationsourcelist>
</relationsourcelist>
<contextsourcelist>
<contextsource path="" type="full" goal="fullbackup"/>
</contextsourcelist>
</application>
]]></programlisting>
</para>
<para>
persons.xml:
<programlisting format="linespecific"><![CDATA[
<?xml version="1.0" encoding="utf-8"?>
<persons exportsource="mmbase://127.0.0.1/builderclass/mm" timestamp="20040408144622">
<node number="28" owner="admin" alias="johndoe">
<name>John Doe</name>
</node>
</persons>
]]></programlisting>
</para>
</section>
</section>
<section>
<title>Deployment</title>
<para>To deploy the application, first do the normal MMBase install stuff,
then create a structure like this:
<programlisting format="linespecific"><![CDATA[
- Hello.xml
- [Hello]
- [builders]
- persons.xml
- persons.xml
]]></programlisting>
Where the names between brackets ([]) are
directories and the persons.xml file directly under the Hello directory
is the data file.
</para>
<para>Place both the Hello directory and the Hello.xml file directly in the
WEB-INF/config/applications directory and put the helloperson.jsp in the
home directory of the webapp.</para>
</section>
<section>
<title>How does it work?</title>
<para>The <computeroutput><mm:function /></computeroutput> tag
results in a call to executeFunction() on the class specified in the
classfile tag in the builderfile for the node the function is called
upon. However, before that call takes place, first a call to
getParameterDefinition is made, which for PersonBuilder results in an
empty List. PersonBuilder.executeFunction(node, “hello”, list) is called,
where 'node' is the node in who's scope the function tag is placed.
</para>
<para>executeFunction is a wrapper for the function we actually want
called, being getGreeting. The result is passed back to the jsp,
resulting in 'Hello John Doe'.</para>
</section>
<section>
<title>Next Steps</title>
<para>Of course, the example given in this how to could more easily be
implemented, not needing a custom java builderclass. This is the most
basic example of how to add custom functionality to your builder. You
could also make the greeting intelligent, wishing the person a
goodmorning, goodafternoon, goodevening or goodnight, depending on the
server's system time, for example.</para>
<para>In the next how to we will deal with parameters. </para>
</section>
</article>
