OLDSTYLE features that are still accepted are presented
in darkblue
(INTENDED features are presented in red with parentheses)
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.
.mdd (Makumba Data Definition)classes/best/Student.mdd)classes/dataDefinitions/best/Student.mdd)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.
Every data definition file contains field definitions, separated by newline.
A field definition looks like:
fieldname= [attributes] fieldtype [parameters] [; description]
(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...
Every datatype has some additional fields by default, as follows:
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. )
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 #fieldName= char[minWidth..maxWidth] password= encrypted char[6..10]; Secret password
"unique" and "encrypted" are field attributes, explained below.
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)
An unlimited-length string of bytes or characters. This type was designed to accomodate large text or binary content. It is implemented with LONGVARBINARY or its counterparts, depending on the underlying DB engine.
application= text ; Application letter description=text ; Description of object image= text ; Picture attachment
A date and/or time.
birthdate= date; Date of birth arrivalTime= date; Arrival time
Pointers define a reference to an object of a certain type. For example
citizenship= ptr general.Country; Citizenship
ptr keyword might be
ommitted in future parsersThe 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
address= ptr{
street= char[80]; Street
number= int; Number}; address
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
addresses: set{
street: char[80]; Street
number: int; Number }; Addresses
The set can contain enumerated int values :
place= set int {"home"=1, "away"=0} ; Home or away
DEPRECATED: The set can contain enumerated char values :
place= set char {"home", "away"} ; Home or away
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
One of the fields is always the object title, and is normally presented differently from other fields in user interface. This 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
address->!title= street
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.
The database can be interrogated using the following language ( [] means optional, {} means any number of repetitions). OQL is similar to SQL, a specification can be found at http://www.odmg.org (or check this PDF). Makumba recognizes a subset of OQL at the moment, which it translates to the host SQL when necessary.
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:
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 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.
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. 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
<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.
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).
<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"/> )
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.
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:
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> 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)
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. )
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 | ||
| char[] | text field | limited char | java.lang.String |
| char{} | dropdown choice or radio button | ||
| text | text area
or file upload |
unlimited byte | org.makumba.Text |
| date | date | date and time | java.util.Date |
| ptr | dropdown select of record titles | preferably a long (foreign index) | org.makumba.Pointer |
| xx=ptr
xx->... |
(the record, if any) | 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 | 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 |
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
(http://cvs.makumba.org/servlet_context/WEB-INF/).
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) :
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) :
org.makumba.LogicException
is thrown, the Exception can write a message to the <mak:response>
in the requested page.org.makumba.UnauthenticatedException and
org.makumba.UnauthorizedException will force
login (although UnauthorizedException probably shouldn't, bug 444)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 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'. 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.
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" countVar="counter" maxCountVar="number">
<% if(counter.intValue()==1) { %>
<p> There are <%= number %> male students:
<% } %>
<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>
<% if (number.intValue()==0) { %> There are no male students. <% } %>
| 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 |
| 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. |
| 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 |
| groupBy | OQL GROUP BY section | Fixed |
| (having) | OQL HAVING section | Fixed |
| orderBy | OQL ORDER BY section | Fixed. Attributes are allowed in this way: groupBy="p.$sortby" |
| 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. Prior to version 0.5.6, counting iterations using simple Java counting might not lead to a correct result. |
| 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. |
| separator | Character string as separator between two list elements. It is not included before the first or after the last | Rtexpr. |
| id | Tag's identifier | Fixed. Can be used to distinguish otherwise identical tags on a page (to avoid confusion by Makumba's JSP analyser) |
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 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)" >
<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. )
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) |
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 |
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)
|
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 |
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.
(Later, new and edit forms that have no body, will build default forms. )
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 field="name"/>
<mak:input field="surname"/>
<input type="submit">
</mak:newForm>
| 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". |
| 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:
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);
The standard Database call for insertion:
Pointer created= db.insert(type, data);
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);
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 field="level"/>
<mak:input field="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 | ||
| 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)
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 field="person.name"/>
<mak:input field="person.surname"/>
<mak:input field="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 | ||
| 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)
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 | ||
| 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 | ||
An input field to be created, depending on the makumba type of the field.
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).<input> will be available
as page $attributes but will all be of type String<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 field="name"/>
surname <mak:input field="surname"/>
gender <mak:input field="gender" type="tickbox" />
dob <mak:input field="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 |
| 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
|
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 |
| 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. |
| 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". |
| (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 field="person.citizenship.capital.name" />
Restrictions for different field types:
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>
Produces a link to the 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:deleteLink object="l" action="studentView.jsp"> Delete <mak:value expr="l.lang.name"/> </mak:deleteLink> </mak:object>
| tag parameter | description | comments |
|---|---|---|
| object | OQL label of the object to delete | Fixed |
| (handler) | the Java class.method that handles the response | defaults to on_delete+MakumbaTypeOfEditedObject. Arguments:
(Pointer object, Attributes a, Database db) |
| 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)
<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.
)