MicroNova YUZU JSP tag library

2008-06-16

MicroNova YUZU (named after Japanese citrus that adds touch of aroma) is a JSP tag library designed to augment JSP Standard Tag Library (JSTL) using Expression Language (EL). For JSTL/EL, please consult JSTL specification. YUZU is designed to be compatible with both JSP 1.2 and JSP 2.0 specifications. YUZU is tested under Apache tomcat (4.x/5.x) with JSTL reference implementation on Linux, and released under BSD-style license.

1 Attribute Evaluation

All YUZU tag attributes are always evaluated as EL on assignment. For example, unlike JSTL <c:set>, you can use dynamic variable names with <m:set> (YUZU version of <c:set>) as follows:

<%-- sets the value of "a" to "b" --%>

<c:set var="variableName" value="a"/>
<m:set var="${variableName}" value="b"/>

However, certain YUZU tag attributes (called "EL attributes") are strings to be evaluated as EL later, and it is necessary to escape evaluation of "${...}" on assignment. One way to do this in standard JSP/JSTL is to use "${'$'}" instead of "$". The following sets the value of "x" to "${xyz}":

<c:set var="x" value="${'$'}{xyz}"/>

To simplify coding, YUZU EL attributes translate a special pattern "@{" to "${" on assignment. The following sets the "test" attribute to "${!empty param.x}" EL expression for later evaluation:

<%-- outputs the value of parameter "x" if not empty, otherwise "EMPTY" --%>

<m:out value="${param.x}" default="EMPTY" test="@{!empty param.x}"/>

Translation from "@{" to "${" is made after evaluating the attribute value as EL, so the following is equivalent to the above:

<c:set var="PARAMNAME" value="param.x"/>
<m:out value="${param.x}" default="EMPTY" test="@{!empty ${PARAMNAME}}"/>

EL attributes common to all YUZU tags are: test, assign, export, prepareCodec, importCodec, processCodec, codec, assignCodec, exportCodec, and cleanupCodec.

2 Overview

Each YUZU tag has an object (called "tagValue" in this document) associated with it, and is always processed in 6 stages as follows:

  1. Prepare stage where the tagValue is prepared (upon tag opening)
  2. Import stage where the tagValue is imported from the tag body, if not prepared (upon tag closing)
  3. Default stage where default value logic is applied to the tagValue (upon tag closing)
  4. Process stage where the tagValue is processed (upon tag closing)
  5. Assign stage where the tagValue is assigned to a variable (upon tag closing)
  6. Export stage where the tagValue is output, if no assignment is made (upon tag closing)

2.1 Prepare Stage

At Prepare stage, the tagValue is set in one of the following ways (in the order of precedence):

Prepare stage is done upon tag opening before processing the tag body, and the tagValue set in Prepare stage is accessible within the tag body using a special page-scoped variable "_" (underscore). See Local Variables below.

In the following example, <m:out> simply outputs the tagValue as-is:

<%-- outputs "Hello World" --%>

<m:out value="Hello World"/>

<%-- outputs current date --%>

<m:out className="java.util.Date"/>

<%-- creates an instance of Gregorian Calendar for 2007/01/01 --%>

<m:out className="java.util.GregorianCalendar:2007:0:1"/>

<%-- creates a double array of size 3 --%>

<m:out className="[]:double:3"/>

You can also specify source attribute as a map of bean properties to initialize the tagValue as in <m:map> tag. The value of source can be an instance of java.util.Map or a string representing such a map in form/xml/json-encoded (with optional '@' prefix to indicate evaluation using "@{..}" syntax), or any other object (in this case the map of all bean property values of given object (as obtained by Bean:getMap codec) is used). For example:

<%-- creates a date in year 1999 --%>

<%-- using json-encoded string --%>

<m:set className="java.util.Date" source="{year:99}"/>

<%-- using xml-encoded string --%>

<m:set className="java.util.Date" source="<root><year>99</year></root>"/>

<%-- using json-encoded evaluated map --%>

<m:set var="year" value="99"/>
<m:set className="java.util.Date" source="@{year:@{year}}"/>

If source is a list or a NestedMap with non-empty "_" sublist, then the tagValue is assumed to be an array or list and its elements are set accordingly. For example,

<%-- creates and initializes a 3x3 int array --%>
<m:set var="x" className="[]:int[]:3">
  <%-- a JSON-encoded NestedMap --%>       
  <m:set property="0" className="[]:int:3" source="{_:[1,2,3]}"/>
  <%-- list obtained by splitting a string --%>
  <m:set property="1" className="[]:int:3">
    <m:set attribute="source" value="4,5,6" codec="String:split"/>
  </m:set>
  <%-- NestedMap with explicitly set sublist elements --%>
  <m:set property="2" className="[]:int:3">
    <m:map attribute="source">
      <m:set property="@_.*">7</m:set>
      <m:set property="@_.*">8</m:set>
      <m:set property="@_.*">9</m:set>
    </m:map>
  </m:set>
</m:set>

<%-- outputs 1 2 3 4 5 6 7 8 9 --%>
<c:forEach var="i" items="0,1,2">
  <c:forEach var="j" items="0,1,2">
    ${x[i][j]}
  </c:forEach>
</c:forEach>           

If necessary, you can specify a pipe of functions ("codec") to be applied to the prepared tagValue using prepareCodec attribute. See Codecs below for more details.

2.2 Import Stage

If the tagValue is not set at Prepare stage, then it is "imported" from the tag body (i.e., set to the string resulting from processing the tag body as JSP) upon tag closing. By default the string is taken as-is, but if necessary, you can specify a "codec" to be applied to the string.

For example:

<%-- outputs "Hello World" --%>

<m:out><m:out value="Hel"/>lo Wor<m:out value="ld"/></m:out>

<%-- outputs the value of "${message}" if not null, otherwise "Hello World" since tagValue is not set in Prepare stage --%>

<m:out value="${message}">Hello World</m:out>

<%-- outputs lower-case "hello world", applying "String:toLowerCase" codec --%>

<m:out importCodec="String:toLowerCase">Hello World</m:out>

2.3 Default Stage

When necessary, a default value for the tagValue can be specified using default attribute. If specified, the default value is taken at Default stage if current tagValue (prepared or imported) is null or empty string (""):

<%-- outputs the value of parameter "X", or "DEFAULT" if not given --%>

<m:out value="${param.X}" default="DEFAULT"/>

You can control when default is taken by specifying test EL attribute (a boolean EL expression that evaluates to true/false). If specified, the default value is taken when test evaluates to false:

<%-- outputs "ONE" if the value of parameter "X" is "1", otherwise "NOTONE" --%>

<m:out test="@{param.X == 1}" value="ONE" default="NOTONE"/>

You can use a special page-scoped variable "_" (underscore) in the test expression to refer to the current tagValue:

<%-- outputs "NONE" if there are no parameters --%>

<m:out test="@{!empty _}" default="NONE"><c:forEach var="p" items="${param}"><m:out value="${p}"/></c:forEach></m:out>

Note: actually the test attribute value is a codec. See Codecs below for more information.

2.4 Process Stage

At Process stage, the tagValue is processed and transformed into another object if necessary. Most YUZU tags perform customized actions here.

If processCodec or codec is specified, it is applied to the processed tagValue before Assign/Export stage.

2.5 Assign Stage

The processed tagValue is assigned to a variable in one of the following ways (as in JSTL <c:set>):

Default variable scope is "page", but this can be controlled by setting localScope attribute in the ancestor tag (see Local Variables below).

When property is specified, target can be omitted if the tag is within the body of another YUZU tag. In this case, the closest surrounding YUZU tag's tagValue is taken as the target.

As in JSTL, when the target object is a map (implementation of java.util.Map), then the property is used as the map key:

<%-- assigns to "map" an instanceof java.util.HashMap initialized as "{a=alpha,b=beta}" --%>

<m:set var="map" className="java.util.HashMap">
  <m:set property="a" value="alpha"/>
  <m:set property="b" value="beta"/>
</m:set>

When the target object is a List (implementation of java.util.List), then the property specifies the element position as follows:

 property  tagValue  operation 
 non-negative integer  any  replace at given index from the beginning (0 = first element) 
 negative integer  any  replace at given index from the end (-1 = last element) 
 "*" or "**"  non-null  append tagValue at the end 
 "*"  null  remove last element 
 "*" or "**" followed by non-negative integer (e.g., "*2")  non-null  insert tagValue at given index from the beginning 
 "*" followed by non-negative integer (e.g., "*2")  null  remove element at given index from the beginning 
 "*" or "**" followed by negative integer (e.g., "*-2")  non-null  insert tagValue at given index from the end 
 "*" followed by negative integer (e.g., "*-2")  null  remove element at given index from the end 
 any string starting with "**"  null  no operation 

For example:

<m:set var="list" className="java.util.ArrayList">
  <%-- append "a", "b", "c", "d" --%>
  <m:set property="*" value="a"/>
  <m:set property="*" value="b"/>
  <m:set property="*" value="c"/>
  <m:set property="*" value="d"/>
  <%-- remove element at 1 ("b") --%>
  <m:set property="*1"/>
  <%-- insert "e" at position 1 --%>
  <m:set property="*1" value="e"/>
  <%-- insert "f" before the last two elements --%>
  <m:set property="*-2" value="f"/>
  <%-- replace element at index 1 with "E" --%>
  <m:set property="1" value="E"/>
  <%-- remove the last element --%>
  <m:set property="*"/>
</m:set>

<%-- this outputs "[a, E, f, c]" --%>

<m:out value="${list}"/>

When the target object is an array, then the property can be either a non-negative integer (index from the beginning) or a negative integer (index from the end), indicating replacement position.

When the target object is a Queue (implementation of java.util.Queue), then property "*" can be used as follows:

 property  tagValue  operation 
 "*"  non-null  inserts tagValue to the queue 
 "*"  null  removes and returns the head of the queue 

As a special case, you can set the value of target to "return" string to return the tagValue to the caller when the JSP is called by another JSP as in <m:return> tag.

By default the tagValue itself is assigned, but you can control what is actually assigned by specifying assign EL expression using a special variable "_" (underscore) representing the tagValue:

<%-- assigns the value of "a" followed by the value of "b" to variable X, instead of the map itself --%>

<m:set var="X" className="java.util.HashMap" assign="@{_.a}@{_.b}">
  <m:set property="a" value="alpha"/>
  <m:set property="b" value="beta"/>
</m:set>

<m:out value="${X}"/>

You can set the value of assign to a special string "_export" to use the same value as export.

If assignCodec is specified, then it is applied to the result of evaluating the assign EL expression (the tagValue by default) before assignment is made.

When necessary, it is possible to set a tag attribute value using attribute attribute within the tag body (in this case target must be omitted). For example,

<m:set var="message">
  <m:set attribute="value">hello</m:set>
</m:set>

is equivalent to the following:

<m:set var="message" value="hello"/>

When necessary, you can use a comma-seperated list of names as property or var. In this case, if the assign value is a list or an array, then each element of the list/array is assigned to each named variable or property, otherwise the same assign value is assigned to each named variable or property. If a name is an empty string, it is skipped and no assignment is made. For example:

<%-- generates java code from given signature --%>

<m:set var="signature" assignCodec="String:trim">
int foo(int a, String b)
</m:set>

<m:set var="template" assignCodec="String:trim">
@{_.type} @{_.name}(@{_.argDecl}){ 
  return super.@{_.name}(@{_.args});
}
</m:set>

<m:map exportCodec="${template}">
  <m:set property=",type,name,argDecl" value="${signature}" codec="String:matchingGroups:^([^ ]+) ([^(]+)\((.*)\)$"/>
  <m:set property="args" value="${_.argDecl}" codec="String:replaceAll:[^, ]+ ::"/>
</m:map>

2.6 Export Stage

If no assignment is made in Assign stage, then the tagValue is "exported" (output as string). By default the tagValue itself is exported, but if necessary, it is possible to specify what is exported by using export attribute. The value of export attribute is an EL expression containing a special variable "_" (underscore) representing the tagValue, and the result of evaluating the EL expression is output as string.

Here is an example of using non-default export:

<%-- outputs number of milliseconds from 01/01/1970. --%>

<m:out className="java.util.Date" export="@{_.time}"/>

If exportCodec is specified, then it is applied to the result of evaluating the export EL expression before exporting. Note that, unlike JSTL <c:out>, YUZU tags do not escape tag characters such as '<', '>' etc. unless exportCodec is set to something like "XML:encode".

If the tagValue object is a DOM Node (implementation of org.w3c.dom.Node), then it is output as XML (without XML declaration).

By default, the tagValue is exported only when it is not assigned, but you can force exporting by setting doesExport attribute to "always".

3 Codecs

At various stages above, you can specify extra functions to be applied such as "URL:encode", "Base64:decode", etc.. Such a function is called a "codec" in this document. YUZU tags support the following codec attributes:

The object to which a codec is applied is called operand; e.g., the operand for "importCodec" is the tag body string, and the operand for "processCodec" is the processed "tagValue".

For example:

<%-- if "x=a&x=b&x=c" is given as form parameters, then outputs "a,b,c" --%>

<m:out value="${paramValues.x}" codec="String:join"/>

You can specify additional arguments separated by ":" (colon):

<%-- if "x=a&x=b&x=c" is given as form parameters, then outputs "a-b-c" --%>

<m:out value="${paramValues.x}" codec="String:join:-"/>

You can use two "::" (two colons) to indicate an empty string argument:

<%-- if "x=a&x=b&x=c" is given as form parameters, then outputs "abc" --%>

<m:out value="${paramValues.x}" codec="String:join::"/>

Codec arguments are evaluated as EL upon function call, and you can use "@{...}" to escape evaluation on assignment:

<m:set var="separator" value=":"/>

<%-- if "x=a&x=b&x=c" is given as form parameters, then outputs "a:b:c" --%>

<m:out value="${paramValues.x}" codec="String:join:@{separator}"/>

You can use "|" to indicate a sequence of codecs ("pipe") to be applied. The second codec is applied to the result of the first codec, and so on:

<m:set var="separator" value=":"/>

<%-- if "x=a&x=b&x=c" is given as form parameters, then outputs "A:B:C" --%>

<m:out value="${paramValues.x}" codec="String:join:@{separator}|String:toUpperCase"/>

You can use "\" to escape separators when necessary ("\:" or "\|"):

<%-- if "x=a&x=b&x=c" is given as form parameters, then outputs "|:|:|" --%>

<m:out value="${paramValues.x}" codec="String:join:\:|String:replaceAll:[abc]:\|"/>

There is a special variable named "_operand" that holds the "operand" of the codec (the object to which the codec is applied):

<%-- outputs "MATCH" instead of "abc" if "x=a&x=b&x=c" is given --%>

<m:out value="${paramValues.x}" codec="String:join::|Type:ifEqual:abc:MATCH:@{_operand}"/>

If you append an "_" (underscore) to the name of the codec method, then the codec is applied to the first codec argument, instead of "_operand". The following two are equivalent:

<m:out value="${paramValues.x}" codec="String:join:-"/>

<m:out codec="String:join_:@{paramValues.x}:-"/>

If there is no ":" found in a codec specification, then it is evaluated as EL:

<%-- outputs "true" if parameter "x" contains more than 2 "t"'s --%>

<m:out value="${param.x}" codec="String:replaceAll:[^t]::|String:length|@{_operand > 2}"/>

You can store a codec in a variable:

<m:set var="ISAPHONE" value="String:match:^\([0-9]{3}\)[0-9]{3}-[0-9]{4}$"/>

x is <m:out value="${param.x}" codec="${ISAPHONE}|Type:ifNull:not a:a"/> phone number.

The following built-in codec's are available ("operand" refers to the object to which the codec is applied, and "[:xxx]" indicates optional arguments):

 Backslash:decode  decodes "operand" as backslash-encoded String. Current supports "\n", "\r", "\t", "\b", "\f", "\'", "\"", "\\", "\/", and "\uxxxx" (unicode). Note that NEWLINE (\n) following a "\" is removed. 
 Backslash:encode  encodes special characters using "\" (backslash) in "operand" as String. Currently supports "\n", "\r", "\t", "\b", "\f", "\", "\'", "\"", "\/". 
 Base64:decode[:ENCODING]  decodes "operand" as base64-encoded string using ENCODING (default "utf-8") 
 Base64:encode[:ENCODING]  applies base64 encoding to "operand" using ENCODING (default "utf-8") 
 Bean:decode  deserializes XML "operand" as java bean. 
 Bean:encode  encodes "operand" as java bean using XML serialization. 
 Bean:fill:PROPERTYMAP  sets bean properties of "operand" as bean according to PROPERTYMAP containing (property, value) pairs 
 Bean:get:PROPERTY  gets the bean property named PROPERTY of "operand". If the "operand" is a map/list/queue, then its value/element corresponding to the PROPERTY is returned. For a list, negative integers can be used to index from the end (e.g., "-1" returns the last element). For a queue, "*" can be used to remove and return the head, and "0" can be used to return the head without removing. 
 Bean:getInfo  returns BeanInfo of "operand" 
 Bean:getMap  returns all (property, value) pairs of "operand" bean as a map 
 Bean:getProperty:PROPERTY  gets the bean property named PROPERTY of "operand" without special handling for List/Map. 
 Bean:set:PROPERTY:PROPERTYVALUE  sets the bean property named PROPERTY of "operand" to PROPERTYVALUE and returns "operand" itself. If the "operand" is a map or a list, then its value/element corresponding to the PROPERTY is set. 
 Bean:setProperty:PROPERTY:PROPERTYVALUE  sets the bean property named PROPERTY of "operand" to PROPERTYVALUE and returns "operand" itself without special List/Map handling. 
 Calendar:add:PROPERTY:VALUE  adds VALUE to given PROPERTY of "operand" as calendar and returns "operand" if successful, null otherwise 
 Calendar:get:PROPERTY  returns given PROPERTY of "operand" as calendar (e.g., "DAY_OF_WEEK" returns the day of week) 
 Calendar:monthly  returns monthly calendar nested map structure for given "operand" as today's date or calendar. The following monthly calendar properties are set: "numberOfWeeks" (number of weeks in this calendar), "week._" (list of week maps; e.g., "week._[0]" is the first week), "week._[n]._" (list of dates in week n), "week._[n].dayIndexStart" (inclusive start index of days of the month in week n; 0 except for the first week), "week._[n].dayIndexEnd" (inclusive end index of days of this month in week n; 6 except for the last week), "week._[n].dayIndexToday" (index of "today" in week n; empty if today is not in week n), "today.date" (today's date), "today.weekIndex" (index of week containing today), "today.dayIndex" (index of today in the week containing today), "lastDayOfMonth.date" (the last day of this month), "lastDayOfMonth.dayIndex" (index of the last day of the month in the last week), "firstDayOfMonth.date" (first day of month), "firstDayOfMonth.dayIndex" (index of the first day of the month in the first week), "nextMonth" (next month today), "lastMonth" (last month today), "nextYear" (next year today), "lastYear" (last year today), "thisWeek" (the week containing today). 
 Calendar:roll:PROPERTY:VALUE  "rolls" (changes without changing larger properties) given PROPERTY of "operand" as calendar by VALUE and returns "operand" if successful, null otherwise 
 Calendar:set:PROPERTY:VALUE  sets given PROPERTY of "operand" as calendar to VALUE and returns "operand" if successful, null otherwise 
 File:append:OUTFILE[:ENCODING]  appends "operand" as string to OUTFILE using given ENCODING (default is "iso-8859-1"). Returns "operand" if successful, otherwise null. 
 File:bean  creates an instance of a "file bean" (com.micronova.util.FileBean) from "operand" as an instance of File (java.io.File) or URI (java.net.URI). A "file bean" is a wrapper bean for File that supports the following bean properties: "fileObject" (underlying File object), "canRead" (boolean), "canWrite" (boolean), "exists" (boolean), "absolute" (boolean), "directory" (boolean), "file" (boolean), "hidden" (boolean), "absoluteFile", "absolutePath", "canonicalFile", "canonicalPath", "name", "parent", "path", "lastModified", "length", "uri", and "url". 
 File:close  closes "operand" (as InputStream/OutputStream/Reader/Writer) and returns "operand" 
 File:delete  deletes given file "operand". The "operand" can be either a directory name or a java.io.File object. Returns Boolean.TRUE if successful, null otherwise. 
 File:flush  flushes "operand" (as OutputStream or Writer) and returns "operand" 
 File:list  list files (as list of strings) in the given file directory "operand". The "operand" can be either a directory name or a java.io.File object. 
 File:listFiles  list files (as list of file objects) in the given file directory "operand". The "operand" can be either a directory name or a java.io.File object. 
 File:mkdir[:CREATEPARENTS]  makes directory named "operand". Returns "operand" if successful, otherwise null. If non-null CREATEPARENTS is given, then non-existing parent directories are created. 
 File:mkdirs  equivalent to "File:mkdir:true". 
 File:read[:ENCODING]  reads the content of given file "operand" as string using given ENCODING (default is "iso-8859-1"). 
 File:rename:NEWNAME  renames given file "operand" to NEWNAME. The "operand" can be either a directory name or a java.io.File object. Returns the renamed java.io.File object. 
 File:tempfile  returns a temporary file named according to the "operand" template. The "operand" is supposed to have the form of "prefix*suffix"; e.g., "TEMP*.dat" generates a temp file having prefix "TEMP" and suffix ".dat". If "prefix" contains a "/", then the substring up to the last "/" is taken as the directory specification (e.g., "/tmp/TEMP*.dat"). If "operand" is null, then "temp*" is used as the template. 
 File:type  returns mime type of the given file "operand". "operand" can be either a filename or a java.io.File object. 
 File:write:OUTFILE[:ENCODING]  writes "operand" as string to OUTFILE using given ENCODING (default is "iso-8859-1"). Returns "operand" if successful, otherwise null. 
 Format:date[:PATTERN:LOCALE]  formats "operand" date according to the PATTERN and LOCALE. PATTERN is a date format pattern used by java.util.SimpleDateFormat. LOCALE is either an instance of java.util.Locale or a map specifying a locale using properties "language", "country", and "variant". 
 Format:map:TYPE[:CONTROLMAP]  formats "operand" as NestedMap according to the TYPE ("xml"/"json"/"encoded"/"encodedSorted"; default "xml") with optional type-specific CONTROLMAP as in XMLMap:encode or JSON:encode. 
 Format:number[:PATTERN:LOCALE]  formats "operand" number according to the given PATTERN and LOCALE. PATTERN is a number format pattern used by java.util.NumberFormat. LOCALE is either an instance of java.util.Locale or a map specifying a locale using properties "language", "country", and "variant". 
 GZIP:decode or GZIP:decompress  decompresses "operand" as GZIP-compressed string 
 GZIP:encode or GZIP:compress  compresses "operand" string using GZIP 
 Hex:decode  decodes "operand" as hexadecimal string 
 Hex:encode  encodes "operand" as hexadecimal string 
 JSON:decode[:CONTROLMAP]  converts "operand" string in JSON-like (Javascript) format to an object (Map/List/String). CONTROLMAP specifies a map with the following properties: "allowUnquoted" (default true; if set to false, then unquoted strings are not allowed). See JSON/Javascript for more information. 
 JSON:encode[:CONTROLMAP]  converts "operand" object into JSON-like (Javascript) format. CONTROLMAP specifies a map with the following properties: "quote" (string to be used as quote charater; default is doublequote), "doesEncode" (if true, special characters in a string are escaped using Backslash:encode; default is true). See JSON/Javascript for more information. 
 Javascript:compile  compiles "operand" string as Javascript. Returned object can used as "operand" in Javascript:eval. This requires "js.jar" from "http://www.mozilla.org/rhino/". See JSON/Javascript for more information. 
 Javascript:eval[:ENVMAP]  evaluates "operand" as Javascript and returns the result. key/value pairs in optional ENVMAP are set as global variable/value before evaluation. This requires "js.jar" from "http://www.mozilla.org/rhino/". See JSON/Javascript for more information. 
 Mime:decode  parses mime string of type "x/y;a=1 b=2;..." into a map of type "{type=x, subtype=y, parameter={a=1, b=2, ...}}". 
 Mime:encode  encodes parsed mime map of type "{type=x, subtype=y, parameter={a=1, b=2, ...}}" to string "x/y;a=1;b=2;...". The "subtype" field can be null. 
 NodeMap:decode[:CONTROL]  converts NestedMap structure into DOM Nodes. CONTROL can be either an instance of DOM document (for which DOM nodes are created) or a map with properties for DocumentBuilder used to create such a DOM document. See NodeMap for more information. 
 NodeMap:encode  converts XML Node into NestedMap structure with the following properties: "type" (node type), "value" (node value), "name" (node name), "attributes" (map of attributes), and "_" (list of children). See NodeMap for more information. 
 Number:abs  returns absolute number of "operand" as Double 
 Number:acos  returns arc cosine of "operand" 
 Number:asin  returns arc sine of "operand" 
 Number:atan  returns arc tangent of "operand" 
 Number:ceil  returns "ceiling" of "operand" as Long 
 Number:cos  returns cosine of "operand" 
 Number:e_  returns constant "e" (natural log base) 
 Number:exp  returns exp of "operand" 
 Number:floor  returns "floor" of "operand" as Long 
 Number:fromBinaryString  converts "operand" as binary string to Long. 
 Number:fromHexString  converts "operand" as hexadecimal string to Long. 
 Number:fromOctalString  converts "operand" as octal string to Long. 
 Number:log  returns log of "operand" 
 Number:max_:X:Y  returns max of X and Y as Double 
 Number:min_:X:Y  returns min of X and Y as Double 
 Number:pi_  returns constant "pi" 
 Number:pow_:X:Y  returns X to the power Y 
 Number:round  returns integer value closest to "operand" as Long 
 Number:sin  returns sine of "operand" 
 Number:sqrt  returns square root of "operand" 
 Number:tan  returns tangent of "operand" 
 Number:toBinaryString[:FILLER]  converts "operand" as number to binary string. If FILLER is given, then it is used to fill the digits to the left. 
 Number:toDegrees  converts "operand" in radians to degrees 
 Number:toHexString[:FILLER]  converts "operand" as number to hexadecimal string. If FILLER is given, then it is used to fill the digits to the left (e.g., FILLER="0000" to get a 4-digit hexadecimal number such as "0caf" instead of "caf"). 
 Number:toOctalString[:FILLER]  converts "operand" as number to octal string. If FILLER is given, then it is used to fill the digits to the left. 
 Number:toRadians  returns "operand" in degrees to in radians 
 Random:number  returns a random Double smaller than "operand" as number 
 Random:pick  picks one element randomly out of "operand" list. If the operand is not a list, picks one character out of the operand as string. The distribution can be controlled by having duplicates in "operand" (e.g., if "operand" is "0000000001", then "0" is returned 9 times more likely than "1") 
 Security:decrypt:KEY:ALGORITHM[:IV]  decrypts "operand" as string using given KEY and ALGORITHM (and IV if given). If given, IV is converted to a byte array as an ISO-8859-1 string. 
 Security:digest:ALGORITHM  computes digest of given "operand" string using ALGORITHM (e.g., "MD5", "SHA", etc.) 
 Security:encrypt:KEY:ALGORITHM[:IV]  encrypts "operand" as binary string using given KEY and ALGORITHM (and IV if given). KEY can be any binary string as long as its byte length matches the ALGORITHM. If given, IV is converted to a byte array as an ISO-8859-1 string. 
 Security:generateSecretKey_:ALGORITHM  generates a secret key for given encryption ALGORITHM (e.g., "AES", "DES", "DESede", "Blowfish", etc.) as binary string 
 Security:secureRandom:ALGORITHM  computes secure random bytes of given "operand" size using ALGORITHM (e.g., "SHA1PRNG"); if "operand" is not an integer, then it's byte length as string is taken as the size 
 String:append:STRING[:CONDITION]  appends STRING to "operand" (when CONDITION is true if given); operand can be a string or an instance of java.io.Writer or java.io.OutputStream. 
 String:capitalize  capitalizes "operand" string 
 String:countWords[:PATTERN]  creates frequency map (histogram) of "words" in the "operand" string separated by given PATTERN (default "[ ]+"); e.g., "{a=2, b=3}" for "a b b a b" 
 String:decompose:PATTERN[:GROUP]  returns a list of alternating non-PATTERN-matching and PATTERN-matching substrings in the "operand" string (i.e., "split" and "matchAll" mixed together). GROUP is 0 by default (meaning the whole matching PATTERN is returned if matched). The first and the last elements of the returned list are always non-matching (possibly empty) substrings. 
 String:escapeUnicode[:CONTROLMAP]  escapes characters in "operand" string to "\uxxxx" format. CONTROLMAP is a map or a form/json/xml-encoded string that specifies the following: "minCode" (smallest character code to be escaped; default 128), "maxCode" (largest character code to be escaped; default 65535) 
 String:fromByteArray:ENCODING  converts "operand" byte array to string using given ENCODING 
 String:fromCharacterList  converts "operand" list of Characters to string 
 String:indexOf:SUBSTRING  returns the first index of SUBSTRING in "operand", -1 if not found 
 String:join[:GLUE]  joins elements of "operand" (list or array) using GLUE string. Default GLUE is ",". 
 String:lastIndexOf:SUBSTRING  returns the last index of SUBSTRING in "operand", -1 if not found 
 String:match:PATTERN[:GROUP]  returns the first matching PATTERN GROUP in "operand" string, or null. GROUP is 0 by default (meaning the whole matching PATTERN). 
 String:matchAll:PATTERN[:GROUP]  returns list of all matching PATTERN GROUP's in "operand" string. GROUP is 0 by default (meaning the whole matching PATTERN). If GROUP is -1, then list of all matching groups is returned instead. 
 String:matchingGroups:PATTERN  returns a list of all matching PATTERN groups in "operand" string (0-th element is the whole expression, 1-st element is the first matching group, etc.). Returns empty list if "operand" does not match PATTERN. 
 String:multiply:COUNT  multiplies "operand" string COUNT times 
 String:prepend:OBJECT[:CONDITION]  prepends OBJECT to "operand" string (when CONDITION is true if given); if OBJECT is an instanceof java.io.Writer or java.io.OutputStream, then operand is append to OBJECT. 
 String:replaceAll:PATTERN[:WITH]  replaces all given regular expression PATTERN in "operand" string with WITH (default "") 
 String:replaceFirst:PATTERN[:WITH]  replaces first given regular expression PATTERN in "operand" string with WITH (default "") 
 String:reverse  reverses "operand" string 
 String:splitCSV[:CONTROLMAP]  splits "operand" string into a List of lists (rows of columns) of strings as CSV (comma-separated) format. CONTROLMAP can be a map or form/json/xml-encoded string that specify the following properties: "separator" (default ','), "quote" (default '"' (double quote), "newline" (default '\n'). 
 String:split[:PATTERN]  splits "operand" string into a List at given regular expression PATTERN (default ",") 
 String:substring:STARTINDEX[:ENDINDEX]  gets substring of "operand" starting at STARTINDEX (ending at ENDINDEX if given). If STARTINDEX or ENDINDEX is negative, then it is counted from the end (e.g., "String:substring:-2" means the last two characters). 
 String:toByteArray:ENCODING  converts "operand" as string to byte array using given ENCODING 
 String:toCharacterList  converts to "operand" string to list of Characters 
 String:toLowerCase  converts "operand" string to lower case 
 String:toUpperCase  converts "operand" string to upper case 
 String:trim  removes whitespaces from both sides of "operand" string 
 System:createCache  creates a cache (instance of java.util.LinkedHashMap) according to the specification by "operand" map or form/json/xml-encoded string. Currently supports the following properties: "initialCapacity" (default 16), "loadFactor" (default 0.75), "maxSize" (default 16), "type" (either "LRU" (default) or "FIFO"). If also "lifespan" is specified, then hits older than given "lifespan" milliseconds are automatically invalidated and removed from cache. 
 System:currentTimeMillis_  returns current system time in milliseconds 
 System:currentTime_  returns current time as java.util.Date 
 System:deserialize  deserializes "operand" as binary (ISO-8859-1) string 
 System:getProperties_  returns map of current system properties 
 System:getStatic[:VARIABLE]  returns the value of a static java variable. The operand can be either a fully qualified name (e.g., "java.awt.Color.GREEN") or a class instance or name (e.g., "java.awt.Color") if VARIABLE is given separately (e.g., "GREEN") 
 System:invoke  dynamically invokes a java method. The "operand" must be a nested map with the following properties: "object" (target object to invoke a method on), "class" (name of the class to invoke a static method of), "method" (name of the method to invoke; "*" means a constructor, and a string starting with a "." means a fieldname), "_" (list of arguments where each element is a map of type {type=xxx, value=xxx} or an object if argument type is equal to the type of the given object). Argument types can be fully qualified class name, class names without "java.lang." prefix such as "String", primitive types such as "int", "float" etc.., or arrays of these such as "String[]". See Dynamic Method Invocation below for more information. 
 System:notifyAll:SIGNAL  notifies all threads waiting (using System:wait). If "operand" is a string, then an internal lock uniquely identified by the string is used as lock, and SIGNAL object is sent to all waiting threads. Otherwise the "operand" object is used as lock, and SIGNAL is ignored. 
 System:resetUniqueId_[:NAME]  resets next unique Id to 0 for given NAME (default "") 
 System:serialize  serializes "operand" into binary (ISO-8859-1) string 
 System:setProperties  sets system properties specified by "operand" map as key/value pairs 
 System:sleep  suspends current thread for given "operand" number of milliseconds 
 System:uniqueId_[:NAME]  returns a unique integer (incremented each time called by any thread) for given NAME (default "") 
 System:wait:WAITTIME  waits for up to WAITTIME milliseconds (0 meaning forever) for notification (given by System:notifyAll). If "operand" is a string, then an internal lock uniquely identified by the string is used as lock, and returns the SIGNAL object sent by System:notifyAll if not timed out, or null. Otherwise, the given "object" itself is used as a lock and returned. 
 System:yield_  yields current thread 
 Thread:currentThread_  returns current thread 
 Thread:interrupt  interrupts given "operand" as Thread 
 Thread:join:WAIT  waits for WAIT milliseconds until given "operand" as Thread stops 
 Thread:maxPriority_  returns thread max priority 
 Thread:minPriority_  returns thread min priority 
 Thread:normPriority_  returns thread normal priority 
 Thread:resume  resumes given "operand" as Thread (deprecated) 
 Thread:sleep  equivalent to System:sleep 
 Thread:stop  stops given "operand" as Thread (deprecated) 
 Thread:suspend  suspends given "operand" as Thread (deprecated) 
 Thread:yield_  equivalent to System:yield 
 Type:add:OBJECT  adds OBJECT to "operand" collection if possible 
 Type:addAll:OBJECT  adds all elements of OBJECT (array or collection) to "operand" collection 
 Type:charAsNumber  returns numeric code for "operand" as a Character 
 Type:clear  clears "operand" as a collection 
 Type:clone  invokes "clone()" method on "operand" if defined 
 Type:countElements  returns histogram of elements in "operand" as Collection or Array, or null 
 Type:forName  returns class object for given "operand" class name, if possible. 
 Type:ifContained:LIST[:DEFAULT]  returns "operand" if "operand" is contained in LIST (or comma-separated string); otherwise returns DEFAULT (default null) 
 Type:ifContains:OBJECT[:ELSEOBJECT]  returns "operand" if OBJECT is contained in "operand" collection, ELSEOBJECT (default null) otherwise 
 Type:ifContainsAll:OBJECT[:ELSEOBJECT]  returns "operand" if all elements of OBJECT (array or collection) are contained in "operand" collection, ELSEOBJECT (default null) otherwise 
 Type:ifEmpty:IFOBJECT[:ELSEOBJECT]  returns IFOBJECT if given "operand" is empty, otherwise ELSEOBJECT (default "operand") 
 Type:ifEqual:TARGET:IFOBJECT[:ELSEOBJECT]  returns IFOBJECT if given "operand" is equal to TARGET, otherwise ELSEOBJECT (default "operand") 
 Type:ifNotEmpty:IFOBJECT  returns IFOBJECT if given "operand" is not empty, otherwise "operand" 
 Type:ifNotEqual:TARGET:IFOBJECT  returns IFOBJECT if given "operand" is not equal to TARGET, otherwise "operand" 
 Type:ifNotNull:IFOBJECT  returns IFOBJECT if "operand" is not null, otherwise null 
 Type:ifNull:IFOBJECT[:ELSEOBJECT]  returns IFOBJECT if "operand" is null, otherwise ELSEOBJECT (operand by default) 
 Type:indexOfSubList:SUBLIST  returns the first index of the SUBLIST in the "operand" list, -1 if not found, or null if either "operand" or "SUBLIST" is not a list. 
 Type:isArray  converts "operand" to Array if possible, otherwise null 
 Type:isBoolean  converts "operand" to Boolean if possible, otherwise null 
 Type:isByte  converts "operand" to Byte if possible, otherwise null 
 Type:isCalendar[:PATTERN:LOCALE:TIMEZONE]  converts "operand" to calendar (instance of java.util.Calendar) if possible, as in Type:isDate. 
 Type:isCharacter  converts "operand" to Character if possible, otherwise null 
 Type:isClass:CLASS  converts "operand" to an instance of given CLASS if possible, otherwise null. CLASS can be either a class object or a class name. If CLASS is a primitive wrapper ("java.lang.Integer" etc.), then "operand" is converted to given CLASS. Otherwise, returns "operand" only when it is an instance of given CLASS. 
 Type:isDate[:PATTERN:LOCALE:TIMEZONE]  converts "operand" to date if possible (according to the given PATTERN and LOCALE if "operand" needs parsing, and TIMEZONE), otherwise null. PATTERN is a date format pattern string used by java.util.SimpleDateFormat. LOCALE is either an instance of java.util.Locale or a map specifying a locale using properties "language", "country", and "variant". TIMEZONE is either an instance of java.util.TimeZone or a map or form/json/xml-encoded string specifying a timezone using "id" property. 
 Type:isDouble  converts "operand" to Double if possible, otherwise null 
 Type:isEmpty  returns Boolean.TRUE if given "operand" is empty, otherwise null 
 Type:isEqual:TARGET  returns Boolean.TRUE if given "operand" is equal to TARGET, otherwise null 
 Type:isFile[:PARENTFILE]  converts "operand" as filename or URI to file (instance of java.io.File) if possible (as a child of PARENTFILE if given), otherwise null. 
 Type:isFloat  converts "operand" to Float if possible, otherwise null 
 Type:isInternetAddress  converts "operand" to valid internet email address (instance of javax.mail.internet.InternetAddress) if possible, otherwise null 
 Type:isList  converts "operand" to List if possible, otherwise null 
 Type:isLocale  converts "operand" to locale (instance of java.util.Locale) if possible. The "operand" can be a map specifying a locale using properties "language", "country", and "variant". 
 Type:isLong  converts "operand" to Long if possible, otherwise null 
 Type:isNestedMap  converts "operand" to a NestedMap if possible (as "__source" property), otherwise null 
 Type:isNotEmpty  returns Boolean.TRUE if given "operand" is not empty, otherwise null 
 Type:isNotEqual:TARGET  returns Boolean.TRUE if given "operand" is not equal to TARGET, otherwise null 
 Type:isNotNull  returns Boolean.TRUE if "operand" is not null, otherwise null 
 Type:isNull  returns Boolean.TRUE if "operand" is null, otherwise null 
 Type:isNumber[:PATTERN:LOCALE]  converts "operand" to number if possible (accordin to the given PATTERN and LOCALEP if "operand" needs parsing), otherwise null. PATTERN is a number format pattern used by java.util.NumberFormat. LOCALE is either an instance of java.util.Locale or a map with with properties "language", "country", "variant". 
 Type:isSQLDate[:PATTERN:LOCALE]  converts "operand" to SQL date if possible, as in Type:isDate, otherwise null. 
 Type:isSQLTime[:PATTERN:LOCALE]  converts "operand" to SQL time if possible, as in Type:isDate 
 Type:isSQLTimestamp[:PATTERN:LOCALE]  converts "operand" to SQL timestamp if possible, as in Type:isDate 
 Type:isShort  converts "operand" to Short if possible, otherwise null 
 Type:isString  converts "operand" to String if possible, otherwise null 
 Type:isStringArray  converts "operand" to an array of Strings (String[]) if possible, otherwise null 
 Type:isStringList[:SEPARATOR:ESCAPE]  converts "operand" to List if possible, otherwise null like Type:isList, but when "operand" is a string, then splits it into a list of Strings using SEPARATOR (default ",") and ESCAPE (default "\"). 
 Type:isTimeZone  converts "operand" to TimeZone (instance of java.util.TimeZone) if possible. The "operand" can be a map or form/json/xml-encoded string specifying a timezone by "id" propery (e.g., "id=JST" for Japan standard timezone) 
 Type:isURI  converts "operand" to URI (instance of java.net.URI) if possible, otherwise null 
 Type:isURL[:CONTEXT]  converts "operand" to URL (instance of java.net.URL) if possible (within CONTEXT URL, if given), otherwise null 
 Type:lastIndexOfSubList:SUBLIST  returns the last index of the SUBLIST in the "operand" list, -1 if not found, or null if either "operand" or "SUBLIST" is not a list. 
 Type:length  returns the length of "operand" (collection or array) if possible, otherwise -1 
 Type:makeSynchronized  returns the synchronized version of given "operand" Collection 
 Type:makeUnmodifiable  returns the unmodifiable version of given "operand" Collection 
 Type:numberAsChar  returns Character for given numeric code "operand" 
 Type:numericValueOf  returns numeric value of given "operand" as a Character 
 Type:remove:OBJECT  removes OBJECT from "operand" collection 
 Type:removeAll:OBJECT  removes all elements of OBJECT (array or collection) from "operand" collection 
 Type:retainAll:OBJECT  retains all elements of OBJECT (array or collection) in "operand" collection 
 Type:reverse  reverses "operand" as a list 
 Type:rotate:DISTANCE  rotates "operand" by DISTANCE as a list 
 Type:shuffle  shuffles "operand" as a list 
 Type:subList:START[:END]  returns the sublist of the "operand" list, starting at START (inclusive) and ending at END (exclusive; default end of list). START/END can be negative to indicate relative index from the end (e.g., -1 as START means last element) 
 Type:unicodeBlockOf  returns unicode block of given "operand" as a Character 
 URL:decode[:ENCODING]  decodes "operand" as URL-encoded string using ENCODING (default "utf-8") 
 URL:encode[:ENCODING]  encodes "operand" as String in URL format (e.g., "a b" becomes "a+b") using ENCODING (default "utf-8") 
 URL:nameType  guesses content type of the given "operand" as URL string 
 URL:normalize  normalizes "operand" as URI 
 URL:relativize:BASE  relativizes "operand" as URI against BASE 
 URL:resolve:BASE  resolves "operand" as URI against BASE 
 URL:streamType  guesses content type of the given "operand" as byte stream 
 XML:appendNode:PARENT  appends "operand" Node as the last child of PARENT Node; "operand" can be a NodeMap
 XML:cloneNode  makes shallow copy of "operand" Node. 
 XML:copyNode  makes deep copy of "operand" Node. 
 XML:decode  un-escapes special tag characters from "operand" as String (>, <;, &, ", ', { (&#123;), and } (&#125;)) 
 XML:encode[:PATTERN]  escapes special tag characters from "operand" as string (>,<,&,",',{ (&#123;), and } (&#125;)). You can specify a subset of supported characters to be encoded by giving matching PATTERN regular expression (e.g., "[<>]" to encode "<" and ">" only). If PATTERN is "~" (tilda), then "[&<>]" is assumed. 
 XML:getAttribute:NAME  gets the value of an attribute named NAME of "operand" Element Node. 
 XML:insertNodeBefore:BEFORE  inserts "operand" Node before BEFORE Node; "operand" can be a NodeMap
 XML:normalizeNode  normalized "operand" Node. 
 XML:output[:CONTROLMAP]  outputs "operand" as XML document according to the specifications given by CONTROLMAP (map or encoded string). The CONTROLMAP supports standard XSLT output attributes ("method", "version", "encoding", "omit-xml-declaration", "standalone", "doctype-public", "doctype-system", "cdata-section-elements", "indent", and "media-type"). Default is "omit-xml-declaration=yes". 
 XML:parseHtml[:CONTROLMAP]  parses HTML as in <m:parseHtml>. CONTROLMAP supports attributes of <m:parseHtml>: "include", "exclude", "strategy", and "rootName". 
 XML:parse[:CONTROLMAP]  parses "operand" as XML document according to the specifications given by CONTROLMAP (map or encoded string). The CONTROLMAP supports the following boolean properties: "namespaceAware", "ignoringComments", "ignoringElementContentWhitespace", "expandEntityReferences", "coalescing", and "validating". Default value is "true" except "validating". 
 XML:removeNode  removes "operand" Node from its parent 
 XML:replaceNode:OLD  replaces OLD Node with "operand" Node; "operand" can be a NodeMap
 XML:setAttribute:NAME:VALUE  sets the value of an attribute named NAME of "operand" Element Node to VALUE. 
 XMLMap:decode[:CONTROLMAP]  converts "operand" XML document into NestedMap according to the specifications given by CONTROLMAP (map or encoded string). See XMLMap below for more information. 
 XMLMap:encode[:CONTROLMAP]  outputs "operand" NestedMap as XML document according to the specifications given by CONTROLMAP (map or encoded string). See XMLMap below for more information. 
 Zip:decode or Zip:decompress  decompresses "operand" as Zip-compressed string 
 Zip:encode or Zip:compress  compresses "operand" string using Zip 
 _JSP:applyCodec:CODEC  applies CODEC to the "operand" 
 _JSP:applyFilter:CONTROLMAP  applies filter defined by CONTROLMAP to the "operand" as in <m:filter>. CONTROLMAP supports the following properties: "include", "break", "apply", "applyCodec". 
 _JSP:binarySearch:KEY[:CONTROLMAP]  performs binary search for KEY on a sorted "operand" list, optionally using CONTROLMAP which specifies the following: "codec" (codec to be applied to each element of list before comparison), "equal" (codec that returns "true" when two elements "${_operand.x}" and "${_operand.y}" are considered equal), "more" (codec that returns "true" when "${_operand.x}" is considered greater than "${_operand.y}"). Returns a non-negative integer index of KEY in the "operand" list if found, otherwise a negative integer (which is equal to "-(index + 1)" where "index" is the index for KEY to be inserted), as in java.util.Collections.binarySearch. 
 _JSP:call:CONTROLMAP  calls a JSP as in <m:call> tag with "operand" parameter map. CONTROLMAP is a map or encoded string that specifies the following: "path" (path of JSP; mandatory), "contextPath" (context path of JSP for cross-context call; optional), "doesForward" (forwards if set to true) 
 _JSP:clear  clears "operand" (or pageContext.out if not given) as JspWriter and returns given "operand" 
 _JSP:dynamicIterator  creates a dynamic iterator that calls codecs specified by "hasNextCodec" and "nextCodec" properties of the "operand" map on "hasNext" and "next" operations. The specified codecs are called with the dynamic iterator itself as the "operand". The following special properties are supported: "collection" (collection to iterate over), "next" (next object to be returned, overriding "collection" or "nextCodec"), "hasNext" (boolean value that specifies if the iterator has more objects, overriding "collection" or "hasNextCodec"), "index" (0-based index which is increased each "next" operation). See Dynamic Iterator below for more information. 
 _JSP:dynamicMap  creates a dynamic map that calls codecs specified as "getCodec" and "putCodec" properies of the "operand" map on "get" and "put" operation. The specified codecs are called with the dynamic map itself as the "operand" having "key" and "value" set to the key and value of the get/set operation. The "_" (underscore) variable is also set to the "operand" map upon codec invocation. See Dynamic Map below for more information. 
 _JSP:encodeRedirectURL  encodes "operand" as redirect URL including session ID if necessary 
 _JSP:encodeURL  encodes "operand" as URL including session ID if necessary 
 _JSP:eval[:CONTROLMAP]  evaluates "operand" as EL (or a map of EL values) according to the specifications given by CONTROLMAP (map or encoded string). The CONTROLMAP supports the following properties: "pattern", "recursive", "evalCodec", "keyCodec", "allowGroup", "environment", as in <m:eval> tag below. 
 _JSP:flush  flushes "operand" (or pageContext.out if not given) as Writer and returns given "operand" 
 _JSP:getAttributes[:SCOPENAME]  returns a map containing variable/value pairs for given list of variables in given SCOPENAME (default = page). The "operand" can be a list/arrary or a comma-separated list of variable names. If "operand" is null (or called as _JSP:getAttributes_), then all variables currently in the given scope are copied. 
 _JSP:getLogWriter  creates an instance of LogWriter (java.io.Writer that writes to a specified log) according to "operand" as map (or encoded string); properties supported are "destination", "category", and "log" as in <m:log> tag. 
 _JSP:getMessageMap_[:]  creates a resource message map, optionally from a map that specifies the following properties: "basename" (resource base name), "defaultValue" (default value to be returned when resource is missing). See MessageMap below for more information. 
 _JSP:getMimeType  returns mime type of "operand" as filename 
 _JSP:getPageScope_[:INDEX]  returns pageScope variables for the entry in the callStack at given INDEX (default 0) as a writable map. This can be used to get/set variables in given pageScope (especially outer pageScope from within a tag file) 
 _JSP:getRealPath  returns real filesystem path of "operand" as URL 
 _JSP:getResource  returns resource URL of "operand" as path 
 _JSP:hasSession_  returns current session as HttpSessionMap (session attributes as a map), or null if none. 
 _JSP:invalidateSession_  invalidates current session and returns null. 
 _JSP:isCalled_  returns true if this JSP is "called" by another JSP. 
 _JSP:log[:CONTROLMAP]  logs "operand" according to the specification by optional CONTROLMAP. CONTROLMAP is a map or form/json/xml-encoded string that specifies the following properties as in <m:log> tag: "destination", "category", and "log"; Default is "destination=log". 
 _JSP:max[:CONTROLMAP]  returns the largest element in the "operand" as Collection using CONTROLMAP which can specify the following: "codec" (codec to be applied to each element of list before comparison), "equal" (codec that returns "true" when two elements "${_operand.x}" and "${_operand.y}" are considered equal), "more" (codec that returns "true" when "${_operand.x}" is considered greater than "${_operand.y}") 
 _JSP:min[:CONTROLMAP]  returns the smallest element in the "operand" as Collection using CONTROLMAP which can specify the following: "codec" (codec to be applied to each element of list before comparison), "equal" (codec that returns "true" when two elements "${_operand.x}" and "${_operand.y}" are considered equal), "more" (codec that returns "true" when "${_operand.x}" is considered greater than "${_operand.y}") 
 _JSP:newSession_  invalidates current session and returns a new session as HttpSessionMap (session attributes as a map). 
 _JSP:putAttributes[:SCOPENAME]  puts all key/value pairs in the "operand" map as variable/value pairs for given SCOPENAME (default = page) 
 _JSP:setResponse:CONTROLMAP  sets HTTP response according to properties defined by CONTROLMAP (map or form/json/xml-encoded string) as in <m:response> tag ("header", "error", "errorMessage", "redirect", "cookie") and returns "operand" as-is. 
 _JSP:setRootPageContext_[:OVERWRITE]  saves current pageContext in requestScope as the pageContext of the root element of the call stack. If OVERWRITE is true, then always overwrites, otherwise overwrites only when current value is null. Returns the pageContext before replacement. 
 _JSP:sort[:CONTROLMAP]  sorts "operand" as list using CONTROLMAP which specifies the following: "codec" (codec to be applied to each element of list before comparison), "equal" (codec that returns "true" when two elements "${_operand.x}" and "${_operand.y}" are considered equal), "more" (codec that returns "true" when "${_operand.x}" is considered greater than "${_operand.y}") 

In Java terms, a codec is any public static method that takes one or more Object arguments and returns an Object; i.e., of the following type:

public static Object codec(Object operand, Object opt1, Object opt2, ...)

Built-in codecs are defined in com.micronova.util.codec package using "Codec" classname prefix. For example, "URL:encode" calls the static method "encode" defined in "com.micronova.util.codec.CodecURL".

You can call your own external codec by using fully qualified class name; e.g., a codec named "abc" in package "com.yourcompany.codec" can be specified by "com.yourcompany.codec:abc".

If necessary, you can call a codec with "implicit" arguments of the following type:

public static Object codec(Object implicit1, Object implicit2, ..., Object operand, Object opt1, Object opt2, ...)

Implicit arguments can be specified using the following syntax:

CODECCLASS:CODECNAME;implicit1;implicit2;...:opt1:opt2:...

If CODECCLASS starts with an "_" (underscore), then current pageContext is passed implicitly; e.g., "_JSP:eval" is equivalent to "JSP:eval;@{pageContext}".

4 Local Variables

All YUZU tags can have tag body. If you need temporary variables to hold values within the tag body, you can use local attribute to specify a comma-separated (or space/tab/newline-separated) list of variables that are "local" to the tag body. The value of a "local" variable is saved before evaluating the tag body, and restored once tag body evaluation is done.

The following outputs "a=AAA, b=BBB" and then "a=A, b=B":

<m:set var="a" value="A"/>

<m:set var="b" value="B"/>

<m:out local="a,b">
  <m:set var="a" value="AAA"/>
  <m:set var="b" value="${a}"/>
  <m:out value="a=${a}, b=${b}"/>
</m:out>

<m:out value="a=${a}, b=${b}"/>

The scope of "local" variables is "page" by default, but can be specified by using localScope attribute.

There is a special request-scoped local variable named "_" (underscore) that holds the prepared tagvalue within the body of a YUZU tag. For example:

<m:set var="map" className="java.util.HashMap">
  <m:set property="a" value="A"/>
  <m:set property="b" value="B"/>
  <m:set property="c" value="${_.a}${_.b}"/>
</m:set>

<m:out value="${map.c}"/>

outputs "AB".

The "_" variable reflects changes made by using attribute attribute. For example:

<%-- this outputs "a-a/a-a" --%>

<m:out value="a">

  <%-- resets tagValue to "a-a" --%>

  <m:set attribute="value" value="${_}-${_}"/>

  <%-- resets tagValue to "a-a/a-a" --%>

  <m:set attribute="value" value="${_}/${_}"/>

</m:out>

When localScope is set in a Yuzu tag, then it is used as the default variable scope by descendent Yuzu tags. For example:

<m:set localScope="request">
  <%-- this uses "request" scope --%>
  <m:set var="x" value="XXX"/>
  <%-- this uses "page" scope --%>
  <m:set var="y" value="YYY" scope="page"/>
</m:set>

Wnen necessary, you can use a map (or a XML/JSON/form-encoded string) as the value of local attribute to initialize local variables (keys are used as variable names, and values are used as initial values). For example:

<m:set var="a" value="alpha"/>
<m:set var="b" value="beta"/>

<m:out local="{a:1, b:2}">
  a is ${a}, b is ${b}       
</m:out>

a is ${a}, b is ${b}

outputs "a is 1, b is 2" followed by "a is alpha, b is beta".

5 Common Attributes

All YUZU tags support the following attributes, unless otherwise specified (those of type "EL" are strings where "@{" are translated to "${"):

 name  type  description  default value 
 value  Object  tagValue to be set  null 
 className  EL  name of java class of which the tagValue is instantiated  null 
 source  Object  object or map to be used to initialize the tagValue  null 
 var  String  name of variable to which the tagValue is assigned  null 
 scope  String  scope of var variable (either "page", "request", "session", or "application")  page 
 target  Object  target Java bean whose property is to be set  null 
 property  String  name of the target bean property to be set  null 
 attribute  String  name of the tag attribute to be set  null 
 default  Object  default value to be used as tagValue when the tagValue is null (or when test EL expression evaluates to false)  null 
 test  EL  boolean EL expression that evaluates to false to make default used  null 
 prepareCodec  EL  codecs to be applied to the tagValue before processing the tag body  null 
 importCodec  EL  codecs to be applied to the tag body on importing  null 
 processCodec  EL  codecs to be applied to processed tagValue  null 
 codec  EL  alias for processCodec  null 
 assignCodec  EL  codecs to be applied to the value to be assigned (value of assign EL expression; default is the tagValue itself)  null 
 exportCodec  EL  codecs to be applied to the value to be exported (value of export EL expression; default is the tagValue itself)  null 
 cleanupCodec  EL  codecs to be applied to the prepared tagValue on cleanup; exceptions are ignored  null 
 assign  EL  EL expression that defines object to be assigned (with underscore (_) representing the tagValue itself)  ${_} (tagValue itself) 
 export  EL  EL expression that defines object to be exported (with underscore (_) representing the tagValue itself)  ${_} (tagValue itself) 
 doesExport  String  forces export if set to "always"  default 
 local  String  comma-separated list of page-scoped variables that are "local" for this tag (saved on tag entry, restored on exit)  null 
 localScope  String  scope of local variables, and also default scope for its descendents  null (meaning "page" scope) 

6 Tag Stacking

All YUZU tags can be nested beyond tag file boundaries (called "stackable" in this document) using a request-scope tag stack. For example, if you have a tag "<u:url>" defined by a tag file like this (tag definitions are omitted):

<%@ tag %>
<%@ attribute name="prefix" %>
<%@ attribute name="target" type="java.lang.Object"%>
<%@ attribute name="property" %>
<%@ attribute name="attribute" %>

<m:map target="${target}" property="${property}" attribute="${attribute}" 
    codec="Bean:get:@param.__encodedSorted|String:prepend:?:@{!empty _operand}|String:prepend:@{_.prefix}">
  <m:set property="prefix" value="${prefix}"/>
  <m:map property="param">       
    <jsp:doBody/>
  </m:map>
</m:map>

then you can output a "url" like this:

<%-- this outputs "http://www.micronova.com?a=alpha&b=beta" --%>

<m:map var="ENV"/>

<u:url target="${ENV}" property="url" prefix="http://www.micronova.com">
  <m:set property="a" value="alpha"/>
  <m:set property="b" value="beta"/>
</u:url>

${ENV.url}

Note that the <m:set> statements above use the map defined by the <m:map> tag surrounding <jsp:doBody/> in the tag file as their target.

When necessary, it is possible to get a shallow copy of the current tag stack by using "_JSP:getCallStack_" codec. "_JSP:getCallStack_" returns a list of tag stack entries with the closest ancestor first, and each tag stack entry is a map with the following properties: 'tag' (instance of YUZU tag object), 'pageContext' (value of pageContext for the tag), and optionally 'hidden' (if set to true, then the tag is ignored when searching for ancestor YUZU tags). Other properties can be set for custom usage - for example:

<%-- 
  't:swallow' tag marks itself hidden and also 'swallow' 
  so 't:output' tag can find in the tag stack
--%>

<%@ tag %><m:out export="" value="${pageContext.out}">
  <m:set var="stackEntry" prepareCodec="_JSP:getCallStack_|Bean:get:0">
    <m:set property="hidden" value="true"/>
    <m:set property="swallow" value="true"/>
  </m:set>        
  <jsp:doBody/>
</m:out>

<%-- 
  't:output' tag finds the closest ancestor with 'swallow' mark 
  and appends the output to it's value (pageContext.out) 
--%>

<%@ tag %>
<%@ attribute name="value" %>
<%@ attribute name="codec" %>
<m:set var="output" value="${value}" assignCodec="${codec}"><jsp:doBody/></m:set>
<m:filter var="swallowTag" prepareCodec="_JSP:getCallStack_" include="@{_element['swallow'] == true}" assignCodec="@{_[0].tag}"/>
<m:set target="${swallowTag}" property="value" value="${swallowTag.value}" codec="String:append:@{output}"/>

<%-- 
  then the following code outputs 'Hello' and 'World' followed by newlines 
--%>

<t:swallow>
  This is not output
  <t:output codec="Backslash:decode">Hello\n</t:output>
  This is not output
  <t:output codec="Backslash:decode">World\n</t:output>
  This is not output
</t:swallow>

The last element of the list returned by _JSP:getCallStack_ is a map with only one property 'pageContext'. The value of 'pageContext' of this last entry is the value of a request scope variable set by "_JSP:setRootPageContext_" codec (to be the value of the PageContext when this is called). This can be used to access outer pageScope variables from within a tag file. For example, using "_JSP:getPageScope_" codec which returns pageScope variables in the pageContext at 0-th index in the call stack:

<%-- with a tag file name "t:test" (tag file declarations are omitted): --%>
<m:set var="env" codec="_JSP:getPageScope_"/>
<m:set export="" value="${env}">
  <m:set property="P" value="${_.P}${_.P}"/>
  <m:set property="Q" value="q"/>
</m:set>
<jsp:doBody/>

<%-- this JSP outputs:
  outside before: a, b
  inside:aa, q
  outside after:aa, q
--%>
<m:set export="" codec="_JSP:setRootPageContext_"/>
<m:set var="P" value="a"/>
<m:set var="Q" value="b"/>
outside before: ${P}, ${Q}
<t:test>
  inside:${P}, ${Q}
</t:test>
outside after:${P}, ${Q}

"_JSP:setRootPageContext_" by default does not overwrite existing PageContext value, and can be put in a JSP prelude code.

7 Tags

YUZU consists of the following tags:

 name  summary 
 set  sets a variable 
 out  outputs a value 
 map  nested map structure 
 eval  evaluates expression 
 param  structured form parameters 
 call  subroutine call 
 return  returns a value to the caller 
 value  modifies the tagValue of the parent 
 include  http client 
 log  server log output 
 postData  posted HTTP data 
 throw  throws an Exception 
 synchronized  synchronizes tag processing 
 query  SQL query with embedded expressions 
 update  SQL update with embedded expressions 
 transaction  stackable SQL transactions 
 response  HTTP response control 
 system  system call 
 filter  filters elements 
 parseHtml  parses HTML document 
 mail  sends email 
 mailFolder  retrieves email 

7.1 set

<m:set> is an enhanced version of JSTL <c:set>. It supports all common attributes, and serves as the default YUZU tag (with no processing done in Process stage)

7.2 out

<m:out> is an alias for <m:set> without support for the following assignment-related attributes: var, scope, target, property, attribute, assign, assignCodec.

7.3 map

<m:map> is a tag with a map (key-value pairs) prepared as its tagValue. For a given key, you can get/set its value using the key as the map's "property". For Example,

<%-- initializes a map --%>

<m:map var="x"/>

<m:set target="${x}" property="a" value="alpha"/>

<m:out value="a is ${x.a}"/>

outputs the following:

a is alpha

You can "nest" maps as follows:

<%-- setting up a nested map --%>

<m:map var="account">
  <m:set property="balance" value="100"/>
  <m:map property="customer">
    <m:set property="firstName" value="John"/>
    <m:set property="lastName" value="Doe"/>
  </m:map>
</m:map>

then, the following:

Account Balance of <m:out value="${account.customer.firstName} ${account.customer.lastName}"/>
is <m:out value="${account.balance}"/>.

outputs:

Account Balance of John Doe is 100.

You can set the "firstName" in the above example in the following two ways:

<%-- using "account.customer" as the target --%>

<m:set target="${account.customer}" property="firstName" value="Johnny"/>

<%-- or, using a "nested property name" starting with "@" --%>

<m:set target="${account}" property="@customer.firstName" value="Johnny"/>

If a property name starts with "@", then the rest of the propery name is taken as nested property specification using "dot" notation. Note that if "@" is omitted, then the whole string "customer.firstName" (including the "dot") is taken as the property name (if necessary, you can start the property name with "#" to force the rest to be taken as a non-nested property name, even if it starts with "@").

When a nested property name is used, then non-existent intermediate maps are automatically created. For example, the nested map above can also be created as follows:

<%-- setting up a nested map using nested properties--%>

<m:map var="account">
  <m:set property="@balance" value="100"/>
  <m:set property="@customer.firstName" value="John"/>
  <m:set property="@customer.lastName" value="Doe"/>
</m:map>
In this case, the intermediate map "${account.customer}" is created by the <m:map> tag automatically and initialized as "{firstName=John, lastName=Doe}".

There is a special propery named "__encoded" (with two underscores) which can be used to convert a nested map to/from form-style encoded string ("x=a&y=b&..."). The following code:

<m:out value="${account.__encoded}"/>

outputs:

balance=100&customer.lastName=Doe&customer.firstName=John

You can use "__encodedSorted" instead of "__encoded" to sort the output by key when necessary.

There also are special properties for other formats: "__json" for JSON-style output, "__xml" for XML output, "__dom" for DOM output, and "__attrList" for XML attribute list output. For example:

<m:out value="${account.__json}"/>

<%-- this outputs: 

{"balance":"100","customer":{"firstName":"John","lastName":"Doe"}}

 --%>

<m:out value="${account.__xml}"/>

<%-- this outputs: 

<root><balance>100</balance><customer><firstName>John</firstName><lastName>Doe</lastName></customer></root> 

--%>

<m:out value="${account.__attrList}"/>

<%-- this outputs: 

balance="100" customer.lastName="Doe" customer.firstName="John"

--%>

You can also set up a map from a form-style string as follows:

<m:map var="account">
  <m:set property="__encoded">
    balance=100&customer.lastName=Doe&customer.firstName=John
  </m:set>
</m:map>

and other output properties such as "__json", "__xml", or "__dom" can be used to set up a map from corresponding output.

Each map also has a special element named "_" (single underscore) which is a sparse list ("sparse" means that you can set elements at any index in any order). You can set elements of the "_" list using "@_.property" where "property" is an integer, "*", or "*" followed by an integer the same way as in Assign stage. For example:

<m:map var="map">
  <m:set property="@_.5" value="Fifth"/>
  <m:set property="@_.2" value="Second"/>
  <m:set property="@_.*" value="Last"/>
</m:map>

<c:forEach var="element" items="${map._}" varStatus="status">
  <m:out value="${status.index}:${element}"/>
</c:forEach>

outputs the following:

0: 1: 2:Second 3: 4: 5:Fifth 6:Last

Elements of the "_" list are encoded/decoded as "_.index=xxx" or "_.index.key=value" (when the list element is a map). For example:

<m:map export="@{_.__encodedSorted}">
  <m:set property="@_.*" value="NAMES"/>
  <m:map property="@_.*">
    <m:set property="firstName" value="John"/>
    <m:set property="lastName" value="Doe"/>
  </m:map>
  <m:map property="@_.*">
    <m:set property="firstName" value="Jane"/>
    <m:set property="lastName" value="Doe"/>
  </m:map>
</m:map>

outputs:

_.0=NAMES&_.1.firstName=John&_.1.lastName=Doe&_.2.firstName=Jane&_.2.lastName=Doe

Properties starting with a single underscore other than "_" are hidden from the key list, and also not copied when used with source attribute or __source property.

You can use source attribute to initialize a <m:map> tag from a map, a form/json/xml-encoded string, or a list of maps or encoded strings (when source is a list, elements are copied to the "_" (underscore) list). For example:

<%-- create a map from encoded string --%>

<m:map var="x" source="a=alpha&b=beta"/>

<%-- make a copy of "x" --%>

<m:map source="${x}"/>

<%-- copy a list.  This outputs "{_=[1, 2, 3, 4, 5]}" --%>

<m:set var="list" value="1,2,3,4,5" codec="String:split:,"/>

<m:map source="${list}"/>

If source is a string starting with "@", then the rest of the string is first used as source and then the resulting map is evaluated as in <m:eval>. For example:

<%-- sets x to {a=alpha,b=beta} using json-encoded evaluated source --%>
<m:set var="a" value="alpha"/>
<m:set var="b" value="beta"/>
<m:map var="x" source="@{a=@{a},b=@{b}}"/>
<%-- or using evaluated xml source --%>
<m:map var="x" source="@<root><a>@{a}</a><b>@{b}</b></root>"/>

You can also use attribute attribute (or "__source" property) within the tag body to set source. In this case, existing key/value pairs are overwritten:

<%-- outputs "a=A&b=beta&c=C" --%>

<m:map source="a=alpha&b=beta" export="@{_.__encodedSorted}">
  <m:set attribute="source" value="a=A&c=C"/>
  <%-- or alternatively <m:set property="__source" value="a=A&c=C"/> --%>
</m:map>

Note that source makes "shallow" copy.

Special property names supported are as follows (all starting with two underscores; "get/set" indicates if the property can be used to "get" values or "set" values):

 name  description  type  get/set 
 __keyList  list of keys  List  get 
 __valueList  list of values  List  get 
 __entryList  list of entries (key/value pairs)  List  get 
 __encoded  nested key/value pairs as form-encoded String  String  get/set 
 __param  nested key/value pairs as map  Map  get/set 
 __keyListSorted  list of keys, sorted  List  get 
 __entryListSorted  list of entries, sorted by key  List  get 
 __encodedSorted  same as _encoded, but sorted by key  String  get 
 __listSize  size of the "_" list  Integer  get 
 __listActualSize  actual number of elements in the "_" sparse list  Inger  get 
 __source  copies values from Map, List, or form-encoded string  Map/List/String  set 
 __xml  XML output  String  get/set 
 __dom  XML DOM output  Node  get/set 
 __json  JSON output  String  get/set 
 __attrList  XML attribute list output  String  get 
 __leaf  map of leaf elements (with non-composite (map/list) values)  Map  get 
 __submap  map of elements with map values (submaps)  Map  get 

Attributes specific to <m:map> are as follows:

 name  type  description  default value 
 source  Object  source of map  null 
 bodyProperty  String  if not null, then tag body string is assigned to this property  null 

See XMLMap on encoding/decoding to/from XML, and JSON/Javscript on encoding/deconding to/from JSON.

When necessary, it is possible to specify what keys are acceptable for a map. Acceptable keys can be specified using a map or form-encoded string that maps key names to either "r" (read-only), "w" (write-only), or "b" (both) as follows:


<%-- sets a map that accepts "x" as read-only key, "y" as write-only key, and "z" as read-write key --%

<m:map var="p" prepareCodec="Bean:setProperty:acceptable:x=r&y=w&z=b"/>

When non-null acceptable key map is specified, an exception is thrown when a non-acceptable key is used.

7.4 eval

<m:eval> evaluates the tag body (tagValue) as an EL expression using a custom pattern (default is "@{X}" for expression "X"). For example, the following code:

<m:set var="a" value="3"/>
<m:set var="b" value="5"/>

<m:eval>
  a is @{a}, b is @{b}, and a + b is @{a + b}
</m:eval>

outputs:

a is 3, b is 5, and a + b is 8

You can specify your own regular expression pattern to be used instead of "@{...}" by using pattern attribute (if you are not familiar with java regular expressions, please consult Sun tutorial). The value of pattern attribute is a regular expression whose first "capturing group" (string matching the expression inside the first parentheses) is used as the EL expression. The default pattern is "[@]\{([^}]*)\}". The following two are equivalent:

<%-- using default pattern --%>

<m:eval>
  a is @{a} and b is @{b}
</m:eval>

<%-- using custom pattern "[[XXX]]" --%>

<m:eval pattern="\[\[([^\]]*)\]\]">
  a is [[a]] and b is [[b]]
</m:eval>

If pattern doesn't contain an "(" (open parenthesis), then it is assumed to indicate the prefix for "{...}" and "\{([^}]*)\}" is appended to make a full regular expression. For example, the following sets the pattern to "!{...}":

<%-- using "!{....}" pattern --%>

<m:eval pattern="[!]">
  a is !{a} and b is !{b}
</m:eval>

You can use evalCodec attribute to specify codecs to be applied to the result of each EL evaluation:

<%-- applies "XML:encode" --%>

<m:set var="text" value="<B>BOLDTEXT</B>"/>

<m:eval evalCodec="XML:encode">
This is @{text}.
</m:eval>

literally outputs the following:

This is &lt;B&gt;BOLDTEXT&lt;/B&gt;.

Also you can use keyCodec attribute to specify codecs to be applied before EL evaluation:

<m:map var="x" source="a=alpha&b=beta"/>

<m:eval keyCodec="String:prepend:x.">
  A is @{a} and B is @{b}        
</m:eval>

outputs "A is alpha and B is beta". When necessary, you can set valueCodec to "noeval" to disable EL evaluation:

<%-- this outputs "A is #a and B is #b" --%>

<m:eval keyCodec="String:prepend:#" evalCodec="noeval">
  A is @{a} and B is @{b}        
</m:eval>

You can use environment attribute to set the "_" (underscore) variable for use in evaluation:

<%-- expression to be evaluted --%>

<m:set var="expr">
  a is @{_.a} and b is @{_.b}
</m:set>

<%-- intialized an environment --%>

<m:map var="env1">
  <m:set property="a" value="AAA1"/>
  <m:set property="b" value="BBB1"/>
</m:map>

<%-- intialized another environment --%>

<m:map var="env2">
  <m:set property="a" value="AAA2"/>
  <m:set property="b" value="BBB2"/>
</m:map>

<%-- evaluate "expr" according to "env1" --%>

<m:eval environment="${env1}" value="${expr}"/>

<%-- evaluate "expr" according to "env2" --%>

<m:eval environment="${env2}" value="${expr}"/>

When necessary, you can set recursive attribute to "true" to perform recursive EL evaluation. The following code:

<m:set var="welcomeMessage" value="welcome, @{userName}"/>
<m:set var="userName" value="john"/>
<m:eval recursive="true">@{welcomeMessage}</m:eval>

outputs:

welcome, john

When the tagValue is a NestedMap, then each key value is evaluated as above:

<%-- outputs "<root><a>alpha</a><b>beta</b></root>" --%>

<m:map var="x" source="a=@{a}&b=@{b}"/>
<m:set var="a" value="alpha"/>
<m:set var="b" value="beta"/>
<m:eval value="${x}" codec="XMLMap:encode"/>

You can also use JSP:eval codec instead:

<m:set var="a" value="3"/>
<m:set var="b" value="5"/>

<%-- these two are equivalent --%>

<m:eval>a is @{a}, b is @{b}, and a + b is @{a + b}</m:eval>

<m:out codec="_JSP:eval">a is @{a}, b is @{b}, and a + b is @{a + b}</m:out>

Attributes specific to <m:eval> are as follows:

 name  type  description  default value 
 pattern  String  pattern to be used as EL expression  [@]\\{([^}]*)\\} 
 recursive  Boolean  enables recursive evaluation  false 
 evalCodec  EL  codecs applied to each evaluated EL expression  null 
 keyCodec  EL  codecs applied to each expression before EL evaluation  null 
 allowGroup  Boolean  enables regular expression group specification ("$1") in the value of EL expression  false 
 environment  Object  sets the "_" variable to be used in evaluation  null 

7.5 param

<m:param> is a special kind of <m:map> that builds a nested map from the form parameter string in Process stage (as if it were given as the "__encoded" property). For example, the following JSP page:

<m:param var="in"/>

<m:out value="${in.user}"/>

outputs the map "${in.user}" as follows if "user.first=John&user.last=Doe" is given as form parameters:

{first=John, last=Doe}

Conversion from form parameter string is done in Process stage (after processing the tag body), so you can set default values for optional form parameters as follows:

<%-- outputs the value of form parameter "x" or "DEFAULT" if not given --%>

<m:param var="in">
  <m:set property="x" value="DEFAULT"/>
</m:param>

<m:out value="${in.x}"/>

There is a special property "request" which holds the current servlet request object (an instance of javax.servlet.http.HttpServletRequest). You can for example obtain the current request URI as "${in._request.requestURI}" if "${in}" holds the <m:param> structure.

When necessary, you can use parameterMap attribute to specify a form-encoded string or a map to be used instead of the actual parameter map of the request. For example, you can use encoded name with HTML "SUBMIT" button as follows:

<%-- this "turns on" the clicked button --%>

<m:param var="in">
  <m:set property="maxRows" value="3"/>
  <m:set property="maxColumns" value="3"/>
</m:param>

<m:param target="${in}" property="__source">
  <m:set attribute="parameterMap" value="${in.SUBMIT.__keyList}" codec="String:join"/>
</m:param>

<HTML>
  <BODY>
    <FORM METHOD="POST">
      <TABLE CELLPADDING="4">
        <c:forEach var="row" begin="1" end="${in.maxRows}">
          <TR>
            <c:forEach var="column" begin="1" end="${in.maxColumns}">
              <m:map var="submit" assign="@{_.__encoded}">
                <m:set property="row" value="${row}"/>
                <m:set property="column" value="${column}"/>
              </m:map>
              <m:set var="cellAttribute" test="${row == in.row && column == in.column}">BGCOLOR="#000000"</m:set>
              <m:eval>
                <TD @{cellAttribute}>
                  <INPUT TYPE="SUBMIT" NAME="SUBMIT.@{submit}" VALUE="Click Here">
                </TD>
              </m:eval>
            </c:forEach>
          </TR>
        </c:forEach>
      </TABLE>
    </FORM>
  </BODY>
</HTML>

You can use encoding attribute to set the character set to be used in URL decoding, if necessary (default is null meaning system default). If encoding is set to "*", then either the request encoding (if available) or default encoding ("utf-8", or the value of a configuration variable "com.micronova.jsp.tag.ParamTag.defaultEncoding" evaluated as EL) is used.

You can specify the max content-length acceptable by maxContentLength attribute. If maxContentLength is positive, then HTTP requests with content-length larger than given maxContentLength are quietly ignored. If maxContentLength is negative, then HTTP requests with content-length larger than the absolute value of given maxContentLength throws an Exception with message "max content length exceeded". You can use a configuration variable named "com.micronova.jsp.tag.ParamTag.maxContentLength" to set the default value for maxContentLength attribute as EL.

You can specify codecs to be applied to each form parameter name/value before it is put into the map structure using nameCodec and valueCodec attribute. nameCodec is applied to each parameter name (default is to remove __ (two underscores)), and valueCodec is applied to each parameter value (default is to encode XML tags to help deal with XSS (cross-site-scripting)).

<m:param> handles certain parameter names specially. If the parameter matches the regular expression pattern given as selectPattern attribute, then it is considered as a dropdown list parameter and specially treated; e.g., if selectPattern is "select_.*" and "select_x=a" is given, then it is treated as if "select_x_SELECTED.a=SELECTED" were also given. Similarly, if the parameter matches the regular expression pattern given as radioPattern attribute, then it is considered as a radio button parameter; e.g., if radioPattern is "radio_.*" and "radio_x=a" is given, then it is treated as if "radio_x_CHECKED.a=CHECKED" were also given. By default these are treated as single-valued (i.e., only the last parameter of the given name takes effect), but if the parameter name also matches the regular expression pattern given as multiPattern attribute, then it is treated as multi-valued. For example:

<m:set var="in">
  <m:param attribute="value" control="multiPattern=m_.*&selectPattern=.*s_.*&radioPattern=.*r_.*"/>
  <c:if test="${empty _.submit}">
    <m:set property="@m_s_x_SELECTED.USA" value="SELECTED"/>
    <m:set property="@m_r_x_CHECKED.INCLUDE" value="CHECKED"/>
  </c:if>
</m:set>

<m:eval>
  <FORM>
    <TABLE>
      <TR>
        <TD>single select</TD>
        <TD>
          <SELECT NAME="s_x">
            <OPTION VALUE="USA" @{in.s_x_SELECTED.USA}>United States</OPTION>
            <OPTION VALUE="EU" @{in.s_x_SELECTED.EU}>European Union</OPTION>
            <OPTION VALUE="JPN" @{in.s_x_SELECTED.JPN}>Japan</OPTION>
          </SELECT>
        </TD>
      </TR>

      <TR>
        <TD>multi select</TD>
        <TD>
          <SELECT NAME="m_s_x" MULTIPLE>
            <OPTION VALUE="USA" @{in.m_s_x_SELECTED.USA}>United States</OPTION>
            <OPTION VALUE="EU" @{in.m_s_x_SELECTED.EU}>European Union</OPTION>
            <OPTION VALUE="JPN" @{in.m_s_x_SELECTED.JPN}>Japan</OPTION>
          </SELECT>
        </TD>
      </TR>

      <TR>
        <TD>radio</TD>
        <TD>
          <INPUT TYPE="RADIO" NAME="r_x" VALUE="INCLUDE" @{in.r_x_CHECKED.INCLUDE}>Include</INPUT>
          <INPUT TYPE="RADIO" NAME="r_x" VALUE="EXCLUDE" @{in.r_x_CHECKED.EXCLUDE}>Exclude</INPUT>
        </TD>
      </TR>

      <TR>
        <TD>checkbox</TD>
        <TD>
          <INPUT TYPE="CHECKBOX" NAME="m_r_x" VALUE="INCLUDE" @{in.m_r_x_CHECKED.INCLUDE}>Include</INPUT>
          <INPUT TYPE="CHECKBOX" NAME="m_r_x" VALUE="EXCLUDE" @{in.m_r_x_CHECKED.EXCLUDE}>Exclude</INPUT>
        </TD>
      </TR>
      
      <TR>
        <TD>&nbsp;</TD>
        <TD>
          <INPUT TYPE="SUBMIT" NAME="submit" VALUE="submit">
        </TD>
      </TR>
    </TABLE>
  </FORM>
</m:eval>

If a regular parameter name matches multiPattern, then it is treated as if "._.*" were appended to it; e.g., if "multi_x=a&multi_x=b" is given, then it is treated as "multi_x._.*=a&multi_x._.*=b", and "multi_x._" becomes a list "[a,b]".

<m:param> also supports "multipart/form-data" requests (file upload). Each uploaded file parameter has file input stream (instance of java.io.InputStream) as its value instead of string, and you can save it using "File:write" codec, or convert it into binary string using "File:read" codec for further processing. A special property named multipart holds the details of the request (e.g., headers, filetype, size, etc.) as in <m:mailFolder> tag below. For example, you can get the size of an uploaded file named "xxx" as multipart.partName.xxx.fileSize. Note that regular (non-file) form parameters behave the same regardless of the ENCTYPE. For example,

<m:set var="MAXFILESIZE" value="1000000"/>

<m:param var="in"/>

<c:if test="${!empty in.submit}">

  <m:set var="fileDetail" value="${in.multipart.partName.file_upload}"/>

  <m:set var="result" value="file is larger than ${MAXFILESIZE} bytes"/>

  <c:if test="${fileDetail.size < MAXFILESIZE}">
    <m:set var="tempFile" codec="File:tempfile"/>

    <m:set var="result" value="${in.file_upload}" codec="File:write:@{tempFile}|Type:ifNull:Failed:Successfully written to @{tempFile}"/>
  </c:if>

</c:if>

<m:eval>
  <FORM METHOD="POST" ENCTYPE="multipart/form-data">
    <TABLE>
      <c:if test="${!empty result}">
        <TR><TD>result</TD><TD>@{result}</TD></TR>
      </c:if>
      <TR><TD>file (max @{MAXFILESIZE} bytes)</TD><TD><INPUT TYPE="FILE" NAME="file_upload"></TD></TR>
      <TR><TD>memo</TD><TD><INPUT TYPE="TEXT" NAME="memo" VALUE="@{in.memo}"></TD></TR>
      <TR><TD>&nbsp;</TD><TD><INPUT TYPE="SUBMIT" NAME="submit" VALUE="upload"></TD></TR>
    </TABLE>
  </FORM>
</m:eval>

valueCodec is applied to text parameter values only, but some browsers may upload text files as text instead of binary. You can use filePattern attribute to specify parameter name pattern to be considered as file parame