Table of Contents
MMBase datatypes are defined in the resource <MMBase
configuration>/datatypes.xml
. See the Xml Schema Definition, for a
formal description of this XML format. This resource can exist multiple times, but there is
at least one in mmbase.jar. The contents of that one are described in Section 7, “Summary of default datatypes”
Other jars (e.g. of MMBase components) can also provide such a datatypes.xml, which will also be read in, and added to the repository of available datatypes.
Of course you can also place your own datatypes.xml, e.g. just in WEB-INF/config.
On a running MMBase you can see which datatypes are available in /mmbase/validation/. See e.g. at /mmbase/validation at the mmbase.org site.
A datatypes.xml
basically contains a list of 'datatype' entries. E.g.
<?xml version="1.0" ?> <datatypes xmlns="http://www.mmbase.org/xmlns/datatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mmbase.org/xmlns/datatypes http://www.mmbase.org/xmlns/datatypes.xsd"> <datatype id="integer"> <description xml:lang="en"> Not so very big integer numbers. Common base for all kind of enumerations. </description> <class name="org.mmbase.datatypes.IntegerDataType" /> </datatype> ...There are only a limited number of data types which can be defined like 'integer' in this example. Namely only the database types of MMBase (string, integer, binary, float, double, long, xml, node, datetime and boolean). All other datatypes are based on one of those. This can be done in two ways. As a sub element 'specialization':
<datatype id="float"> <specialization id="scale1-10"> <description xml:lang="en">A scale from 1 to 10.</description> <minInclusive value="1.0" /> <maxInclusive value="10.0" /> </specialization> </datatype>or as a 'datatype' element with a 'base' attribute.
<datatype base="float" id="scale1-10"> <description xml:lang="en">A scale from 1 to 10.</description> <minInclusive value="1.0" /> <maxInclusive value="10.0" /> </datatype>
It is also possible to replace a data type, by extending from the data type with the same
id. This is only feasible in WEB-INF/config/datatypes
because that one
is parsed last.
<!-- In this site, email addresses are required --> <datatype base="emailaddress" id="emailaddress"> <required value="true"> <description xml:lang="nl">Je moet een emailadres intypen</description> <description xml:lang="fr">Un address courriel est requis</description> <description xml:lang="en">An email address is required</description> </required> </datatype>
In the following subsections we will elaborate a bit on the possible sub-elements of a datatype (or 'specialization') element.
With every data type a default value is associated. E.g.
<datatype id="integer"> <specialization id="colors"> <description xml:lang="en"> colors as can be used in css </description> <default value="white" /> <enumeration> <entry basename="org.mmbase.datatypes.resources.string.colors" /> </enumeration> </specialization>The value is implicitly cast to the correct type. In this case 'white' can be converted to an integer, because there is a mapping present in the defined enumeration.
If the class of the data type supports properties which are not recognized by the data type XSD (as described in this document) then arbitrary properties can be set using 'property' sub elements.
<specialization id="confirmpassword"> <description xml:lang="en"> This is a field datatype that of which the value is only valid, if it is equal to the value of another field in this node. The other field's name is default 'password' but it can be changed by overriding the property 'field'. </description> <class name="org.mmbase.datatypes.ConfirmPasswordDataType" /> <property name="field" value="password" /> </specialization>In this case, the 'ConfirmPasswordDataType' class has a 'setField' method which is called when this data type is instantiated.
<specialization id="emailaddress"> <description xml:lang="en"> The valid values of such a field must be a valid email address. The current implemenation is by a rather simple regular expression. </description> <pattern value="(?i)\A[A-Z0-9_\-\+\&\*\#]+([\.-]?[A-Z0-9_\-\+\&\*\#])*@([A-Z0-9_-]{2,}[\.]{1})+([A-Z]{2,})\z"> <description xml:lang="nl">'${VALUE}' is geen geldig email adres</description> <description xml:lang="en">'${VALUE}' is not a valid email-address</description> <description xml:lang="fr">'${VALUE}' n'est pas un correct address courriel</description> <description xml:lang="eo">'${VALUE}' ne estas korektforma retadreso</description> </pattern> </specialization>As you see, token replacement is done. Currently, NAME, VALUE, CONSTRAINT and CONSTRAINTVALUE are recognized. No java.text.MessageFormat features are yet supported.
A value can be marked to be 'unique'. This can only be applied if the data type is associated with a field (See also Section 3, “How to associate a data type with a field”) Of course this means that that values which are already present, are not valid any more for new objects.
<datatype base="datetime" xmlns="http://www.mmbase.org/xmlns/datatypes"> <default value="now" /> <minExclusive value="today - 3 day" enforce="oncreate" /> <maxInclusive value="today + 100 year" enforce="onchange" /> </datatype>As you can see, these minimal and maximal values can be set -Exclusive or -Inclusive, with the obvious semantics.
Most datatypes are comparable. But e.g. not binaries or xml's. It is most logical for dates, and numerics. For strings it indicates alphabetic ordering (I have yet to encounter the first serious use of a restriction on minimal or maximal value of a string field)
<datatype base="binary" xmlns="http://www.mmbase.org/xmlns/datatypes"> <minLength value="3" /> <maxLength value="10000" /> </datatype>If minLength and maxLength are equal, you can simply use 'length'.
A minimal length of '1' is often a bit confusing, because that means approximately the same as 'required'. Especially when using taglib generated input-fields. Taglib interprets the empty string as 'null' if the value is not required. So, it is adviced to use the 'required' restriction if you find that content for this data type is essential.
<specialization id="password"> <pattern enforce="never" value="\A[^\n\r]*\z" /> <!-- cannot contain newlines --> <password value="true" /> .. this would work too: <specialization id="password"> <property name="password" value="true" ?> <pattern enforce="never" value="\A[^\n\r]*\z" /> ..
<specialization id="spells"> <!-- example to test --> <enumeration> <entry value="1" xml:lang="nl" display="hokus pokus" /> <entry value="2" xml:lang="nl" display="simsalabim" /> <entry value="3" xml:lang="nl" display="pilatus pas" /> <entry value="4" xml:lang="nl" display="abcracadabra" /> <entry value="2" xml:lang="en" display="simsalabim" /> <entry value="3" xml:lang="en" display="pilatus pas" /> <entry value="1" xml:lang="en" display="hocus pocus" /> </enumeration> </specialization>You can see that you can enter the same value more than once, for different languages. The default value to display is the value itself, so it is not needed to specify localized display values.
Enumerations are most often used on data types with 'base="integer"', but can also work on string data types, and node data type (using 'query').
An enumeration is a restriction, but or course it is mainly a powerfull hint to produce a user interface using e.g. a dropdown list or so.
It is also possible to specify the possible value using a ResourceBundle.
<enumeration > <entry basename="org.mmbase.datatypes.resources.weekdays" /> </enumeration>where the weekdays resource bundle could look something like this:
0=sunday 1=monday 2=tuesday 3=wednesday 4=thursday 5=friday 6=saturdayIf you look in the
datatypes.xml
in mmbase.jar
you will find that this 'weekdays' enumeration actually defined like this<enumeration> <entry basename="org.mmbase.datatypes.resources.weekdays" javaconstants="java.util.Calendar" /> </enumeration>This indicates that the keys of the resource bundle are resolved to the actual values using constants in the given java class. This results in that the resource bundle can look like this:
SUNDAY=sunday MONDAY=monday TUESDAY=tuesday WEDNESDAY=wednesday THURSDAY=thursday FRIDAY=friday SATURDAY=saturdayWhich looks of course a lot nicer.
<datatype base="long" xmlns="http://www.mmbase.org/xmlns/datatypes"> <enumeration> <entry sorterclass="org.mmbase.util.ReverseComparator" basename="org.mmbase.notifications.resources.offset" /> </enumeration> </datatype> TUESDAY=tuesday WEDNESDAY=wednesday THURSDAY=thursday FRIDAY=friday SATURDAY=saturday
<enumeration> <entry sorterclass="org.mmbase.util.SortedBundle$ValueWrapper" basename="org.mmbase.datatypes.resources.iso639" /> </enumeration>
<specialization id="created"> <description xml:lang="en"> Read-only date-time field that contains the time of creation of the node. </description> <default value="now" /> <setprocessor> <class name="org.mmbase.datatypes.processors.Readonly" /> </setprocessor> <getprocessor type="*"> <class name="org.mmbase.datatypes.processors.CreationTimeGuesser" /> </getprocessor> <getprocessor type="string"> <class name="org.mmbase.datatypes.processors.CreationTimeGuesser" /> <class name="org.mmbase.datatypes.processors.FormatDateTime" /> </getprocessor> </specialization>Using the 'type' attribute one of the MMBase database type can be associated with get- and setprocessors. Those database types also correspond to methods in the MMBase bridge 'Node' interface. In this case we see that when getting a value as a string ('getStringValue'), something else happens then when it is gotten otherwise ('getDateValue'). In this case the creation time is nicely formatted when the value is requested as a string.
The CreationTimeGuesser processor arranges that if the value is empty, it guesses an actual value using the MMBase 'day markers'.
In this example, there is also hooked in a class on the set-processor. Namely the processor which simply refuses the action, effectively leading to a read-only field. (The CreationTimeGuesser itself can use 'setObjectValue' to bypass all set-processors, if it wants to store its guessed value for efficiency).
You can specify more than one class for a certain processor. They will be 'chained' in such a case.
The class may also implemented org.mmbase.util.transformers.CharTransformer (or factory), in which case an instance of that class is simply wrapped into a Processor, which only transforms the value.
The instances of the processors can be configured with 'param' subtags.
<specialization id="lastmodified"> <description xml:lang="en"> Read-only date-time field that contains the most recent time at which this node was changed . </description> <setprocessor> <class name="org.mmbase.datatypes.processors.Readonly" /> </setprocessor> <commitprocessor> <class name="org.mmbase.datatypes.processors.LastModified" /> </commitprocessor> ..So, on commit, the 'LastModified' processor is called, which simply fills the current time into the value of the field with this data type.
<field> <datatype xmlns="http://www.mmbase.org/xmlns/datatypes" base="lastmodified" /> <db> <name>updated</name> <type key="false" notnull="false" state="system">DATETIME</type> </db> </field>
which can also be noted like this.
<field name="updated" state="system"> <datatype xmlns="http://www.mmbase.org/xmlns/datatypes" base="lastmodified"> <required value="false" /> <!-- this is btw also the default --> </datatype> </field>
Since MMBase 1.8.5, the meta information provided by MMBase Data Types can also be accessed using JavaScript. For that you include the javascript file /mmbase/validation/validation.js.jsp, plus some other utilities (see /mmbase/valiation/test.jspx), and instatiate an "MMBaseValidator".
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Test</title> <jsp:directive.include file="/mmbase/validation/javascript.jspxf" /> </head> <body> <script type="text/javascript">new MMBaseValidator(window);</script> ... the rest of your page..
This javascript library searches (on load) all form elements with the class "mm_validate". 'onkeyup' events are added to all those elements.
The data type is determined by inspecting the css class names. If one starts with "mm_dt_" then the remaining is interpreted as the MMBase Data Type id. There can also be two class names, one starting with mm_f_ and mm_nm_ which can together identify the datatype of a certain field of a nodemanager.
The mm:fieldinfo tag of the MMBase Taglib will set up the correct CSS class for form elements that it creates.
As soon a data type meta information is needed, then this is requested (using 'ajax') with a call to /mmbase/validation/datatype.jspx. The resulting XML's are cached in MMBaseValidator.
This is part of the MMBase documentation.
For questions and remarks about this documentation mail to: documentation@mmbase.org