Makumba Specification

Data Definition Language

(the Makumba abstract level)

Types, objects, databases

Data definitions describe data types (or classes). They are placed in files contained in directory hierarchies, and the directory name is part of the type name (similar to Java packages). For example the file best/Student.mdd describes the type best.Student. Type names can contain letters, digits, underscores and dashes and cannot contain slashes and dots. Usually, the directories are used to separate organisations and projects.

Current Java implementation finds the data definition files as follows:
  • the designated file extension is .mdd (Makumba Data Definition)
  • relative to CLASSPATH (e.g. classes/best/Student.mdd)
  • in a directory called "dataDefinitions/" in the CLASSPATH (e.g. classes/dataDefinitions/best/Student.mdd)
  • OLDSTYLE: if no mdd file is present, the no-extension file (i.e. best/Student) is looked up

Data objects (records) are stored in databases.

The actual implementation of the database is not part of this specification but implementation suggestions will be made. Data can be copied and/or replicated between different databases, even between different DB engine types.

Replication is not yet implemented, but the design is prepared for it. Copying works.

Fields

Every data definition file contains field definitions, separated by newline.

A field definition looks like:

fieldname= [attributes] fieldtype [parameters] [; description]

 

default values are supported internally, but not by the mdd parser
As an implementation guideline, field names tend to stay approximately the same in:
  • http requests
  • Record instances (java.util.Dictionary in the current Java API)
  • database columns
  • etc

(Automatic labeling: The field description might be used at interface levels to present that field. It is typically shown at the left of, or somewhere near to, the input control (text box, radio button, chooser, etc) that allows for data input in that field. If a field description is not present, its field name stands for its description by default.)

Comment lines can be inserted in the data definition files as follows:

# your comment...

Default fields

Every datatype has some additional fields by default, as follows:

  • Primary Key field, consisting of two parts [DBSV with 8 bits | UID with 24 bits]:
    • Database identifier (DBSV). It is unique (within the webapp) per database. All objects created thru that webapp and in that database get the same value. It is set by property dbsv in the database config file.
    • Object identifier (UID): unique id for the object in the given database.

    This combination ensures that no two objects of one type have the same primary key field. See how to configure this.
    The name of the primary key field is the same with the last part of the type name. If another field by that name is defined by the makumba user, this field will be renamed in the database.
  • Object creation time
    Can be accessed as TS_create.
  • Last modification time. Updates whenever the object is changed. The initicial value is TS_create.
    Can be accessed as TS_modify.

Simple field types

int

A 32-bit integer. For example

shoeSize= int; Shoe size

If the int can have a limited number of values, it can be described as follows

gender= int{ "male"=0, "female"=1 }; Sex

This will help the presentation layer to present a suitable input control (e.g. )

"deprecated" can be used in this way to denote a deprecated option:
userType = int{"type1"=10, "type2"=10,"old"=0 deprecated}
In the present implementation, this type is called "intEnum" internally.
Negative numbers are supported (e.g. int { "aa"=5, "bb"=2, "cc"=-10}).

real

A real number with double precision with (2-2-52)·21023 as max value and 2-1074 as min value. For example:

high= real; high of a person

char

A char field contains a number of characters. Maximal width must be specified and is limited to 255. (Optionally a minimal number of characters (lesser than max) can be indicated). Both must be positive integers. For example:

#fieldName= char[maxWidth]
name= unique char[80]; Username password= encrypted char[6..10]; Secret password

"unique" and "encrypted" are field attributes, explained below.

Pay close attention to the character set (charset) for encoding the characters. In Java the charset is Unicode, but the JSP/HTML pages have their own encoding settings, as well as the database, etc.

DEPRECATED (use int{...} instead): If the char can have a limited number of value, it can be described as follows

gender= char{ "male", "female" }; Sex

This will help the presentation layer to present a suitable input control (e.g. a HTML SELECT)

in the present implementation, this type is called "charEnum" internally

boolean

A boolean, that can take as values true or false. For example:

hasChildren= true; whether this person has children

text

An unlimited-length string of characters. This type is designed to accommodate large text content. It is implemented with LONGTEXT or its counterparts, depending on the underlying DB engine. The text data-type is ready for accepting data in UTF-8 encoding.

application= text ; Application letter
description=text ; Description of object

binary

An unlimited-length field designed for binary content. In contrast to the text data type, binary will always be of 8 bit length. It is implemented with LONGTEXT or its counterparts, depending on the underlying DB engine. This type is meant for storing only raw binary data, for storing files along with meta-data like a file name, content type, etc., you should rather use the file data type.

singature= binary    ; a binary digital signature

date

A date and/or time.

birthdate= date; Date of birth
arrivalTime= date; Arrival time

Structural (relational) types

Pointers (ptr)

Pointers define a reference to an object of a certain type. For example

citizenship= ptr general.Country; Citizenship
the ptr keyword might be ommitted in future parsers

The type can be defined on-the-spot for a single usage. For example

addres= ptr ; Address
address->street= char[80]; Street
address->number= int; Number
The main difference between sets of external types and internal sets is that when the host object (e.g. Person.mdd that has the above field "address") is deleted from the database (DB), also all elements of the set (addresses) are deleted automatically, so there is no orphans (addresses) in the DB. Elements (addresses) of an internal set of some host object (Person X) also can't be used in a set of some other host object (Company Y).
future parsers might read this:
address= ptr{
street= char[80]; Street
number= int; Number}; address
this type is known internally as ptrOne

Sets (set, bag, list)

Sets define a number of references to multiple objects of a certain type. For example:

language= set general.Language; Spoken languages

This type accomodates sets, bags and lists. The set and list constraints (sets have to contain only one element of a certain value and lists have to be ordered) have to be cared for by the programmer. Lists are easy to represent, just having an integer field, for the order.

The type which the set is made of can be defined on the spot:

addresses= set; Addresses
addresses->street= char[80]; Street
addresses-> number= int; Number
the future parser might recognize this form:
addresses: set{
street: char[80]; Street
number: int; Number }; Addresses
this type is known internally as setComplex

The set can contain enumerated int values :

place= set int {"home"=1, "away"=0} ; Home or away
this is currently known internally as setintEnum

DEPRECATED: The set can contain enumerated char values :

place= set char {"home", "away"} ; Home or away
It means that place is a set that can take only the "home" and "away" values.
This is currently known internally as setcharEnum

File

A file data-type is a kind-of record containing several fields needed when wanting to store files. These fields are:

  • content (binary): the actual binary data of the file.
  • name (char): the file name.
  • originalName (char): the original file name.
  • contentType (char): the MIME content-type of the file.
  • contentLength (int): the content length in byte.
  • imageWidth (int): (only for images) the image width.
  • imageHeight (int): (only for images) the image height.
image= file    ; Picture attachment

All fields are automatically set by Makumba, all needed to do is to make a <mak:input> on the field name.

This type should be used in favour of the binary data type when you don't want to store only the raw binary data, but also meta-data as in the fields above.

Macro types

A name can be defined for a more complex type and it can be reused in the file. This can be done with a !type directive

!type.yesno= int{"yes"=1, "no"=0}
!type.rank= int{"neutral"=0, "very good"=5, "very bad"=-5}
married=yesno
happyInLife=rank

Field attributes

  • fixed fields can only set during the record's insertion in the database. The subsequent updates will not update the field
  • not null fields will produce a exception if an attempt is made to insert/update without them being initialized
  • unique fields have a unique value in the respective object, for the respective type
  • (encrypted fields are encrypted when written to the database and decrypted when read)

Object title

The object title is used for set and ptr choosers

One of the fields is always the object title, and is normally presented differently from other fields in user interface. For example, when you have a field that is a set and you use a mak:input on that field, Makumba will automatically create a list with all the items in the set and it will use the object title to know what field to display. The default is the field called "name" if that exists, otherwise it is the first non-pointer field in the record description. If another field needs to be title, it can be specified like

!title=gender
for the on-the spot types in the current implementation, the following notation works:
address->!title= street

Include mechanism

A record description can include text from one or more files. This is declared as

!include=name_of_included_type

The included file has the idd extension and is found in a similar way like the data definitions.

The included file is inserted instead of the !include line. There can be more include lines in a record description file. If a field is defined that exists also in the included metadata, the defined field takes precedence. If

fieldname=

it means that it does not actually exist. this can be used to cancel an included field.

include might be replaced by more advanced concepts such as inheritance and type inclusion (rather than reference in foreign table)

Validation Rules

Validation rules are defined inside a data definition, and allow Makumba to automatically validated form data input.

The general syntax of a validation rule definition is as follows:

[fieldName or ruleName]%[ruleType] = [validation rule] : [error message]

FieldName / ruleName and ruleType

For validation rules that operate on one specific field only, you have to use the name of the field; this applies to number range, string length and regular-expression rules. For other rules, instead of a field name, you specify the validation rule name, which serves an identifier which should be unique. The exact usage of the identifier is not yet specified, but it could be used in the future to centralise error messages or provide translations into other languages, etc.

The ruleType can be one of the following: [range | length | matches | compare | unique]

Validation rule

The validation rule specifies what should be validated, and can be one of the following

[range validation | string length | regular expression | comparison | multi-field uniqueness]

Number range rule

The range definition rule applies for Number types, i.e. int and real. The [validation rule] is defined as:

[fieldName]%range = [1..10]

Using ? allows to keep one parameter unbound, which will default to java.lang.Integer.MIN_VALUE and java.lang.Integer.MAX_VALUE, respectively, i.e. +/- 231-1.

To require that the age needs to be between 12 and 99:

age%range = [12..99] : Age must be between 12 and 99!

To define that we need to be at least 5 year old, but without any upper limit:

age%range = [5..?] : Age must be at least 5!

String length rule

The length definition rule is very similar to the range definition, but applies for string types, i.e. char and text. The [validation rule] is defined as:

[fieldName]%length = [1..10]

Using ? allows to keep one parameter unbound, which will default to a minimum length of 0 and a maxium length of 255

To define that the CV needs to be at least 100 characters, define:

cv%length = [100..?] : CV must be of decent length!

Regular expression rule

The string regular expression rule applies for string types, primarily for char, but also for text. The [validation rule] is defined as:

[fieldName]%matches = regular expression

Regular expressions must be valid regular expressions in Java, for more details please refer to the specification and tutorial.

To compare if a field contains a valid e-mail address, define:

email%matches = .+@.+\.[a-z]+ : Email address is not valid!

Comparison rule

This rule allows to compare a field to a constant value or simple function calls.

The following constants are currently available:

Constants Description Valid
$now The current date and time. date types
$today The current date, time set to 00:00.

The following functions are currently available:

Function Description Valid
$date(.., .., .., .., .., ..) Constructs a date.
The function takes up to six arguments, for day, month, year, hours, minutes and seconds. If less than six arguments are passed, the missing values will be automatically set to the current date.
$now is available as a constant for the current date value, and + and - operators can be used to modify that value. e.g.
date($now,$now,$now - 5)
evaluates as the current date 5 years ago.
date types
lower(..) Converts a string to lower case. String, i.e. 'char' and 'text' types
upper(..) Converts a string to upper case.

Valid comparison operators are the ones defined in Java:

Operator Meaning
== equal
!= not equal
< less than
> less than
=< less than or equal
>= greater than or equal

To compare if someone is at least 15 years old, define the following validation rule:

minimumAge%compare = birthdate >= date($now,$now,$now - 15) : You have to be at least 15 years old!

To ensure that a field doesn't contain only lower-case values, define this rule:

nameNotAllLower%compare = lower(name) != name : Your name must not contain only lower-case letters!

Two fields can be compared in a similar way

graduationCheck%compare = birthdate < graduationDate : You cannot finish school before your birthdate!

Multi-field uniqueness definition

Similar to the unique field attribute, you can also define multi-field uniqueness contraints. These constraints can even span over several data definitions, if they are related via pointers.

Multi-field uniqueness can be defined as follows

uniqueAgeEmail%unique = age, email : the combination of age and email must be unique! 

If the fields are in the same data definition, the uniqueness definition will translate into a database level multi-field key and uniqueness will be enforced there.
Otherwise, Makumba will issue a query checking the uniqueness before new or edit operations.

Error message

The error message that will be displayed if the validation fails.

Query languages

MQL

As of Makumba version 0.8.1., the default query language is 'MQL', Makumba Query Language. MQL builds upon Hibernate's HQL.

MQL Functions

MQL provides support for functions that will translate into SQL functions. Currently, the following functions are supported:

String functions
name argument(s) result type description
lower (str) string Converts the string argument to lower case
upper (str) string Converts the string argument to upper case
trim (str) string Remove leading trailing spaces.
ltrim (str) string Remove leading spaces.
rtrim (str) string Remove trailing spaces.
concat (str1, str2, ...) string Concatenates two or more strings
concat_ws (separator, str1, str2, ...) string Concatenates two or more string with the given separator
substring (str, position [, length]) string Takes a substring of the given string
format string string Left-trim on the string argument
reverse (str) string Returns the string str with the order of the characters reversed.
ascii (str) int Return numeric value of left-most character.
character_length (str) int Return number of characters in the string argument.
regexp expr regexp patt int (0, 1) Performs a pattern match of a string expression expr against a pattern patt. For example:
SELECT 'makumba!' REGEXP '[a-z]*'; 
 -> 1
Date functions
name argument(s) result type description
dayOfMonth (date) int Return the day of the month (0-31).
dayOfWeek (alternatively: weekday) (date) int Return the weekday index of the argument.
week (date) int Return the week number.
dayOfYear (date) int Return the day of the year (1-366).
year (date) int Return the year from the date argument.
month (date) int Return the month from the date argument.
hour (date) int Return the hour from the date argument.
minute (date) int Return the minute from the date argument.
second (date) int Return the second from the date argument.
extract (unit FROM date) int Extracts parts from the date. For example:
SELECT EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03');
 -> 200907
See the MySQL Documentation for available units.
monthName (date) string Return the name of the month.
dayName (date) string Return the name of the day.
date_add (date, INTERVAL expr unit) date Adds expr times the unit to the date. For example:
SELECT '2008-12-31 23:59:59' + INTERVAL 1 SECOND;
 -> '2009-01-01 00:00:00'
See the MySQL Documentation for available units.
date_sub (date) date Substracts expr times the unit to the date. See date_add.
last_day (date) string Return the name of the day.
current_date date Return the current date.
current_time date Return the current time.
current_timestamp (alternatively: now) date Return the current date and time.

Support for new functions is normally easy to add, so if you miss specific functions, please just mail the makumba developers!

OQL

Before Makumba version 0.8.1, the default query language was OQL. OQL is similar to SQL, a specification can be found at http://www.odmg.org (or check this PDF). Makumba recognized a subset of OQL, which it translated to the host SQL when necessary. The following language was accepted ([] means optional, {} means any number of repetitions):

SELECT expression [[AS] label] {, expression [[AS] label] }
FROM {type [AS] label | label.field{.field} [AS] label }
[ WHERE expression
[ GROUP BY expression {,expression}
[ HAVING expression {,expression} ]
]
]
[ORDER BY expression {,expression} [(ASC|DESC)] ]

Notations like label.field{.field} only allow "field" to be of pointer type in expression and set type in FROM. In expressions, also label.ptr{.ptr}.simplefield is valid.

If a label, representing a type, appears alone in an expression, a default field will be added. The default field depends on the type of the label:

  • for set XXX types (sets of foreign objects), the label denotes the pointer to the set member
  • for set int { } and set char { } types, the label denotes the set member (i.e. and int or a string)
  • for all other types, the label denotes the pointer to that object
In OQL, NULL values are named 'nil', example
ms.account_active=1 OR ms.account_active=nil
In the future, the MDDs should use 'nil' instead of null, e.g. nickName = not nil char[20]

Hibernate Query Language - HQL

Makumba also integrates Hibernate, thus allowing to take full advantage of hibernate's query language HQL. For documentation, please see the Hibernate Query Language BNF.

To enable Hibernate in JSP pages, you have to import a different TLD than normally:

<%@ taglib uri="http://www.makumba.org/view-hql" prefix="mak" %>

Query Fragments

Makumba focuses on combining query fragments to obtain high-performance systems with a minimum number of queries sent to the database back-end, while keeping its concerns about easy learnability and rapid development. The mak:list engine already combines query fragments for embedded mak:lists by combining their FROM and WHERE sections, but we found a need for a better formalization and sharing of query fragments across the sytem. The elementary concept of such formalization is the MDD function.

MDD Functions

A simple function for an MDD called Leveler that has a level integer field looks like

level=int

function(int a) { level+a }
In principle, a function is inlined in queries whenever it is encountered in a SELECT projection or WHERE condition as follows:
SELECT label.function($param) FROM Leveler label
The above query is inlined like this:
SELECT label.level + $param FROM Leveler label

Some properties of MDD functions:

  • If the underlying query language allows it, functions can use subqueries.
  • If functions wish to refer to the owner object, functions can use this which will be inlined with the label or the expression denoting the object in the query
  • If a function is not using MDD fields at all, then it is static and can be invoked like MDDname.function(params)
  • If functions wish to define labels, they can use a FROM section and if needed a WHERE section to constrain the labels defined.
In principle it is possible to translate the functions into database-level stored procedures or equivalent but a lot can be achieved already just by inlining the functions.

The main uses of MDD functions are:

  • reuse of query code
  • query simplification and improved lisibility
  • authentication using well-known function names
  • authorisation using well-known function names
  • data view using well-known function names

Function specification

The complete specification of function definition is as follows:

[sessionVar%]function([type parameter]*){ expression [FROM supplementaryLabels [WHERE condition]]} [errorMessage] [; comment]
  • sessionVar may be used for MDDs that define actors (or those related to them) to indicate the name of a session variable where the function result will be stored. This is only possible for functions with no parameters. (this is currently implemented but may be deprecated)
  • parameter type can be either the primitive types (int, char, date, text, binary, boolean) or an MDD name
  • expression is a query language expression and may use MDD field names, this, function parameter names, supplementary labels (see below), other functions calls, actor invocations and $attributes from the query context
    • Since functions are inlined, recursive calls are not possible
      (this is not yet checked though)
    • $attributes are discouraged because using them would mean counting on "global variables", it is advised that they are passed as function parameters (in case of e.g. page parameters or page/request attributes), or that actor invocations are used to retrieve session attributes
  • supplementaryLabels may need to be defined, in which case a normal query language FROM section is used
  • sometimes conditions are needed to join the supplementary labels with this.
  • if the function is boolean and returns false, an error message will be needed to construct an exception e.g. when an actor() function fails (UnauthenticatedException) or when a canRead() function fails (UnauthorizedException). If that functions calls other functions, their error messages might be composed to provide a more accurate reason for failure.
A static keyword may be added to function definitions.
A return type may be added to function definitions.

actor(MDDname) invocations and actor() functions

Actors are a special type of function that, when mentioned in queries or functions, may trigger authentication. An actor invocation looks like

actor(MDDName)

and a query invoking it may be

SELECT actor(Person).name 
SELECT obj.hasDoneJob(actor(Person)) FROM SomeType obj

These queries are inlined as follows:

SELECT actor_Person.name FROM Person actor_Person WHERE actor_Person=$actor_Person
SELECT obj.hasDoneJob($actor_Person) FROM SomeType obj 

(in the second example, the function hasDoneJob() will be inlined further)

$actor_Person is a special attribute retrieved from the query context. The query context handler will check for the attribute and if it is not defined, it will look in the MDD indicated by the actor attribute name (Person) for actor functions. Assuming that Person has a username and a passoword field, some actor functions may look like

username=char[255]
password=char[255]
actor(char[] user){username=user }
actor1(char[] admin){ username=admin }
actor2(char[] user, char []pass){ username=user AND password=pass }

First, the context handler will look for a suitable function to use. For example if the attribute user is defined in the context, the first function (actor()) will match. However if both the attributes user and pass are defined in the context, the actor2() function will match (so the function with most matching parameters will be chosen). Finally, if the admin attribute is found, the actor1() function will match.

The functions above correspond to different authentication mechanisms that may be used. The first two functions use an external authentication mechanism, where the role of a correctly authenticated user is provided. In such a case, the Makumba query context handler will define an attribute with th role as name (user, admin) and the username as value. The third function (actor2()) will be useful when authentication is managed by the web application (for example using the mak:login feature) and the authentication data is passed as request parameter, in this case they are expected to be called user and pass.

Once a function has been selected (say actor2()) the following query is ran:

SELECT x FROM Person x WHERE x.actor($user, $pass)

which inlines to

SELECT x FROM Person x WHERE x.username=$user AND x.password=$pass   

Once the actor is authenticated, the $actor_Person attribute is put in the session part of the query context. It can be removed using <mak:logout actor="Person" /> . Some fields of Person (the MDD declaring the actor) may also be put in the session, along with the results of functions with no parameters, and along with related objects.

Explicit authorisation constraints

Explicit authorisation constraints are associations between web application paths and query language expressions. When an access is made to a resource whose path matches an authorisation constraint (partial matches supported, longest match considered), the corresponding expression is evaluated. If the expression produces an error (like UnauthenticatedException), that will be handled. If the exception returns 0, false or null an UnauthorizedException is raised with an error message indicated in the constraint.

Currently explicit authorisation constraints can be put in the file MakumbaController.properties. authorisation constraints looks like:

authorize%/={actor(Person)}
authorize%/admin=(char[]admin){actor(Person).username=admin} You are not an administrator 

The first example makes the whole site accessible to users who can authenticate as a Person actor.

The second example makes the /admin part of the site accesible only if there is an admin attribute in the context, and if that is the username of the Person actor. If any constraint fails, an UnauthorizedException will be raised. The second example also shows how to indicate a specific message for the exception, which will then be displayed to the user.

Implicit authorisation constraints (not yet implemented)

Implicit authorisation constraints are defined in functions like canRead(), canInsert(), canUpdate(), canDelete() in the respective MDDs. These functions will be used whenever a mak:list, mak:object or mak:*Form attempts to view, create, change or delete an obect of the respective type. The following features are intended:

  • filter out from mak:list and mak:object objects that the user is not authorized to see, but do not raise any exception if there are such objects.This will probably be the default for mak:list
  • block access to the whole page if the user is not authorized. This will probably be the default for mak:object, and mak:*Form
  • not link to a page that is not authorized

Query execution context

A query execution context is a set of known attributes. In the case of JSP this concept maps on the page, request, and session attributes, as well as request parameters. If however application logic is executed before launching a JSP, the context will be made of the session and request attributes and of request parameters. This is managed by two different query context handlers (implementing the interface Attrributes) and other such handlers can be defined.

Actor functions define a special type of session attributes that are computed based on other attributes from the query context.

Presentation with JSP taglib

Data can be presented and edited per record and field. The current presentation language uses JSP taglibs and corresponding notation, but principles can be applied in any other HTML-centric presentation language such as PHP.

Makumba in Java Server Pages

Makumba offers a JSP custom tag library, that allows easy interaction (viewing, editing) with the data in your database, right from your HTML (actually, JSP) document. Since Makumba pages, are essentially JSP pages, a basic understanding of JSP will be helpful to make more advanced use of makumba. Same goes for knowing a bit of Java itself. But you can get a long way with just a few notions! Really.

Makumba tags are written according to Servlet 2.3 specification and JSP 1.1 specification. You will need a so-called "servlet container" that supports them both, such as Apache Tomcat. The corresponding WEB-INF/makumba.tld is already included in the distribution makumba.jar. The example WEB-INF/web.xml can be found in Makumba cvs repository.

Before using Makumba tags in your JSP pages you also need to declare the taglib with:

<%@ taglib uri="http://www.makumba.org/presentation" prefix="mak" %>

A few resources on JSPs (don't be afraid to try first, read later) :

Makumba Controller

The makumba controller is a component running in the 'servlet container'. When a request for a makumba page enters the servlet container, the controller will intercept the request, and perform its "controller" activities (cfr. the model-view-controller pattern) :

  • checking if the page has the appropriate attributes (see handler initialisation; e.g. force login).
  • checking if the page request is the result of a form submit or a deleteLink. If so, perform the relevant actions in the handler and database.
  • deal with problems (exceptions) during the controller activity:

For this to work, the correct configuration must be applied in WEB-INF/web.xml (example file). The following would tell the makumba controller to filter all requests for .jsp files.

  <filter>
<filter-name>makumba_controller</filter-name>
<filter-class>org.makumba.controller.http.ControllerFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>makumba_controller</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>

Note that if (in this example) the result page for a makumba form would be an .html page, then the makumba controller would not intercept the .html page request, and the actions implied by the form, would not be performed.

JSP tag parameters

JSP-tag parameter values are either FIXED or RTEXPR (runtime expression). A FIXED tag parameter must have a constant, literal value, while an RTEXPR can also be of the form <%= java_expression %>. On the other hand, some FIXED parameters can contain jsp attributes like $attr in makumba tags.

All parameters are optional unless specifically mentioned as being mandatory.

Specific concern can be the parameter quoting. Tag parameters can be written as name="value" or name='value' (note: the stringLiteral on DATE must be quoted with "). The choice of quote can be determined by the need to use either double or single quote as part of the value itself. If the quote is also present within the value, it must be escaped by a backslash.

  <mak:list from="general.Person p" where="p.gender=\"male\"" >
<mak:list from="general.Person p" where='p.gender="male"' >
<mak:list from="general.Person p" where="p.gender='male'" >
<mak:list from="library.Book b" where="b.publisher=\"O'Reilly\" " >
<mak:list from="library.Book b" where='b.publisher="O\'Reilly" ' >

Quotes in extra HTML formatting parameters, such as styleClass, title, styleId, onClick ... need some special attention with quotes. The parameter values are copied verbatim (with no modifications by makumba) to the resulting HTML, always surrounded with double quotes ("). This means that you have to use other quotes, like single one ('),
If you need to pass a literal backslash (\) you have to escape it with a preceeding backslash (\\).

  <mak:input ... onClick="alert(this.value);"/>
<mak:input ... onClick="alert('Hello world!');"/>
<mak:input ... onClick="alert('Hello\\nWorld');"/>

Unfortunately the idea to use a sequence of escapes, eg writing \\\' in the JSP page to set the tag attribute to \', which could be handy for javascript tag attributes, is confusing the Tomcat servlet container.

<mak:response/>

<mak:response/> prints information about the results of the actions that were performed by the makumba controller (e.g. for a form submit or deleteLink): It either displays the message="..." parameter of the form tag (in green) in case of success, or (in red) the message of a uncaught LogicException resulting from Business Logic. Other exception types will provoke an exception page.

The unformatted message is available as request-scope attribute makumba.response. The jsp page can get hold of the message using e.g.

<% String s = (String) request.getAttribute("makumba.response") %>

Similarly, request-scope attribute makumba.successfulResponse is set only in case of successful action execution.

<% if (null == request.getAttribute("makumba.successfulResponse")) { /* action failed */ } %>

(A body-tag style (<mak:response>...</mak:response>) will be added later, to display different messages for different circumstances (errors). It will also be possible to get hold of the actual exception object. )

JSP taglib - listing

<mak:list...>...</mak:list>

Performs a query on the database. The body of the list, if present, is run once for every item in the resulting data (size 0..N), e.g. to display it. Queries are generated on the spot and can be nested.

Example:

<mak:list from="best.Student s, s.person p" where="p.gender=\"male\""
orderBy="p.name">

<c:if test="${mak:count()==1}">
<p> There are ${mak:maxCount()} male students:
</c:if>

<br> <%= counter %>.
<mak:value expr="p.name"/>
<mak:value expr="p.surname"/> <br>
<mak:list from="p.addresses a">
<mak:value expr="a.streetno"/> <mak:value expr="a.city"/>
</mak:list>
</mak:list>

<c:if test="${mak:lastCount()==0}"> There are no male students. </c:if>

tag parameter description comments
db The makumba database to connect to. The format is Host_SQLEngineType_DatabaseName
If not present, the default database is used. See database configuration and lookup.
Fixed, cannot contain attributes, for now.
The default database is chosen if this argument is not set.
Can only be set for top-level (root) query tags
Can be a Rtexpr <%= ...%>
from OQL FROM section. If the query is nested, the keys from the parent's query are added to this FROM section in the resulting query Fixed, Mandatory.
variableFrom supplementary, variable OQL FROM section. Fixed, can contain #{ JSP EL expressions }
where OQL WHERE section. If the query is nested, the WHERE section from the parent's query, is added to this in the resulting query Fixed, can contain #{ JSP EL expressions }
groupBy OQL GROUP BY  section Fixed, can contain #{ JSP EL expressions }
(having) OQL HAVING  section Fixed
orderBy OQL ORDER BY  section Fixed, can contain #{ JSP EL expressions } label.$fieldname used to be supported, not anymore
offset the offset of the result to show (0 for starting from the first result)
Fixed ($attribute allowed). If $attribute is not found, defaults to 0. Only allowed for the outermost mak:list
limit the maximum numbers of results to show (-1 for all results)
Fixed ($attribute allowed). Only allowed for the outermost mak:list. if $attribute is not found, defaults to the value of defaultLimit, if present, or -1 otherwise.
LIMIT can limit the query time dramatically, but the children mak:lists are not yet limited.
defaultLimit the default value for limit, if the $attribute in limit="$attribute" is not present. Fixed ($attribute allowed). Only allowed for the outermost mak:list.
countVar The java.lang.Integer variable that will contain the number of the current iteration. Fixed. A new Java variable is created, so no other variable by the same name can exist in the Java scope at that point in the JSP. Deprecated, use mak:count() expression language function instead
maxCountVar The java.lang.Integer variable that will contain the total number of iterations. Fixed. A new Java variable is created, so no other variable by the same name can exist in the Java scope at that point in the JSP. Deprecated, use mak:maxCount() expression language function instead
separator Character string as separator between two list elements. It is not included before the first or after the last Deprecated, use <c:if test="${mak:count<mak:maxCount()}"> instead.
id Tag's identifier Fixed. Can be used to distinguish otherwise identical tags on a page (to avoid confusion by Makumba's JSP analyser)

<mak:object  ...>.... </mak:object>

Like list, but the query can only have zero or one result. A zero value for maxCountVar and countVar indicate that the object does not exist.

Example: See <mak:list>.

Attributes and OQL in <mak:list > and <mak:object >

Attributes are accessible through $AttributeName to any makumba tag. Typically they will be present in OQL sections instead of $number attributes (therefore the OQL sections of these tags is not "pure"). For example:

<mak:list from="best.internal.Lbg"
where="lbg.country=$country"
orderBy="lbg.$lbg_order">
.....
</mak:list>

If a $ (dollar) sign needs to be in the string, the escape is $$.
If at the end of an attribute there has to be a Java identifier letter, the attribute name can be written as text1$attrName$text2, that is, with $ at both ends.

The http parameters are automatically set as page attributes. Other attributes can be set by the Java code as attributes in any scope (page, request, session, application) using pageContext.setAttribute(name, value, scope).

The query generator is setting all the attributes that are logically possible as prepared query parameters. For example, the $country above is a query parameter since it's a value, but the $lbg_order will not be accepted as query parameter, since it's a field name.

If an attribute has multiple values, it is expanded into multiple OQL parameters. For example:

<mak:list from="best.internal.Lbg" where="lbg.status in set($status)" >

(For view-level attributes such as lbg_order above, the value range can be defined by :
   <mak:defineAttribute name="lbg_order" values="name, id" default="name"/> )

(Later: Maybe the page might want to set attributes. Something like :
   <mak:setAttr name="lbg" from="best.internal.Lbg lbg" where ... scope="session" />
Then the attribute could be used as $lbg in the rest of the page/session/application... Con: such stuff is normally done by the Java code. )

<mak:value  .../>

Displays the value of an expression from within the query.

Example:

<mak:list from="best.Student s, s.person p"
where="p.gender=\"male\"" orderBy="p.name">
<mak:value expr="p.name"/>
<mak:value expr="p.surname"/>
<mak:value expr="p.birthdate" var="birth" printVar="printBirth"/>
<% // we only print the birthdate if it's after some date
if ( ((java.util.Date)birth).after(new java.util.Date(1980, 0, 1)) )
out.print(printBirth);
%>
<mak:value expr="s.person.favoriteQuote" maxLength="60" addTitle="auto" />
</mak:list>

tag parameter description comments
expr OQL SELECT projection expression. It will be displayed if var nor printVar are not specified. Fixed, Mandatory.
var The value of the expression is set to a new java.lang.Object variable by this name, as well as to a page-scope attribute, also by the same name (accessible as $attributename). Fixed. A new Java variable is created, so no other variable by the same name can exist in the Java scope at that point in the JSP.
Note: the Java variable must be cast to its specific type (Integer, String, Date, Text, Pointer, Vector) before using it as such.
printVar The formatted output as it would have been printed, is instead stored in a new java.lang.String variable by this name, as well as to a page-scope attribute by the same name (accessible as $attributename). Fixed. A new Java variable is created, so no other variable by the same name can exist in the Java scope at that point in the JSP.
urlEncode Indicates if the expression will be part of an URL or not. If "true", the output is URL-encoded. Default is "false". Rtexpr.
html Normal behaviour is to transform character output to its HTML escaped form. If this is "true", content is assumed to be HTML, and is not escaped. If "auto", heuristically checks the content for HTML tags and inhibits escape if there are any. Default is "false". Rtexpr. Only char[] and text
format Format string to specify the formatting of a date value, according to java.text.SimpleDateFormat Rtexpr. Only for date. Defaults to "dd MMMM yyyy"
lineSeparator Separator for long lines. If a text consists of short lines only, it will be surrounded by <pre>...</pre>. Default is "<p>". Rtexpr. Only for text. Current implementation is buggy: separator is added before every long line, instead of between every long line.
longLineLength The length of a long line. If a text contains long lines, it will be printed differently. See lineSeparator. Default is "30" Rtexpr. Only for text.
maxLength The maximum length (number of characters) to print. Longer output is cut off, and an ellipsis is added to indicate the cut. If not set (default), there is no maximum. Rtexpr. Only applies for char[] AND if it is not already HTML formatted (cfr. html).
ellipsis The character string to print to indicate that the text extended the maxLength. Default is "...". The final printed string, including the ellipsis, will not exceed maxLength. Rtexpr
ellipsisLength The equivalent character length of ellipsis. By default, this is the number of characters in ellipsis. But if ellipsis is e.g. HTML code, then that is not appropriate. Rtexpr.
Example, the ellipsis is an image of approx 3 characters wide. ellipsis="<img src=icon.gif width=10 height=10>" ellipsisLength="3"
addTitle If "true", add an HTML tooltip with the value, to the printed output. If "auto", add tooltip only if the printed output is cut (cfr maxLength). Default is "false".
Rtexpr. Note: implementated by producing as output: <span title="printVar">possibly-cut-printVar</span>
default The character string to print if the expr results in a NULL value. Default is default="" (i.e. zero-length string)
Support not available for: date, "choice" = ptr, set, setCharEnum
Rtexpr
empty The character string to print if the normal printed output would be empty (i.e. zero-length string). Therefore, this is also used for case expr=NULL and default="". Rtexpr

mak:count(), mak:maxCount(), mak:lastCount()

These are JSP EL (expression language) functions that give information about the iterations in a list.
  • mak:count() gives the number of the current iteration inside a mak:list or mak:object. It has no value outside that tag.
  • mak:maxCount() gives the total number of iterations inside a mak:list or mak:object (1). It has no value outside that tag.
  • mak:lastCount() gives the total number of iterations of the previous mak:list or mak:object, respectively. It has no value inside the mak:list/object.
    Note: if you want to store the value of some mak:list/object for usage in/after a later mak:list/object, you can do that with <c:set var="someVariableName" value="${mak:lastCount()}" just after that mak:list/object.
Example using the Java Standard Tag Library (JSTL, prefix "c"):
<mak:list ...>
<c:if test="${mak:count()==1}">These are the list elements: </c:if>
<tr bgcolor="${mak:count()%2==1?"white":"grey"}">
<td>this shows in alternative colors</td>
...
<c:if test="${mak:count()!=mak:maxCount()}">
a separator where we can have any <b>tag</b>
we don't want separators to be shown after the last element
</c:if>
</mak:list>
<c:if test="${mak:lastCount()==0}">These are no elements </c:if>

<mak:if  ...> ... </mak:if>

Displays the body of the tag only if the OQL expression evaluates to true.

Example :

<mak:list from="best.Student s"
where="s.person.birthdate <> nil" orderBy="s.name">
<mak:value expr="s.person.name"/>
<mak:if test="s.person.hideAge = 0">
was born on <mak:value expr="s.person.birthdate" />
</mak:if>
</mak:list>

tag parameter description comments
test

OQL SELECT  projection expression. It must be a test, resulting in a 'boolean' in SQL : 0 or 1.

for the test expressions: =, !=, <, <=, >, >=

Fixed, Mandatory.
(in first implementation, this was called expr, but changed to reflect practice in XSL and JSTL)

<mak:pagination  .../>

Provides pagination of the results in an enclosing <mak:list>. The tag provides links to the first, previous, next and last item in the result set, and the page number currently displayed.
To achieve this, pagination makes use of the information provided by the enclosing <mak:list>, i.e. the offset and limit, and automatically computes the total of rows that would be returned by the list, if no limit was specified.

Example:

<mak:list from="best.Student s" offset="$offset" limit="$limit" defaultLimit="25" orderBy="s.name">
  <mak:pagination action="studentList.jsp" title="true" itemName="Students" />
  <mak:value expr="s.person.name"/>, born on <mak:value expr="s.person.birthdate" />
  <mak:pagination action="studentList.jsp" title="true" itemName="Students" />
</mak:list>

tag parameter description comments
action The target page to go to when clicking on a pagination link. Rtexpr.
itemName The name of the items displayed, to be used in the text "Showing 'itemName' x out of y (Page z)". Rtexpr.
paginationLinkTitle Whether or not to display title="..." elements on the pagination links. Fixed; defaults to true
styleClass Generic html tag attribute, see newForm

<mak:attribute  .../>

Displays the value of an attribute, or sets it to a Java variable.

Example:

<mak:attribute name="pattern" var="pattern" exceptionVar="exception"/>

<% if (exception!=null) {
pageContext.setAttribute("pattern", (String)pattern+"%");
%>
<mak:list from="type t" where="t.field like $pattern" >...</mak:list>

<% } else { %>
No pattern argument. Please indicate one.
<% } %>

tag parameter description comments
name the name of the attribute. Will be printed if var is not present and there is no exception when finding the argument. If there is an exception but exceptionVar is indicated, nothing will be printed. Fixed, Mandatory.
var The name of the java.lang.Object variable where to store the attribute value. Note that you will have to cast it to its specific type. Fixed
exceptionVar The name of the created java.lang.Throwable variable that will hold eventual exceptions raised when trying to compute the attribute. If exceptionVar is missing, any raised exception will stop page execution. If it is present, and AttibuteNotFoundException occurs, the attribute is set to null (so a next request for the attribute will return null) Fixed
db The database in which the business logic (if any) will compute the attribute. The default database is normally used. Fixed

JSP taglib - Forms

Makumba can produce four types of forms: new, add, edit and generic forms.

All forms have a number of common features: They can include <mak:input > tags. They all can have "action", "method", "handler", "name" and "message" arguments.

Handler methods (if they exist) are executed by the makumba controller, when the form is submitted to another makumba page.

Non-generic (type specific) forms
New, edit and add forms are type specific. Their fields must be named after the fields in the respective type (and related fields).

If there is a business logic class, the engine will look (once after each page compilation) for the corresponding handler method. The handler methods are executed before the default action and may prevent the action from being executed by throwing an exception. Some forms also have an after-action handler method.

If the handler class exists but no handler method can be found, an error is thrown (the site is not allowed to do the operation, e.g. StudentHandler will never have a on_newLibraryBook() method). If the handler class wishes to allow the action, it can define an empty handler method.

Multiple forms
- addForms can add to the subsets of object produced by the enclosing newForm.
- any number of levels of form inclusion is possible but only the outermost form can have an action, onSubmit, and method and other attributes specific to HTML forms.
- all form actions take place in a single transaction, which is rolled back by the controller filter if there is an error.
- after_ methods are not executed in correct order (bug 689)

<mak:form action="blabla">
<%-- the topmost form, will result in a HTML form, may or may not have logic,
or it can be a specialized form (new, edit, add...)
--%>

<mak:input name="first" /> <%-- the topmost form can have fields of its own --%>

<mak:list .... >
  <mak:addForm object="bla" field="bla" >
<%-- note that there is no action indicated here, it's the action of the
topmost form a normal on_add BL method will be called
--%>
   <mak:input name="second" /><%-- the topmost form can have fields of its own,
even repeated in loops
--%>
...
</mak:addForm>
</mak:list>

<mak:list .... > <%-- there can be more than one loop in a root form -- %>
...
</mak:list>
<input type=submit> <%-- it's easy to add a submit button anywhere --%>
</mak:form>

(Later, new and edit forms that have no body, will build default forms. )

Form annotation
Form validation errors are either reported in the Makumba response which would be displayed on the form action page, or can for improved usability be annotated in the form itself. In the latter case, on a form validation error, the form page itself would be displayed again, and errors are displayed next to the inputs that failed validation.
An example can be seen below:

age   invalid integer: 1r
weight   invalid real: 24b

The annotation message will be put inside a <span class="formAnnotation">; this CSS-class can be used to add custom formatting to the message.

Reloading the form page on errors can be triggered by the attribute reloadFormOnError, the location of the annotation message by the attribute annotation.

Additionally, form validation can be done also on the client-side, i.e. in the browser. Client-side validation can be either live, i.e. on entering data in an input, or before form submission; this is controlled by the attribute clientSideValidation.

<mak:newForm  ...>.... </mak:newForm>

Makes a form for creating a new object of the indicated type.

Example (personNew.jsp):

<mak:newForm type="general.Person" action="personList.jsp" method="post">
<mak:input name="name"/>
<mak:input name="surname"/>
<input type="submit">
</mak:newForm>

Multiple submission of forms

If new forms are submitted more than once (intentionally or by accident, e.g. impatient users pressing twice one a submit button, reloading a form result page, ...), problems might occur in the data integrity.
Makumba has a built-int mechanism to prevent multiple submission of forms; a ticket will be generated on form load, containing a form-specific key and a time stamp. Each ticket is only valid for a single form submission. Upon subsequent submission of the very same form, an error message will be displayed.

Note that this does not prevent duplicate entries, it just prevents double submission of one specific form instance. To prevent duplicate entries, define unique keys.

tag parameter description comments
type Makumba type for record creation, or OQL label for subrecord creation Fixed, mandatory.
(handler) the Java class.method that handles the response defaults to on_new+NameOfMakumbaType. Arguments:
(Dictionary newData,  Attributes a, Database db)
action the response page of the form Mandatory if a <mak:action> is absent
method the HTTP method (get or post) Defaults to get
name the name of the created object in the response page Fixed. Defaults to __mak__edited__. If set, it is also used for the name of the html form (<form name="..." ...>)
message the message that is displayed in the response page upon success Fixed. Defaults to "changes done".
multipleSubmitErrorMsg Enables multiple form submission prevention, and sets the given value as the error message. Rtexpr.
reloadFormOnError Indicates whether the form page shall be reloaded on an error, or the specified form action page will be loaded Fixed. Values are true or false; defaults to false.
annotation Indicates that validation whether errors should be shown in the form, or be displayed in the <mak:response/>. Taken into account only if reloadFormOnError is not set to false.
Values are none (displayed in <mak:response/>), before (before the input), after (after the input) or both (displayed both before and after the input). Defaults to none.
annotationSeparator Fixed. Prints the given separator between the annotation and the input field. Also HTML can be used, e.g. printing an error icon.
clientSideValidation Controls whether client side validation shall be used. Rtexpr. Values are false (off), true (on submission) or live (while tpying).
target Form-specific html tag attributes The content is copied to the resulting <form...> tag. Careful with (escaping) quotes.
onReset
onSubmit
styleId Generic HTML tag attributes. results in id="..."
styleClass results in class="..."
style The content is copied to the resulting html tags. Careful with (escaping) quotes.
title
onClick
onDblClick
onKeyDown
onKeyUp
onKeyPress
onMouseDown
onMouseUp
onMouseMove
onMouseOut
onMouseOver

At form response, makumba (controller) invokes the following methods:

  1. By defining on_new*, the handler class gets the opportunity to validate/change the data. If the data is not correct, the handler can throw an exception to prevent insertion in database.

    handler.on_newTypeName(data, attr, db);
  2. The standard Database call for insertion:

    Pointer created= db.insert(type, data);
  3. By defining after_new*, the handler class gets the opportunity to do supplementary operations with the inserted record.

    handler.after_newTypeName(created, data, attr, db);

argument Java type comments
data java.util.Dictionary The new record to create. It is read from the HTTP query string by interpreting the form.
attr org.makumba.Attributes Other attributes in the page (sent as HTTP arguments or present in the HTTP session).
db org.makumba.Database The database where the record will be inserted
created org.makumba.Pointer The pointer to the created record. Only for after_new

If the handler class is present but both handler methods are missing (on_new and after_new), the action is not allowed.

At response the following calls are executed (in this order):

PersonLogic handler_obj; // see handler discovery
handler_obj.checkAttributes(attr, db);
handler_obj.on_newGeneralPerson(data, attr, db);
Pointer created= db.insert("general.Person", data);
handler_obj.after_newGeneralPerson(created, data, attr, db);

<mak:addForm  ...>.... </mak:addForm>

Makes a form for creating a sub-object of the mandatory enclosing <mak:object> (e.g. a language of a student, an address for a person).

Example:

<mak:object from="best.Student s" where="s=$student">
<mak:addForm object="s" field="languages"
action="studentView.jsp" method="post">
<mak:value expr="s.name"/>
<mak:input name="level"/>
<mak:input name="comments"/>
</mak:addForm>
</mak:object>

tag parameter description comments
object The label of the object whose sub-object will be created Fixed, mandatory
field The field name that denotes the sub-object. Fixed, mandatory.
(handler) the Java class.method that handles the response defaults to on_add+MakumbaType+fieldname. Arguments: (Pointer baseObject, Dictionary newData,  Attributes a, Database db)
action see newForm
method
name
message
reloadFormOnError
annotation
annotationSeparator
target Form-specific html tag attributes, see newForm
onReset
onSubmit
styleId Generic html tag attributes, see newForm
styleClass
style
title
onClick
onDblClick
onKeyDown
onKeyUp
onKeyPress
onMouseDown
onMouseUp
onMouseMove
onMouseOut
onMouseOver

This will call the handler methods: (the argument names are adapted to the example. Note the changed pointer argument in the methods.)

on_addBestStudentLang(Pointer student, Dictionary languageData, Attributes pageParams, Database db)
after_addBestStudentLang(Pointer address, Dictionary languageData, Attributes pageParams, Database db)

<mak:editForm  ...>.... </mak:editForm>

Makes a form for editing the object indicated by any of the labels of the mandatory enclosing <mak:object> or <mak:list>. Also linked objects can be edited through the same form.

Example:

<mak:object from="best.Student s, s.person p" where="s=$student">
<mak:editForm object="s" action="studentView.jsp" method="post">
<mak:input name="person.name"/>
<mak:input name="person.surname"/>
<mak:input name="graduated"/>
</mak:editForm>
</mak:object>

tag parameter description comments
object The label of the OQL object to edit Fixed, mandatory.
(handler) the Java class.method that handles the response defaults to on_edit+MakumbaTypeOfEditedObject. Arguments: (Pointer object, Dictionary changedFields, Attributes a, Database db)
action see newForm
method
name
message
reloadFormOnError
annotation
annotationSeparator
target Form-specific html tag attributes, see newForm
onReset
onSubmit
styleId Generic html tag attributes, see newForm
styleClass
style
title
onClick
onDblClick
onKeyDown
onKeyUp
onKeyPress
onMouseDown
onMouseUp
onMouseMove
onMouseOut
onMouseOver

The response will call the handler method: (the argument names are adapted to the example)

on_editBestStudent(Pointer student, Dictionary fieldsToChange, Attributes pageParams, Database db)

<mak:form  ...>....</mak:form>

Creates a generic form, that may call a handler method in response. It allows the JSP author to make any kind of form. They are suitable for more complex operations than new, add, edit.

Example:

<mak:object from="best.Student s" where="s=$student">
<mak:form handler="doSomething" action="studentView.jsp" method="post">
<mak:input name="xxx" value="s.person.name"/>
<input type=submit>
</mak:form>
</mak:object>

tag parameter description comments
handler the Java method that handles the response Arguments: (Dictionary formFields, Attributes restOfArguments, Database db)
Not mandatory. A form without handler will simply set attributes (as makumba objects) for the next page
action see newForm
method
name
message
reloadFormOnError
annotation
annotationSeparator
target Form-specific html tag attributes, see newForm
onReset
onSubmit
styleId Generic html tag attributes, see newForm
styleClass
style
title
onClick
onDblClick
onKeyDown
onKeyUp
onKeyPress
onMouseDown
onMouseUp
onMouseMove
onMouseOut
onMouseOver

<mak:input... />

An input field to be created, depending on the makumba type of the field.

Set and pointer inputs will render as select boxes. Sometimes you may need to use two select boxes whereby the user can move items from one box to the other, which is illustrated in this example.

Date inputs are slightly different than normal inputs, as they are rendered with several input fields (for the day, month, year, hours, minutes and second, depending on the date/time format). Additionally, a JavaScript-based calendar widget can be used, as shown in an example.

The difference between <mak:input > and normal HTML <input> in a makumba form are:

  • <mak:input> produces objects prepared for setting/comparing makumba fields (e.g. Pointer, Date, Text).
  • the fields produced by <input> will be available as page $attributes but will all be of type String
  • the fields produced by <mak:input> are available separately as a Dictionary to the handler method
<mak:object from="best.Student s, s.person p" where="s=$student">
<mak:editForm object="p" action="studentView.jsp" method="post">
name <mak:input name="name"/>
surname <mak:input name="surname"/>
gender <mak:input name="gender" type="tickbox" />
dob <mak:input name="birthdate" format="yyyy-MM-dd" />
</mak:editForm>
</mak:object>

tag parameter description comments
name
(or field)
Makumba field (from the edited record or via base pointers or sub-record pointers) Fixed, mandatory
nameVar The name of the java variable in which to store the name of the HTML input. In multiple forms,  there may be more HTML inputs generated by one mak:input, so a suffix is added by makumba to the name to generate unique names for each.
Fixed
value OQL expression relative to enclosing query tags or a $attribute computed previously in the page (with <mak:value var=.../> or pageContext.setAttribute(...)), or read by in the previous page by an <mak:input /> Fixed
type HTML INPUT type to be used
  • "hidden" works for all fields
  • for char[] , type can be "text" or "password", default is "text"
  • default type for [set]intEnum, [set]charEnum, ptr and set is "select" (dropdown or scroll list depending on size). Alternative is "tickbox" (checkboxes or radio buttons). Can be forced to a specific type by using "radio" or "checkbox"
  • for set, type can be seteditor, which will create two multiple-select boxes (see an example).
  • for int, spinner creates a spinner input with increase/decrease buttons; if a validation definition defines a range for the field, select and radio are will create select boxes and radio buttons.
  • date is split in 3 inputs, <fieldname>_0 (day), _1 (month), _2 (year), and likewise for time elements
  • for text, default is "textarea"; "file" will create file upload box, and will create supplementary attributes <fieldname>_filename, <fieldname>_contentType and <fieldname>_contentLength that have to be handled separately by the handler method
  • for file, a file upload box will automatically created, and handling of file name, content type and length will be done automatically.
Fixed
display If "false", it will not show the <input> but it will expect to read it in the next page. This allows the page designer to format the input control manually Rtexpr.
dataType The makumba type of the data (needed if there is no value, no default expression for the value, or no makumba type associated with an attribute) Fixed. Can be char, char[xx], int, date, text, ptr Type, set Type
nullOption A text that would be displayed as the "null option" in drop-down boxes, i.e. to add a null value to the other possible options. May be used to allow a ptr to be set to null, and/or require a deliberate action from the users to select a value, rather leaving the default (first) value selected. Fixed. Only for ptr and intEnum types
format Format string, according to java.text.SimpleDateFormat
Can only countain d, M, y, H, m, s formatting chars, and any kind of separators. Ex:
'the day' dd 'of the month' MMMM 'in the year' yyyy.
Default is "dd MMMM yyyy"
Rtexpr. Only for date.
stepSize For int data with type select or radio, the step size defines the steps between each option. The default stepsize is 1. Rtexpr. Only for int with type=select/radio.
size Size of the input control Rtexpr. Only for char[], int (size of the textbox) and set, ptr (height of the select)
maxLength Max length of a text control Rtexpr. Only for char[] and int. Defaults to makumba width of the char[]
labelSeparator The string that separates the tickbox (radio/check) from the label. Default is " " (space).
The output will be < tick >< labelSeparator >< label >
Rtexpr. Only for type="tickbox".
elementSeparator The string that separates the different options. Default is " " (space).
The output will be < [x] label >< elementSeparator >< [x] label >
Rtexpr. Only for type="tickbox".
calendarEditor Whether to generate code for a calendar editor, defaults to true.
See the detailed example for more information.
Fixed, values are true and false. Only for date.
calendarEditorLink The formatting that appears on the link to the calendar date-choser.
See the detailed example for more information.
Fixed. Only for date.
(elementSeparatorList) The list of strings that separates the different options. Not active by default. The format is "!sep[1]!sep[2]!...!sep[n]!" where any character (not appearing inside the separators) can be used as delimiter, e.g. '!'.
The output will be
< [x] label >< sep[1] >< [x] label >< sep[2] > ... < [x] label >< sep[n] >< [x] label >< sep[1] > ...
Rtexpr. Only for type="tickbox". Overrides elementSeparator if it exists.
rows, cols Number of textarea rows and columns only for text
default FIXME Rtexpr
empty FIXME Rtexpr
styleId Generic html tag attributes, see newForm
styleClass
style
title
onClick
onDblClick
onKeyDown
onKeyUp
onKeyPress
onMouseDown
onMouseUp
onMouseMove
onMouseOut
onMouseOver

Fields of related records can be reference and edited as well, via pointers. In this (somewhat strange) example, one can edit the name of the capital city of the country of which person is a citizen, through the person edit form :

<mak:input name="person.citizenship.capital.name" />

Restrictions for different field types:

  • fixed fields: cannot be edited
  • relational and index pointer: cannot be edited
  • timestamps (create and modify): cannot be edited
  • subset, subpointer: cannot be edited as a field, only as a separate object
<mak:option....>...</mak:option>
By default, for pointer and set fields, mak:input will show a choser (selector) that includes the title of all possible options, ordered by that title. To change that behavior, the mak:input can include one or more mak:option. Options can be repeated using mak:list, c:foreach, and in general can appear inside any other tag.

Text inside mak:option will become an option title. The value attribute will become the option. Text inside the mak:input that is not inside a mak:option amd is not blank (whitespace) will be assumed to separate groups of options and will be rendered. For options that render HTML SELECTs, this is only accepted for multiple SELECTs which will create several SELECT boxes of equal size, one for each option group.

If mak:option doesn't have a value indicated, it will produce a nil option. Such nil options will be ignored at form submission.

If an option value appears many times it will only be shown the first time it occurs.

<mak:input name="some" dataType="ptr T">
<mak:option>Please choose:</mak:option>
<mak:list from="T choice" where="someCondition" >
<mak:option value="choice"><mak:value expr="choice.someField" /></mak:option>
</mak:list>
<mak:option> -------- separator----------</mak:option>
<mak:list from="T choice" where="someOtherCondition" >
<mak:option value="choice"> <mak:value expr="choice.someField /></mak:option>
</mak:list>
</mak:input>

tag parameter description comments
value
Value of the option, can be an OQL expression or a $attribute Fixed, if not indicated, nil (null option) is default

<mak:action>....</mak:action>

If the action URI of a form or deleteLink is more complex, possibly including other makumba tags, the action parameter of the form tag can be omitted, and the action URI can be indicated in a mak:action, anywhere inside the form tag.

Example:

<mak:editForm object="ins" method="post">
<mak:action>memberView.jsp?person=<mak:value expr="p"/></mak:action>
...
</mak:editForm>

<mak:delete>...</mak:delete>

Produces a form or a link to an action page that will delete the object indicated by any of the labels of the mandatory enclosing <mak:object> or <mak:list>

Example:

<mak:object from="best.Student s, s.languages l" where="s=$student AND l.lang.name=$langname">
<mak:delete object="l" action="studentView.jsp">
Delete <mak:value expr="l.lang.name"/>
</mak:delete>
</mak:object>

DEPRECATED: The usage of <mak:deleteLink> is deprecated, and should be replaced by the equivalent:

<mak:delete widget="link">
tag parameter description comments
object OQL label of the object to delete Fixed
widget UI element of the delete Fixed, can be one of button or link; defaults to link.
preserveWhitespace All white space inside a <mak:delete> will be trimmed, unless specifically preserved. Fixed, can be one of true or false; defaults to false.
(handler) the Java class.method that handles the response defaults to on_delete+MakumbaTypeOfEditedObject. Arguments: (Pointer object, Attributes a, Database db). After deletion, makumba will look for after_delete+MakumbaTypeOfEditedObject. Arguments: (Pointer object, Attributes a, Database db) and execute it.
action see newForm
message
target
name
styleId Generic html tag attributes, see newForm
styleClass
style
title
onClick
onDblClick
onKeyDown
onKeyUp
onKeyPress
onMouseDown
onMouseUp
onMouseMove
onMouseOut
onMouseOver

The response will call the handler method: (the argument names are adapted to the example)

on_deleteBestStudentLang(Pointer lang, Attributes pageParams, Database db)

Business Logic (BL)

Attributes

Java Server Pages use attributes to keep the state of the application. Makumba builds upon that its own notion of Attributes that keep the read-only state of a makumba task. They represent the "environment" of that makumba task. The typical example is a JSP page during execution, with its HTTP and session parameters as attributes. Since other kinds of attributes are possible, the attribute specification is kept HTTP-independent. Makumba BL code sees the attributes as an org.makumba.Attributes object.

Java handler classes

Java handler classes are classes that implement the "business logic" of the organisation. Every makumba page will look for a handler, and will call its methods when needed. Check also the <mak:newForm> to know which methods are called. If a handler class exists, then some operations cannot be performed if these methods are not defined in the handler class.

Handler Discovery

Each page will determine its handler class on first access, after being compiled. If the class changes on disk, a webapp reload is generally needed for the new class to take effect.

The handler is 'discovered' by decomposing the full path of the JSP page, and finding a class with a matching name. Decomposition breaks the full path at every capital letter, or forward slash. For example, with the page path /student/mycv/indexPersonal.jsp, the following criteria are applied, in order:

criterium Java classes checked for
page name StudentMycvIndexPersonalLogic
caps parts of page/directory name StudentMycvIndexLogic
directory name StudentMycvLogic
parent directory name(s) StudentLogic
Logic

The class name prefix (e.g. java package name) can be regulated per parts of the site in a file called MakumbaController.properties which can be found in the CLASSPATH (just like MakumbaDatabase.properties). For example, the file can contain:

/student=org.eu.best
/makumba=org.makumba
/=test

path Java classes checked for
/student/mycv/index.jsp org.eu.best.MycvIndexLogic
org.eu.best.MycvLogic
org.eu.best.Logic
/makumba/tests/x.jsp org.makumba.TestsXLogic
org.makumba.TestsLogic
org.makumba.Logic
/some.jsp test.SomeLogic
test.Logic

There are good reasons to take into account the name of the response page of a form when looking for the business logic. Still, it is the name of the page that contains the form which matters not the name of the action page. It is good practice for both pages to actually have the same handler class.

All methods of the handlers are http-independent. Methods are non-static, so the handler classes can use inheritance to their advantage. Still, handler classes are singletons (only one instance of a certain class in a JVM). For example, the validation of a form can be in a class that is closer to the actual JSP application (view level) while the more view-independent methods can be in the parent of that class. For example:

org.eu.best.minerva.StudentHandler extends org.eu.best.StudentHandler

Role of Java handlers

  1. find attributes unknown by pages. e.g.
    <mak:object from="best.Student stud" where="stud=$student"> ...</mak:object>

    If the $student attribute is not known in the page (from a http argument) or in the session, the find{AttributeName}(Dictionary existingAttributes, Database d, String expression) method is called for the Handler object. In this case findStudent(). The handler has to compute the attribute, based on existing attributes, making DB accesses.

    The find{AttributeName} method's name is constructed literally from the name of the attribute (capitalising only the first letter), so dots and other illegal characters for java identifier names, are not to be used. Also, one shouldn't use 2 attribute names that differ only in the capitalisation of the first letter.

    For example "lbg.$lbg_order" (in an example elsewhere in the specs), will generate a call findLbg_order(otherAttributes, db) and the Java handler will return the default ordering for LBGs (say "name").

    If the attribute is computed successfully, it is associated with the session (i.e. set as JSP attribute in session scope)

    If not, an exception will be thrown (typically org.makumba.UnauthenticatedException), and the engine will act accordingly (i.e. ask for authentication).

  2. execute action methods in response to makumba forms. See makumba forms and actions below.

  3. ( later: return query parts, as methods. e.g. <mak:value expr="lbg.$title()" /> will generate a call to method BestInternalLbgTitle(lbg) which can return an OQL expression "concat(lbg.id, \"-\" lbg.name)" (such methods can be put directly in the Makumba data definitions) For now, OQL only accepts count() and sum(), but that can be easily fixed, till then, the method can be replaced by hand: <mak:value expr="lbg.id"/>-<mak:value expr="lbg.name"/> )

Handler Initialization

Whenever a handler is used in a new context (i.e. with a different set of attributes, e.g. a new page access), a method called checkAttributes(Attributes a, Database db) is looked for and executed, if it is defined.

checkAttributes can perform sanity checks for attributes used in the respective logic (in case of mismatches, org.makumba.UnauthorizedException is usually thrown), can load attributes that are absolutely needed for page execution (formerly given by the requiredAttributes() method), etc.

Transaction provider configuration

Most handlers provide a Transaction that can be used to perform addition database operations in the Business Logic. The class of this handler can be configured by providing a getTransactionProvider() String, that returns the fully-qualified name of the transaction provider implementation. For the moment, possible values are org.makumba.db.makumba.MakumbaTransactionProvider (native Makumba database layer) and org.makumba.db.hibernate.HibernateTransactionProvider (Hibernate-driven database layer)

Login

Login is done as a result of a missing attribute (possibly invoked in checkAttributes), when a find{AttributeName} method is called. The missing attribute is the principal that needs to log in.

If the attribute cannot be found due to wrong login information, org.makumba.UnauthenticatedException is usually thrown.

The principal (the person who logs in) can have more members (e.g. group, Lbg, Company representatives). E.g. the findCompany() method will check to see if the authentication (email_address and password) corresponds to any company representative of that company. If yes, it will return that company.

Login can be done in 2 ways:

  1. (Http basic authentication login: will set the attributes $username, $password )
  2. cookie login: done in a page called login.jsp, in the same directory or (if missing) in any of the parents. It should contain at least:
    <mak:login>
    <input type=text name=username>
    <input type=password name=password>
    <input type=submit>
    </mak:login>

    The login form will pass further (as hidden arguments) all the http parameters it got. Note that <mak:login> is only needed upon automatic login (a page displayed when the user requested another page, that needs authentication). If you wish to ask for login manually in a startup page, a normal HTML form is enough.

To cancel out a certain attribute, in order to produce a new login, the logout tag is available

<mak:logout actor="student"/>

You can remove (cancel-out, logout) multiple attributes from the session by using <mak:logout actor="attribute name"> several times and/or by using the star (*) wildcard, e.g.:

<mak:logout actor="demo_*"/> (attributes whose names start with "demo_")
<mak:logout actor="*app"/> (attributes whose names end with "app")
<mak:logout actor="*"/> (all attributes; this "invalidates" the session)

(Later on, logout request might be done in the business logic, with a method deleteAttributes(param) that can accept either a String (with optional '*') or a String[]. )

(Later: to accomodate servers that don't do session tracking, login can be done by a query condition rather than by doing a query (once per session) to find an attribute. This way, it won't need to do a query (to check the authentication) at every access, but that condition will make sure that authentication is done. )

(<mak:object from="best.Student stud" where ="stud.$login()"> ...</mak:object>
then methodBestSudentLogin("stud") will return "stud.auth.email=$username AND stud.auth.password=$password"
This can be used for http authentication with no session tracking. )

(Later: if an attribute has multiple values, a choose{AttributeName}.jsp page is shown. For example, a super user (for that area) can choose to act as any student, Lbg, or company... A student member of more local Vivaldi teams can choose to act for any of the viv teams, etc. )

Presentation and internal representation summary

This table describes the data types and their default user interface representation. That user interface can be altered with the Presentation language described below. Orientative SQL and Java types are presented.


 
Data definition type Default edit user interface Relational database type (orientative) Java type (orientative)
type (table) (list of records, with add, delete, edit controls; titles emphasized) table
record (all fields, as shown below) record java.util.Dictionary
int  text field (or slider) integer java.lang.Integer
int{}  dropdown choice or radio button
real text field double java.lang.Double
char[]  text field limited char java.lang.String
char{} dropdown choice or radio button
text text area unlimited characters org.makumba.Text
binary binary area unlimited byte org.makumba.Text
date date date and time java.util.Date
ptr dropdown select of record titles. See the example for set/ptr choosers with Makumba. preferably a long (foreign index) org.makumba.Pointer
xx=ptr
xx->...
(the record, if any) preferably a long (foreign index)
+ table
file file upload preferably a long (foreign index)
+ table
Index field (nothing) preferably long,
autoincrement, or other unique
creation date
modification date
date, not editable timestamp java.sql.Timestamp
set multiple choice of record titles. See the example for set/ptr choosers with Makumba. table with ptrRel to the parent table and ptr to the foreign table java.util.Vector of org.makumba.Pointer
xx=set
xx-> ...
(like a table, under current record) table with ptrRel to the parent table, and the rest of the fields
set int{ ...} multiple choice from values table with ptrRel to the parent table, and an int field java.util.Vector of java.lang.Integer
set char{ ...} multiple choice from values table with ptrRel to the parent table, and a char field java.util.Vector of java.lang.String