2008-12-28
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.
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.
Each YUZU tag has an object (called "tagValue" in this document) associated with it, and is always processed in 6 stages as follows:
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.
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>
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.
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.
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, 1) 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, 2) if the assign value is a map, then the map value for each property is assigned to each named variable or property, 3) 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>
or
<%-- set "name" and "home" page-scope variables to the values of system properties "user.name" and "user.home" --%> <m:map var="name,home" assign="@{_.user}"> <m:set property="__param" codec="System:getProperties_"/> </m:map>
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".
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". |
Format:paging | computes values for simple paging based on the following properties of the "operand" map: "numberOfItems" (total number of items to page through), "pageSize" (max number of items in each page), "itemIndex" (0-based index of an item to be included in the "current" page), "pageRadius" (number of pages before and after the "current" page to be shown if possible; 0 means the "current" page only, 1 means the "current" plus "previous" and "next", etc.). Returns a map with the following computed properties: "numberOfPages" (total number of pages), "pageIndex" (0-based index of the "current" page), "firstPageIndex" (0-based index of the first page; always 0), "lastPageIndex" (0-based index of the last page), "firstRadiusPageIndex" (index of the first radius page), "lastRadiusPageIndex" (index of the last radius page), "firstItemIndexOnPage" (item index of the first item on the current page), "lastItemIndexOnPage" (item index of the last item on the current page), "centerPageIndex" (index of the center of the radius) |
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:replace:SUBSTRING[:WITH] | replaces all SUBSTRING in "operand" string with WITH (default "") |
String:replaceAll:PATTERN[:WITH] | replaces all given regular expression PATTERN in "operand" string with WITH (default "") |
String:replaceCharacters:FROM:TO | replaces all characters in FROM with corresponding characters in TO |
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 "operand" string to list of Characters |
String:toCharacterArray | converts "operand" string to character array (char[]) |
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 (>, <;, &, ", ', { ({), and } (})) |
XML:encode[:PATTERN] | escapes special tag characters from "operand" as string (>,<,&,",',{ ({), and } (})). 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}".
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".
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) |
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.
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 |
sends email | |
mailFolder | retrieves email |
<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)
<m:out> is an alias for <m:set> without support for the following assignment-related attributes: var, scope, target, property, attribute, assign, assignCodec.
<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, "__css" for single-level CSS-style output ("key:value;key:value;..."), and "__attrList" for XML attribute list output (with submaps output using __css 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.__css}"/> <%-- this outputs: balance:100;customer:{firstName=John, lastName=Doe} --%> <m:out value="${account.__attrList}"/> <%-- this outputs (with a leading space): balance="100" customer="firstName:John;lastName:Doe;" --%>
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. When necessary, use __merge property instead to do nested 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 (shallow copy) | Map/List/String | set |
__merge | copies values from Map, List, or form-encoded string (nested copy) | Map/List/String | set |
__xml | XML output | String | get/set |
__dom | XML DOM output | Node | get/set |
__json | JSON output | String | get/set |
__css | CSS style output | String | get |
__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.
<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 <B>BOLDTEXT</B>.
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 |
<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> </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> </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 parameters to avoid application of valueCodec. The default value is ".*[Ff]ile.*" (i.e., names containing "file" or "File" as substring are considered as file parameters).
You can use control attribute to set these attributes and any other control properties accepted by <m:mailFolder> by using as its value a map or a form-encoded string for the attributes and their values to be set.
As an extension, <m:param> supports all attributes of <m:map>. Attributes specific to <m:param> are as follows:
name | type | description | default value |
---|---|---|---|
parameterMap | Object | map to be used instead of actual parameterMap of the request. This can be an instance of a map, or a form-encoded string. | null |
nameCodec | String | codec applied to each form parameter name | String:replaceAll:__:: |
valueCodec | String | codec applied to each form parameter value | XML:encode |
encoding | String | character encoding used for form parameters | null |
maxContentLength | String | maximal request content length accepted | 0 (unlimited) |
multiPattern | String | regular expression pattern for multi-valued forma parameter names | null |
selectPattern | String | regular expression pattern for "select" form parameters | null |
radioPattern | String | regular expression pattern for "radio" form parameters | null |
filePattern | String | regular expression pattern for form parameters to be treated as file names | .*[Ff]ile.* |
control | Object | map or form-encoded string that specifies the following atttibutes: "nameCodec", "valueCodec", "encoding", "maxContentLength", "filePattern", "multiPattern", "selectPattern", "radioPattern", plus any other controlproperties accepted by <m:mailFolder> | null |
<m:call> extends <m:map> and makes a "subroutine call" to another JSP in the same context at Process stage. Suppose we have the following JSP named "/Box.jsp" that puts the value of "parameter" inside a gray box:
<m:param var="in"/> <TABLE BGCOLOR="DDDDDD" CELLPADDING="6"> <TR><TD><PRE><m:out value="${in.parameter}"/></PRE></TD></TR> </TABLE>
Then the following behaves as if "/Box.jsp?parameter=This+is+a+test" were called:
<m:call path="/Box.jsp"> <m:set property="parameter" value="This is a test"/> </m:call>
and outputs the following:
<TABLE BGCOLOR="DDDDDD" CELLPADDING="6"> <TR><TD><PRE>This is a test</PRE></TD></TR> </TABLE>
The value of a property named "x" of <m:call> appears in the callee JSP as "${in.x}" if "in" is the structured parameter variable name set by <m:param> tag. Property values are passed to the callee JSP as-is without marshalling, so if a property value is a submap, then its content is shared by both the caller and the callee.
By default, the tagValue of a <m:call> is set to the output of the callee JSP, but the callee JSP can explicitly set the value to be returned to the caller JSP using <m:return> tag or by setting target attribute to "return". The following is equivalent to "/Box.jsp" above:
<m:param var="in"/> <m:return> <TABLE BGCOLOR="DDDDDD" CELLPADDING="6"> <TR><TD><PRE><m:out value="${in.parameter}"/></PRE></TD></TR> </TABLE> </m:return> OUTPUT HERE IS IGNORED
You can return arbitrary object back to the caller. For example, you can write a simple "MVC"-style controller code like this:
<m:param var="in"> <m:set property="action" value="login"/> </m:param> <m:call var="view" path="control/${in.action}.jsp" source="${in}"/> <m:call path="view/${view.path}" source="${view.param}" doesForward="true"/>
where controllers such as "control/login.jsp" return the path and parameters to be shown like this:
<%-- return path/param using map --%> <m:map target="return"> <m:set property="path" value="PATH-TO-VIEW"/> <m:map property="param"> <m:set property="VIEWPARAM-1" value="VALUE-OF-VIEWPARAM-1"/> <m:set property="VIEWPARAM-2" value="VALUE-OF-VIEWPARAM-2"/> ... </m:map> </m:map>
When necessary, you can make recursive calls. For example, the following displays a file directory given as "file=xxx" form parameter as a simple tree using HTML "UL" tag:
<m:param var="in"/> <m:set var="file" value="${in.file}" codec="Type:isFile"/> <LI><c:out value="${file.name}"/></LI> <c:if test="${file.directory == true}"> <m:set var="subfiles" value="${file}" codec="File:listFiles"/> <UL> <c:forEach var="subfile" items="${subfiles}"> <%-- call this JSP recursively --%> <m:call path="${in._request.servletPath}"> <m:set property="file" value="${subfile}"/> </m:call> </c:forEach> </UL> </c:if>
and the following computes the fibonacci number for given number "x" using a shared "cache" of previously computed numbers:
<m:param var="in"> <m:set property="x" value="1"/> </m:param> <c:if test="${empty in.cache}"> <m:map target="${in}" property="cache" source="1=1&2=1"/> </c:if> <m:set var="cached" value="${in.cache[in.x]}"/> <c:if test="${empty cached}"> <m:call var="a" path="${in._request.servletPath}"> <m:set property="x" value="${in.x - 2}"/> <m:set property="cache" value="${in.cache}"/> </m:call> <m:call var="b" path="${in._request.servletPath}"> <m:set property="x" value="${in.x - 1}"/> <m:set property="cache" value="${in.cache}"/> </m:call> <m:set var="cached" target="${in.cache}" property="${in.x}" value="${a + b}"/> </c:if> <m:return value="${cached}"/>
If necessary, you can set doesForward to "true" to pass control over to the callee JSP.
The tag body string of <m:call> is assigned to the property named "parameter" by default (you can use bodyParameter attribute to specify a non-default property name). So the following is equivalent to the caller example above:
<m:call path="/Box.jsp">This is a test</m:call>
When a JSP page is "called" by another one, <m:param> tag adds a special property named "_caller" which holds the http request object (an instance of "javax.servlet.http.HttpServletRequest") of the calling JSP/servlet, and you can find the caller's path by using "_caller.servletPath", for example. The "_caller" property is set only when the JSP is "called".
When necessary, you can call a JSP in other servlet context by specifying contextPath. In order to cross context boundary, objects being passed need to be loaded by the same class loader (e.g., by placing JSTL and YUZU jar files in "common/lib" instead of individual webapp's "WEB-INF/lib" directory).
<m:call> supports all attributes of <m:map>. Attributes specific to <m:call> are as follows:
name | type | description | default value |
---|---|---|---|
contextPath | String | name of the servlet context for cross-context call | null |
bodyProperty | String | name of the property for the tag body | parameter |
body | Object | the value of the property named bodyProperty | null |
doesForward | boolean | if set to true, control is passed to the callee JSP. | false |
Alternatively you can use "_JSP:call" codec.
<m:return> returns a value to the caller JSP when called. See <m:call> above for more information about JSP calling. When used in a JSP that is not called by another JSP, this always exports the tagValue. This makes it easier to debug the callee JSP because you can directly call the callee JSP to view the returned value. If the tagValue is null, then "" (empty string) is returned to the caller.
You can alternatively set the value of target attribute of a YUZU tag to string "return" to return its tagValue. For example, the following:
<m:return> <m:map attribute="value"> <m:set property="name" value="test"/> </m:map> </m:return>
is equivalent to:
<m:map target="return"> <m:set property="name" value="test"/> </m:map>
Due to the nature of the tag, <m:return> does not support the following attributes: var, target, property, attribute, scope, assignCodec, assign.
<m:value> sets the tagValue of the parent YUZU tag as if attribute attribute were set to "value". The following two are equivalent:
<m:out> <m:set attribute="value" codec="String:toUpperCase">this is a test</m:value> </m:out> <m:out> <m:value codec="String:toUpperCase">this is a test</m:value> </m:out>
The default attribute value of a <m:value> is set to the tagValue of the closest ancestor YUZU tag (as if it were set to "${_}", but across tagfile boundaries) unless explicitly set to a non-null value. For example:
<%-- map is initialized to "a=alpha&b=beta" --%> <m:map> <m:set attribute="value" default="${_}" codec="Bean:set:a:alpha"/> <m:set attribute="value" default="${_}" codec="Bean:set:b:beta"/> </m:map> <%-- this is equivalent to the above --%> <m:map> <m:value codec="Bean:set:a:alpha"/> <m:value codec="Bean:set:b:beta"/> </m:map>
If value attribute is set to "*" (asterisk), then <m:value>'s tagValue is replaced with the tagValue of the closest ancestor YUZU tag before the tag body is evaluated.
Due to the nature of the tag, <m:value> does not support attribute attribute.
<m:include> extends <m:map> and makes HTTP/HTTPS request at Process stage. The following properties are supported:
name | summary |
---|---|
url | target URL to call |
method | HTTP method; either "get" or "post" is supported. Default is "post". |
throwsException | if "true", then HTTP errors (status other than 200) causes Exception. Default value is "true". If false, then response.status and response.message are set. See below. |
followsRedirects | if "true", then HTTP redirection is automatically followed. Default value is "true" |
usesTrustManager | if "true", then HTTPS connection uses trust manager. Default is "true" |
allowsFile | if "true", then "file://*" URLs are allowed. Default is "false" |
usesHostnameVerifier | if "true", then HTTPS connection uses hostname verifier. Default value is "true" |
connectTimeout | connection timeout in milliseconds (JDK 1.5 and above only). |
readTimeout | read timeout in milliseconds (JDK 1.5 and above only). |
request | request data structure (a nested map). |
request.content | request content string |
request.parameter | request parameter map. If request.content is not given, then this map is encoded as form-data ("a=b&c=d&...") and used as request.content |
request.encoding | character encoding used to encode the request.parameter map |
request.header | request header name/value map. Either a string or an array/list of strings or a NestedMap with "_" list of strings can be used as "value" |
request.authorization | if set to "basic", then request.user and request.password are used to generate HTTP basic "Authorization" header |
request.user | user for HTTP authentication. Used if request.authorization is set to "basic". |
request.password | password for HTTP authentication. Used if request.authorization is set to "basic". |
response | response data structure (nested map) |
response.status | response status. Set if request.throwsException is false. |
response.message | response status message. Set if request.throwsException is false. |
response.header | response header name/value map; each value is a NestedMap with "_" list containing header values |
response.type | parsed response content mime type map |
response.type.type | mime type; e.g., "text" if content-type is "text/html; charset=utf-8" |
response.type.subtype | mime subtype; e.g., "html" if content-type is "text/html; charset=utf-8" |
response.type.parameter | mime type parameter map; e.g., {charset=utf-8} if content-type is "text/html; charset=utf-8" |
response.content | response content string which is exported by default. |
The default export attribute of <m:include> is set to "${_.response.content}" to make it simpler to include a URL. The default assign attribute is "${_}" so that the response values can be examined by assigning to a variable.
Here is a simple "get" example:
<m:include> <m:set property="url" value="http://www.micronova.com/"/> </m:include>
This sends a request parameter using "get" method:
<m:include> <m:set property="url" value="http://www.micronova.com/"/> <m:set property="method" value="get"/> <m:map property="request"> <m:map property="parameter"> <m:set property="page" value="yuzu"/> </m:map> </m:map> </m:include>
If asynchronous attribute is set to "true", then asynchronous request is made. In this case, the "tagValue" is set to the thread making the request.
As an extension, <m:include> supports all attributes of <m:map>. Attributes specific to <m:include> are as follows:
name | type | description | default value |
---|---|---|---|
url | String | sets the url property | null |
allowsFile | boolean | allows "file://*" URL | false |
asynchronous | boolean | if set, makes asynchronous request | false |
<m:log> writes the tagValue to the server log at Process stage:
<m:param var="in"/> <m:log value="servlet request is : ${in._request}"/>
By default the output goes to the servlet log. You can change where the log output goes by using destination attribute. If destination is set to "out" (or "err"), then the output goes to stdout (or stderr).
For apache logging, you can also specify the following logging levels as destination: "trace", "debug", "info", "warn", "error" or "fatal", and optional category using category attribute. You can also specify an instance of org.apache.commons.logging.Log to be used using log if necessary.
Alternatively you can use JSP:log codec instead of <m:log> tag. Internally <m:log> uses an instance of LogWriter (which can be obtained by JSP:getLogWriter codec).
Due to the nature of the tag, <m:log> does not support the following attributes: var, target, property, attribute, scope, exportCodec, assignCodec, assign, export, doesExport. Attributes specific to <m:log> are as follows:
name | type | description | default value |
---|---|---|---|
destination | String | log output destination, either "log", "out", or "err"; or for apache logging, "trace", "debug", "info", "warn", "error" or "fatal". | value of configuration variable "com.micronova.jsp.tag.LogTag.destination" evaluated as EL (default "log") |
category | String | category for apache logging | value of configuration variable "com.micronova.jsp.tag.LogTag.category" evaluated as EL (default "") |
log | org.apache.commons.logging.Log | specific instance of org.apache.commons.logging.Log to be used | value of configuration variable "com.micronova.jsp.tag.LogTag.log" evaluated as EL (default null) |
<m:postData> gets the HTTP post data. For example, you can parse the POST data as XML as follows:
<x:parse var="x"><m:postData/></x:parse>
If you specify contentTypePrefix, then <m:postData> returns POST data only if the request content type starts with given contentTypePrefix. For example, the following outputs POST data only if the request content type is "text/xml*":
<m:postData contentTypePrefix="text/xml"/>
By default the POST data is returned as string, but actually <m:postData> first sets the tagValue to the current ServletRequest object at Prepare stage if the request content type matches contentTypePrefix, and then sets tagValue to the POST data as string right before Default stage (after processing the tag body) if tagValue is still equal to the current ServletRequest. So when necessary you can directly process the POST data within the tag body as follows:
<m:postData var="parsed" contentTypePrefix="text/xml"> <m:set attribute="value" value="${_.reader}" codec="XML:parse"/> </m:postData>
<m:postData> does not do anything if used in a JSP called by using <m:call>.
You can use encoding attribute to set the character set to be used to convert the POST data to string. The value of encoding takes precedence over the request encoding unless it is prefixed by "*" (asterisk) - in this case, the request encoding takes precedence (if given). The default value of encoding is "*utf-8" or the value of the configuration variable "com.micronova.jsp.tag.PostDataTag.defaultEncoding" evaluated as EL.
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.PostDataTag.maxContentLength" to set the default value for maxContentLength attribute.
Attributes specific to <m:postData> are as follows:
name | type | description | default value |
---|---|---|---|
contentTypePrefix | String | if given, returns POST data only if the request content type starts with this | null (accepts any content type) |
encoding | String | character encoding used to obtain postData as String | null |
maxContentLength | Number | maximal request content length accepted | value of configuration variable "com.micronova.jsp.tag.PostDataTag.maxContentLength" evaluated as EL or 0 (unlimited) |
<m:throw> throws an Exception having the tagValue as its message when tagValue is not null at Process stage. You can catch the thrown exception using JSTL's <c:catch>. The following outputs "Exception: bad input given" if input parameter "x" equals "bad":
<m:param var="in"/> <c:catch var="exception"> <m:throw test="${in.x == 'bad'}" value="bad input given"/> </c:catch> <m:out value="Exception:${exception.message}" test="${!empty exception}"/>
If necessary, you can use <m:throw> to break out of JSTL loop tags such as <c:forEach>:
<m:param var="in"/> <c:catch var="exception"> <c:forEach var="p" items="${in}"> <m:throw test="${p.key == 'needle'}" value="needle found"/> </c:forEach> </c:catch> <c:if test="${exception.message == 'needle found'}"> Form Parameter named 'needle' found </c:if>
Or you can define tag files such as 't:block' and 't:break' as follows to break out of a specified block:
<%-- 't:block' tag catches special 'break' exception with message 'YUZUBREAK-XXX'; if 'XXX' part matches its 'label' or '*', then consumes the exception; otherwise rethrows. --%> <%@ tag %> <%@ attribute name="label" %> <m:set var="label" value="${label}" default="*"/> <c:catch var="exception"> <jsp:doBody/> </c:catch> <c:if test="${!empty exception}"> <m:set var="breakLabel" value="${exception.message}" codec="String:match:^YUZUBREAK-(.*)$:1"/> <c:if test="${breakLabel == label || breakLabel == '*'}"> <m:set var="exception"/> </c:if> </c:if> <m:throw value="${exception}"/> <%-- 't:break' tag throws a special 'break' exception with message 'YUZUBREAK-${label}' when the value of optional 'test' is true (default). --%> <%@ tag %> <%@ attribute name="label" %> <%@ attribute name="test" %> <m:set var="label" value="${label}" default="*"/> <m:set var="test" value="${test}" default="true"/> <c:if test="${test}"> <m:throw>YUZUBREAK-${label}</m:throw> </c:if> <%-- using 't:block' and 't:break', the following outputs 'A1 B1 C1 A2' --%> <t:block label="A"> A1 <t:block label="B"> B1 <t:block label="C"> C1 <t:break label="B"/> C2 </t:block> B2 </t:block> A2 </t:block>
Due to the nature of the tag, <m:throw> does not support the following attributes: var, target, property, attribute, scope, exportCodec, assignCodec, assign, export, doesExport, processCodec, codec.
<m:synchronized> synchronizes tag body processing so that only one thread can execute it. For example:
<m:synchronized> <m:set target="${applicationScope.data}" property="${name}" value="${value}"/> </m:synchronized>
modifies an application-scope object "applicationScope.data" synchronously.
If necessary, you can set thread lock timeout in milliseconds using waitTime attribute (default is 0 meaning "no timeout"). If thread lock can not be obtained within given waitTime, then an exception with "thread lock timeout" message is thrown.
You can also specify the name of the lock to be used for synchronization by using lockId attribute (default is "" (empty string)). The current thread executes the body of a <m:synchronized> with lockId "X" only when no other thread is executing the body of any <m:synchronized> tag with the same lockId. For example:
<%-- only one thread writes ${content} to ${fileName} --%> <m:synchronized lockId="${fileName}"> <m:set var="result" value="${content}" codec="File:write:@{fileName}"/> </m:synchronized>
If the value of lockId is not a String, then the value object itself is used as a lock.
Attribute specific to <m:synchronized> is as follows:
name | type | description | default value |
---|---|---|---|
waitTime | Long | thread lock timeout in milliseconds | 0 (no timeout) |
lockId | Object | lock identifier | "" (empty string) |
<m:query> is a simpler version of JSTL <sql:query> that takes embedded patterns ("%{x}" by default) inside queries to be translated as SQL parameters. For example, the following JSTL code:
<sql:query> select * from Test where Age = ? and Name = ? <sql:param value="${age}"/> <sql:param value="${name}"/> </sql:query>
can be written using <m:query> as follows:
<m:query> select * from Test where Age = %{age} and Name = %{name} </m:query>
The tagValue of <m:query> is an instance of javax.servlet.jsp.jstl.sql.Result as in JSTL. You can use assign or export to obtain particular row or field as follows:
<%-- Assuming that "Test" has a primary key "id" and a field "name", this assigns the name for the given id, if exists --%> <m:query var="name" assign="@{_.rows[0].name}"> select name from Test where id = %{id} </m:query>
You can embed a List value in the query as follows:
<%-- set "names" to a list ["a","b","c","d","e"] --%> <m:set var="names" value="a,b,c,d,e" codec="String:split"/> <%-- this query is equivalent to "select id from Test where name in ('a','b','c','d','e')" --%> <m:query> select id from Test where name in (%{names}) </m:query>
Note that if the value of an embedded EL expression is a byte (or char) array, then it is treated as a binary (or character) stream.
<m:query> extends <m:eval> and supports all its attributes. Attributes specific to <m:query> are as follows:
name | type | description | default value |
---|---|---|---|
dataSource | String or javax.sql.DataSource | jdbc URL, resource name, or an instance of javax.sql.DataSource | value of configuration variable "javax.servlet.jsp.jstl.sql.dataSource" evaluated as EL |
startRow | Integer | first query row to be returned | 0 |
maxRows | Integer | max number of rows to be returned | -1 (unlimited) |
When non-empty dataSource is given, then a new database connection for the given dataSource is always opened and used. When dataSource is not given and there is no ancestor <sql:transaction> or <m:transaction> tag, then a new database connection for the dataSource specified by the default configuration variable is used. Otherwise the connection that belongs to the outermost <sql:transaction> or <m:transaction> is used.
<m:update> is a simpler version of JSTL <sql:update> that takes embedded patterns ("%{x}" by default) within the query to be translated as SQL parameters. For example, the following JSTL code:
<sql:update> update table Test set age = ? where name = ? <sql:param value="${age}"/> <sql:param value="${name}"/> </sql:update>
can be written using <m:update> as follows:
<m:update> update table Test set age = %{age} where name = %{name} </m:update>
In this case the tagValue of <m:update> is the number of rows affected as in JSTL.
Note that if the value of an embedded EL expression is a byte (or char) array, then it is treated as a binary (or character) stream.
<m:update> can also execute SQL stored procedures and return output values. In stored procedure syntax ("{...}"), you can use embedded patterns starting with '#' (e.g., "%{#output}") to indicate output variables using the following syntax ("[...]" indicates optional parts):
#[NAME][#TYPE][#TYPENAME]
where "NAME" is the name of the output value (default "OUTPUT"), "TYPE" is the SQL type of the output value (e.g., "BIGINT", "VARCHAR", etc. as defined in java.sql.Types; default "BIGINT"), and TYPANAME is the type name required for types such as "JAVA_OBJECT" (please see "java.sql.CallableStatemet" class for more details). The tagValue of <m:update> in this case is a map of output name/value pairs. For example:
<m:update>{%{#result#BIGINT} = myfunction(%{a}, %{b})}</m:update>
returns a map like {result=32}. When the called stored procedure returns a ResultSet, then the tagValue is an instance of javax.servlet.jsp.jstl.sql.Result. For an "IN OUT" argument, you can append the output specification as above to the "IN" expression (e.g., "%{12#outputValue}" to send "12" as "IN" value, and receive the "OUT" value as "outputValue").
<m:update> extends <m:eval> and supports all its attributes. Attributes specific to <m:update> are as follows:
name | type | description | default value |
---|---|---|---|
dataSource | String or javax.sql.DataSource | jdbc URL, resource name, or an instance of javax.sql.DataSource | value of configuration variable "javax.servlet.jsp.jstl.sql.dataSource" evaluated as EL |
startRow | Integer | first query row to be returned (used only when stored procedure returns a ResultSet) | 0 |
maxRows | Integer | max number of rows to be returned (userd only when stored procedure returns a ResultSet) | -1 (unlimited) |
When non-empty dataSource is given, then a new database connection for the given dataSource is always opened and used. When dataSource is not given and there is no ancestor <sql:transaction> or <m:transaction> tag, then a new database connection for the dataSource specified by the default configuration variable is used. Otherwise the connection that belongs to the outermost <sql:transaction> or <m:transaction> is used.
<m:transaction> is a nestable (stackable) version of JSTL <sql:transaction>. The body of a <m:transaction> forms a database transaction boundary for <m:update> or <m:query> tags inside. A successful closing of <m:transaction> tag commits its transaction, and any uncaught exception inside its body rolls back the transaction and throws an exception to the outside of the <m:transaction> tag. For example,
<%-- typical MySQL row insertion, assuming a table named "Test" with auto-increment primary key "id", "firstName", and "lastName" fields --%> <m:map var="fields"> <m:set property="firstName" value="john"/> <m:set property="lastName" value="doe"/> </m:map> <m:transaction> <m:update environment="${fields}"> insert into Test (<m:out value="${_.__keyList}" codec="String:join"/>) values (<m:filter value="${_.__keyList}" apply="%{_.${_element}}" codec="String:join"/>) </m:update> <m:query var="id" assign="@{_.rows[0].id}"> select last_insert_id() as id </m:query> </m:transaction> inserted id is ${id}
When <m:transaction> tags are nested, then the outermost <m:transaction> defines the the transaction boundary; i.e., the following code either inserts two rows or no rows at all:
<m:map var="ENV"/> <m:transaction> <m:map var="fields"> <m:set property="firstName" value="john1"/> <m:set property="lastName" value="doe1"/> </m:map> <m:transaction> <m:update> insert into Test (<m:out value="${fields.__keyList}" codec="String:join"/>) values (<m:filter apply="%{fields.@{_element}}" value="${fields.__keyList}" codec="String:join"/>) </m:update> <m:query var="id" assign="@{_.rows[0].id}"> select last_insert_id() as id </m:query> </m:transaction> <m:set target="${ENV}" property="id1" value="${id}"/> <m:map var="fields"> <m:set property="firstName" value="john2"/> <m:set property="lastName" value="doe2"/> </m:map> <m:transaction> <m:update> insert into Test (<m:out value="${fields.__keyList}" codec="String:join"/>) values (<m:filter apply="%{fields.@{_element}}" value="${fields.__keyList}" codec="String:join"/>) </m:update> <m:query var="id" assign="@{_.rows[0].id}"> select last_insert_id() as id </m:query> </m:transaction> <m:throw>Error</m:throw> <m:set target="${ENV}" property="id2" value="${id}"/> </m:transaction> ${ENV}
Since <m:transaction> is stackable, if you have a tag <d:create> defined by a tag file like this (tag definitions are omitted):
<%@ tag %> <%@ attribute name="target" type="java.lang.Object" %> <%@ attribute name="property" %> <%@ attribute name="table" %> <m:map var="fields"> <jsp:doBody/> </m:map> <m:transaction> <m:update> insert into ${table} (<m:out value="${fields.__keyList}" codec="String:join"/>) values (<m:filter apply="%{fields.@{_element}}" value="${fields.__keyList}" codec="String:join"/>) </m:update> <m:query var="id" assign="@{_.rows[0].id}"> select last_insert_id() as id </m:query> </m:transaction> <m:set target="${target}" property="${property}" value="${id}"/>
then the code above can be rewritten as follows:
<m:map var="ENV"/> <m:transaction> <d:create target="${ENV}" property="id1" table="Test"> <m:set property="firstName" value="john1"/> <m:set property="lastName" value="doe1"/> </d:create> <d:create target="${ENV}" property="id2" table="Test"> <m:set property="firstName" value="john2"/> <m:set property="lastName" value="doe2"/> </m:map> </m:transaction> ${ENV}
When isolation is given, then it always affects the transaction defined by the tag (even when nested). Also, if non-empty dataSource is given, then a new transaction (connection) is made always, regardless of nesting.
The tagValue of <m:transaction> is undefined (null).
Attributes specific to <m:transaction> are as follows:
name | type | description | default value |
---|---|---|---|
dataSource | String or javax.sql.DataSource | jdbc URL, resource name, or an instance of javax.sql.DataSource | value of configuration variable "javax.servlet.jsp.jstl.sql.dataSource" evaluated as EL |
isolation | String | transaction isolation level; either "read_committed", "read_uncommitted", "repeatable_read", "serializable" or null (no change) | null |
<m:response> extends <m:map> and modifies the response for the HTTP request currently being processed. The following properties are supported:
name | summary |
---|---|
header | response header name/value map. The value can be either string or a list of strings. |
error | error code |
errorMessage | error message |
redirect | redirect URL |
cookie | cookie name/value map. The value can be either an instance of javax.servlet.http.Cookie or a map of Cookie bean property/value pairs (comment, domain, maxAge, path, secure, value, version). |
The following redirects the browser:
<m:response> <m:set property="redirect" value="http://www.micronova.com/"/> </m:response>
The following sets the content type:
<m:response> <m:set property="@header.content-type" value="text/xml; charset=utf-8"/> </m:response>
The following sets the response code to "500":
<m:response> <m:set property="error" value="500"/> <m:set property="errorMessage" value="Something happened"/> </m:response>
The following sets a secure cookie:
<m:response> <m:map property="@cookie.test"> <m:set property="value" value="test cookie"/> <m:set property="secure" value="true"/> </m:map> </m:response>
<m:system> extends <m:map> and makes a system call. The following properties/attributes are supported:
name | summary |
---|---|
command | system command to execute |
stdin | standard input for the executed command |
stdout | standard output of the executed command |
stderr | standard error of the executed command |
encoding | encoding for stdin/stdout/stderr (default: iso-8859-1) |
rc | status code of the executed command (property only) |
The default export is set to "${_.stdout}" to make it easier to import the standard output. The following creates a tar file for download:
<m:system command="sh"> <m:set property="stdin"> cd mydirectory tar cz * </m:set> <m:response> <m:map property="header"> <m:set property="content-type" value="application/binary"/> <m:set property="content-disposition" value="filename=myfile.tar.gz"/> </m:map> </m:response> <%-- make sure no character follows "</m:system>" --%> </m:system>
You can specify a Writer as stdout or stderr to pipe the output; for example, the following outputs the shell's output unbuffered:
<%@ page contentType="text/plain; charset=utf-8" buffer="none" %> <m:system command="sh" stdout="${pageContext.out}" stderr="${pageContext.out}"> <m:set property="stdin"> curl -o "/tmp/file" "http://www.micronova.com/YUZU/yuzu-20070909.zip" </m:set> </m:system> DONE
Attributes specific to <m:system> are as follows:
name | type | description | default value |
---|---|---|---|
command | String | system command to execute | null |
stdin | Object | standard input for the command to be executed, either a reader (instance of java.io.Reader) or a string | null |
stdout | Object | standard output for the command to be execute; if this is a Writer (istance of java.io.Writer) then the command's standard output is piped to it (unbuffered) | null |
stderr | Object | standard error for the command to be executed; if this is set to a Writer (instance of java.io.Writer), then the commands' standard error is piped to it (unbuffered) | null |
encoding | String | character encoding for stdin/stdout/stderr | iso-8859-1 |
export | String | object to be exported | ${_.stdout} |
<m:filter> "filters" elements of "tagValue" list (i.e., creates a new list of "filtered" elements). It iterates over elements of "tagValue" setting the following page-scoped local variables for each element:
and each element is processed according to given EL attributes include, apply, applyCodec, and break as follows:
By default, all elements are included (include is "true" and break is null) and copied as-is to the new list (apply is "${_element}", and applyCodec is null).
The following "squares" each odd number in the list up to (and not including) the first negative number:
<%-- outputs [1, 9, 25] --%> <m:set var="list" value="1,2,3,4,5,-1,6,7,8,9" codec="String:split"/> <m:filter value="${list}" include="@{(_element % 2 > 0) && (_element > 0)}" apply="@{_element * _element}" break="@{_element < 0}"/>
The "tagValue" can also be a string or map. When "tagValue" is a string, then each character of the "tagValue" is used as _element , and the filtered values are appended together as a string:
<%-- converts each character into 4-digit hex value --%> <m:filter value="Hello World" applyCodec="Type:charAsNumber|Number:toHexString:0000"/>
When "tagValue" is a map, then each key/value pair is used as _element , and the filtered value is used as the value for the given key in the resulting map:
<m:map var="map"> <m:set property="a" value="alpha"/> <m:set property="b" value="beta"/> <m:set property="c" value="gamma"/> </m:map> <%-- converts value to "key:value" --%> <m:filter value="${map}" apply="@{_element.key}:@{_element.value}"/>
If necessary, you can use "_JSP:applyFilter" codec instead. For example:
<%-- the following two are equivalent --%> <m:filter value="Hello World" applyCodec="Type:charAsNumber|Number:toHexString:0000"/> <m:out value="Hello World" codec="_JSP:applyFilter:applyCodec=Type\:charAsNumber\|Number\:toHexString\:0000"/>
<m:parseHtml> parses the tagValue as HTML document into a DOM structure (so that JSTL XML tags can be applied). For example, the following prints out all the links in MicroNova's home page:
<m:parseHtml var="html"><m:include url="http://www.micronova.com/"/></m:parseHtml> <x:forEach var="link" select="$html//a/@href"> link: <x:out select="$link"/> </x:forEach>
<m:parseHtml> supports the following attributes:
name | description | default value |
---|---|---|
include | comma-separated list of HTML tag names to be included while parsing, null by default (meaning "include all"). The following special element names can also be used: "text", "comment", "script" (<script> tag), "style" (<style> tag), "sgml" (<!...> other than comments), and "pi" (<?...>). | null (include all) |
exclude | comma-separated list of HTML tag names to be excluded while parsing, null by default (meaning "exclude none"). The special element names as above can be used. | null (exclude none) |
strategy | parsing strategy for handling missing closing tags; either "single", "data", or "none". See below for more information. | single |
rootName | root XML document name to be used. | root |
strategy sets the behavior of the parser when closing tags are missing. The "single" strategy assumes the opening tag is a single tag ("<x/>"). The "data" strategy assumes the opening tag encloses the following text. The "none" strategy assumes the opening tag encloses all following texts and tags. For example, the following:
<a> <b> text1 <c> text1 <d> text2 </a>
is parsed into the following XML if strategy is "single":
<a> <b/> text1 <c/> text1 <d/> text2 </a>
and if strategy is "data":
<a> <b>text1</b> <c>text1</c> <d>text2</d> </a>
and finally if strategy is "none":
<a> <b> text1 <c> text1 <d> text2 </d> </c> </b> </a>
<m:mail> extends <m:map> and sends multi-part emails in Process stage. In its simplest form, the following sends a text email:
<m:mail url="smtp://your-smtp-server"> <m:set property="to">somebody@someaddress</m:set> <m:set property="from">somebody@someaddress</m:set> <m:set property="subject">Test email</m:set> <m:set property="type">text/plain; charset=ISO-8859-1</m:set> <m:set property="content">Hello, this is a test</m:set> </m:mail>
When the "_" (underscore) list property is not empty, then a multi-part email is composed of the list elements ("_.0", "_.1", ..., each having its own "content", "header", etc.) recursively using "type" as the multi-part subtype. The following sends a multi-part email consisting of alternative text/html parts with images:
<m:mail url="smtp://your-smtp-server"> <m:set property="to">[email protected]</m:set> <m:set property="from">[email protected]</m:set> <m:set property="subject">Test</m:set> <m:set property="type" value="alternative"/> <%-- alternative text part --%> <m:map property="@_.*"> <m:set property="type" value="text/plain; charset=iso-8859-1"/> <m:set property="content">This is Text</m:set> </m:map> <%-- alternative HTML part with images --%> <m:map property="@_.*"> <m:set property="type" value="related"/> <%-- related HTML part --%> <m:map property="@_.*"> <m:set property="type" value="text/html; charset=iso-8859-1"/> <m:set property="content"> <HTML> <BODY>Here is an image:<IMG SRC="cid:image1"></BODY> </HTML> </m:set> </m:map> <%-- HTML image, CID: image1 --%> <m:map property="@_.*"> <m:set property="dataSource" value="file:///somedirectory/image.png"/> <m:set property="@header.Content-ID" value="<image1>"/> <m:set property="@header.Content-Transfer-Encoding" value="base64"/> </m:map> </m:map> </m:mail>
The following properties are supported:
name | description |
---|---|
to | "to" addresses. Either a comma-separated list of email addresses, or an instance of java.util.List of email addresses or maps of type {address=xxx, personal=yyy, charset=zzz} (for "yyy <xxx>" email address encoded using the charset "zzz"; "personal" and "charset" are optional) |
cc | "cc" addresses. Same type of value as "to" |
bcc | "bcc" addresses. Same type of value as "to" |
from | "from" addresses. Same typeof value as "to" |
replyTo | "replyTo" addresses. Same type of value as "to" |
subject | email subject |
type | content type. Default is "text/plain; charset=ISO-8859-1". For multi-part email, this specifies subtype ("related", "alternative", "mixed") |
content | message content |
header | header map. Can be name/value pairs, or with "_" list consisting of {name=xxx, value=yyy} type maps or header line strings such as "Content-type: text/plain" when ordering is significant. |
fileName | content fileName |
dataSource | content dataSource URL |
By default the connection to the mail server is closed each time <m:mail> tag is closed, but if the "url" attribute is not given, then <m:mail> shares the mail server connection of the the closest surrounding <m:mail> tag with non-null "url". For example:
<m:set var="addresses" importCodec="String:split">a1,a2,a3</m:set> <m:mail url="smtp://your-smtp-server"> <c:forEach var="address" items="${addresses}"> <m:mail> <m:set property="to" value="${address}"/> <m:set property="from">somebody@someaddress</m:set> <m:set property="subject">Test email</m:set> <m:set property="type">text/plain; charset=ISO-8859-1</m:set> <m:set property="content">Hello, this is a test</m:set> </m:mail> </c:forEach> </m:mail>
sends out emails to "a1", "a2", "a3" using the mail server connection of the outer <m:mail>. The mail server connection is closed when the outer <m:mail> is closed.
You can specify username/password for the mail server either in the url attribute (e.g., "smtp://USERNAME:PASSWORD@smtpserver") or using mail properties (e.g., "mail.smtp.user" and "mail.smtp.password"), along with other properties. The following sends an email using Google's smtp server with debug output:
<m:map var="mailProperties"> <m:set property="mail.smtp.user">${USERNAME}</m:set> <m:set property="mail.smtp.password">${PASSWORD}</m:set> <m:set property="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</m:set> <m:set property="mail.debug">true</m:set> </m:map> <m:mail url="smtp://smtp.gmail.com:465" properties="${mailProperties}"> <m:set property="to">[email protected]</m:set> <m:set property="subject">Test</m:set> <m:set property="type">text/plain; charset="utf-8"</m:set> <m:set property="content">This is a test</m:set> </m:mail>
As an extension, <m:mail> supports all attributes of <m:map>. Attributes specific to <m:mail> are as follows:
name | type | description | default value |
---|---|---|---|
url | String | mail server url | null |
properties | Object | map (or form-encoded string) of javax.mail.Session properties | null |
<m:mailFolder> retrieves/deletes emails from a mailbox (folder) in Process stage. For Example:
<%-- read all messages --%> <m:mailFolder url="pop3://your-username:your-password@your-popserver/INBOX" operation="read" messages="*"/> <%-- reads messages 123 and 126 --%> <m:mailFolder url="pop3://your-username:your-password@your-popserver/INBOX" operation="read" messagesNumbers="123,126"/> <%-- deletes messages 123,124,125,126 --%> <m:mailFolder url="pop3://your-username:your-password@your-popserver/INBOX" operation="delete" messages="123-126"/>
messages specifies the messages to read or delete. It can be either a comma-separated string of message numbers or range of message numbers ("m-n" indicating "m,m+1,...,n"; "m-*" meaning "equal or larger than m", "*-n" meaning "equal or smaller than n", or "*" meaning all), or a list of message numbers or "javax.mail.Message" instances.
The tagValue of <m:mailFolder> is set to a nested map with the following properties:
name | dscription |
---|---|
name | name of the folder |
fullName | full name of the folder |
urlName | URL name of the folder |
messageCount | number of messages in the folder |
_folder | instance of javax.mail.Folder |
_ | list of messages for "read" operation |
Each message/part is retrieved as nested maps with the following properties:
name | description |
---|---|
to._ | "to" addresses. List of maps of type {address=xxx, personal=yyy} |
cc._ | "cc" addresses. List of maps of type {address=xxx, personal=yyy} |
bcc._ | "bcc" addresses. List of maps of type {address=xxx, personal=yyy} |
from._ | "from" addresses. List of maps of type {address=xxx, personal=yyy} |
replyTo._ | "replyTo" addresses. List of maps of type type {address=xxx, personal=yyy} |
subject | message subject |
sentDate | sent date |
receivedDate | received date |
type | parsed content mime type; e.g., a map {type=text, subtype=html, parameter={charset=utf-8}} for content type "text/html; charset=utf-8". If "type" is "multipart", then the "_" (underscore) list contains message parts as in <m:mail>. |
content | message/part content |
header | header map. The "_" (underscore) sublist contains the headers in the given order as {name=xxx, value=yyy} maps. |
description | description, if given |
lineCount | line count, if given |
fileName | file name, if given |
size | size, if given |
disposition | parsed disposition map like type, if given |
partName | subpart map by disposition name; e.g., if a subpart's disposition has "name=xxx", then it is accessible as "partName.xxx") |
_ | list of subparts |
_part | instance of javax.mail.Part |
For example:
<%-- shows subject/date/from of all messages --%> <m:mailFolder var="folder" url="pop3://your-username:your-password@your-popserver/INBOX" operation="read" messages="*" control="content=false&header=false"/> <TABLE> <TR> <TH>subject</TH> <TH>sent date</TH> <TH>from</TH> </TR> <c:forEach var="message" items="${folder._}"> <m:set target="${message}" property="fromList" value="${message.from._}" codec="String:join"/> <m:eval evalCodec="XML:encode"> <TR> <TD>@{message.subject}</TD> <TD>@{message.sentDate}</TD> <TD>@{message.fromList}</TD> </TR> </m:eval> </c:forEach> </TABLE>
You can specify a map of various control properties using control attribute. The value for control can be either a form-encoded string or a map. The following control properties are supported:
name | description | default value |
---|---|---|
content | if set to "false", then message content is not read | true |
header | if set to "false", then message header is not read | true |
headerMap | if set to "true", then the "header" maps each header name to its value | false |
maxContentSize | specifies max part content size. Part contents larger than this are ignored. | 0 (unlimited) |
maxPartSize | specifies max part size (including multiparts). Parts larger than this are ignored. | 0 (unlimited) |
By default the connection to the mailbox server is closed each time <m:mailFolder> tag is closed, but if the "url" attribute is not given, then <m:mailFolder> shares the mailbox server connection of the the closest surrounding <m:mailFolder> tag with non-null "url". For example:
<m:mailFolder url="pop3://your-username:your-password@your-popserver/INBOX"> <%-- reads messages 123-130 --%> <m:mailFolder operation="read" messagesNumbers="123-130"/> <%-- then reads messages 150-180 --%> <m:mailFolder operation="read" messagesNumbers="150-180"/> </m:mailFolder>
As an extension, <m:mailFolder> supports all attributes of <m:map>. Attributes specific to <m:mailFolder> are as follows:
name | type | description | default value |
---|---|---|---|
url | String | mailbox server url | null |
operation | String | operation to perform; either "read" or "delete" | read |
messages | Object | comma-separated string of message numbers or ranges of message numnbers, or list of message numbers or instances of javax.mail.Message, to be read or deleted; "*" means "all" | null |
control | Object | Map or form-encoded string of control properties. | null |
When necessary, you can use "System:invoke" codec to call a java method dynamically. "System:invoke" takes a nested map operand having the following properties:
name | description |
---|---|
object | Object on which an instance method is invoked. |
class | Class object of which a static method is invoked. This can be either an instance of java.lang.Class, or type string ("String", "int[]", "java.lang.security.MessageDigest", etc.). If "." (dot) is missing from the class name, then "java.lang" package is assumed. |
method | name of the method to be invoked. If this is "*" (asterisk), then a constructor for given class is invoked. If this starts with a "." (dot), then it is taken as a field name instead of a method name. |
_ | list of method arguments. Each list element is a map with type and value properties, or an object if its type matches the argument type. The type can be either an instance of a java.lang.Class or type string like "java.lang.Integer". |
For example:
<%-- performs "This is a Test".substring(3) --%> <m:map codec="System:invoke"> <m:set property="object" value="This is a Test"/> <m:set property="method" value="substring"/> <m:map property="@_.*"> <m:set property="type" value="int"/> <m:set property="value" value="3"/> </m:map> </m:map> <%-- creates a char[] of size 4 initialized to {'a', 'b', 'c', 'd'} --%> <m:set var="c"> <m:map attribute="value" codec="System:invoke"> <m:set property="class" value="java.lang.reflect.Array"/> <m:set property="method" value="newInstance"/> <m:map property="@_.*"> <m:set property="type" value="java.lang.Class"/> <m:set property="value" codec="Type:forName" value="char"/> </m:map> <m:map property="@_.*"> <m:set property="type" value="int"/> <m:set property="value" value="4"/> </m:map> </m:map> <%-- initialize char[] to {'a','b','c','d'} --%> <m:set property="0" codec="Type:isCharacter" value="a"/> <m:set property="1" codec="Type:isCharacter" value="b"/> <m:set property="2" codec="Type:isCharacter" value="c"/> <m:set property="3" codec="Type:isCharacter" value="d"/> </m:set> <%-- creates a String "abcd" out of char[] "c" --%> <m:map codec="System:invoke"> <m:set property="class" value="String"/> <m:set property="method" value="*"/> <m:map property="@_.*"> <m:set property="type" value="char[]"/> <m:set property="value" value="${c}"/> </m:map> </m:map> <%-- gets the value of "javax.xml.transform.OutputKeys.MEDIA_TYPE" --%> <m:map codec="System:invoke"> <m:set property="class" value="javax.xml.transform.OutputKeys"/> <m:set property="method" value=".MEDIA_TYPE"/> </m:map>
A "dynamic map" is a special kind of map that calls specified codecs on "get" and "put" operations. Such a map can be created by "_JSP:dynamicMap" codec on an "operand" map with "getCodec" and "putCodec" properties set. On each "get" operation with key "XXX" on the resulting dynamic map, the codec defined by "getCodec" property is invoked on the original "operand" map with its "key" property set to "XXX". On each "put" operation with key "XXX" and value "YYY" on the resulting dynamic map, the codec defined by "putCodec" proprty is invoked on the original "operand" map with its "key" property set to "XXX" and its "value" property set to "YYY". In either case, the original "codec" map is also accessible by using the "_" (underscore) variable within the invoked codecs. For example:
<%-- a dynamic map that maps key to its length --%> <m:map var="lengthMap" codec="_JSP:dynamicMap"> <m:set property="getCodec" value="Bean:get:key|Type:length"/> <%-- or equivalently <m:set property="getCodec" value="Type:length_:@{_.key}"/> --%> </m:map> <%-- this outputs 10 --%> <m:out value="${lengthMap['somestring']}"/>
Properties of the "operand" map other than "getCodec", "putCodec", "key", "value" can be freely used. For example:
<%-- a case-insensitive dynamic map --%> <m:map var="ignoreCaseMap" codec="_JSP:dynamicMap"> <m:map property="storage"/> <m:map property="getCodec" value="String:toUpperCase_:@{_.key}|Bean:get_:@{_.storage}:@{_operand}"/> <m:map property="putCodec" value="String:toUpperCase_:@{_.key}|Bean:set_:@{_.storage}:@{_operand}:@{_.value}"/> </m:map> <m:set target="${ignoreCaseMap}" property="this" value="something"/> <m:out value="${ignoreCaseMap['This']}"/> <m:out value="${ignoreCaseMap['THIS']}"/>
You can combine "System:invoke" to create a dynamic map that calls java methods:
<m:map var="SYSTEMPROPERTY" codec="_JSP:dynamicMap"> <m:map property="getMethod"> <m:set property="class" value="java.lang.System"/> <m:set property="method" value="getProperty"/> <m:map property="@_.*"> <m:set property="type" value="String"/> </m:map> </m:map> <m:map property="putMethod"> <m:set property="class" value="java.lang.System"/> <m:set property="method" value="setProperty"/> <m:map property="@_.*"> <m:set property="type" value="String"/> </m:map> <m:map property="@_.*"> <m:set property="type" value="String"/> </m:map> </m:map> <m:set property="getCodec" value="Bean:set_:@{_.getMethod}:@_.0.value:@{_.key}|System:invoke_:@{_.getMethod}"/> <m:set property="putCodec" value="Bean:set_:@{_.putMethod}:@_.0.value:@{_.key}|Bean:set_:@{_.putMethod}:@_.1.value:@{_.value}|System:invoke_:@{_.putMethod}"/> </m:map> <m:out value="${SYSTEMPROPERTY['os.name']}"/> <m:set target="${SYSTEMPROPERTY}" property="unknown" value="UNKNOWNPROPERTY"/> <m:out value="${SYSTEMPROPERTY['unknown']}"/>
A "dynamic iterator" is a dynamically controllable iterator. You can create a dynamic iterator for a collection using "_JSP:dynamicIterator" as follows:
<%-- "words" is a ["this", "is", "a", "test"] --%> <m:set var="words" value="this is a test" codec="String:split: :"/> <%-- regular iteration over "words" --%> <c:forEach var="word" items="${words}"> <m:out value="${word}"/> </c:forEach> <%-- create a dynamic iterator for "words" --%> <m:map var="wordIterator" codec="_JSP:dynamicIterator"> <m:set property="collection" value="${words}"/> </m:map> <%-- iteration using dynamic iterator, same as above --%> <c:forEach var="word" items="${wordIterator}"> <m:out value="${word}"/> </c:forEach>
A dynamic iterator can be changed dynamically; e.g., the following breaks out of the loop after finding a word "a":
<%-- iteration using dynamic iterator, break on "a" --%> <c:forEach var="word" items="${wordIterator}"> <m:out value="${word}"/> <c:if test="${word == 'a'}"> <%-- makes the "wordIterator" return "false" on the next iteration --%> <m:set target="${wordIterator}" property="hasNext" value="false"/> </c:if> </c:forEach>
You can create a "while" loop:
<%-- keep removing "10" while found --%> <m:map var="whileLoop" codec="_JSP:dynamicIterator"> <m:set property="hasNext" value="true"/> </m:map> <m:set var="x" value="10001010111001101"/> <c:forEach items="${whileLoop}"> <m:set var="before" value="${x}"/> <m:set var="x" value="${x}" codec="String:replaceAll:10::"/> <m:out value="[[${before}:${x}]]"/> <m:set target="${whileLoop}" property="hasNext" value="${x != before}"/> </c:forEach> <m:out value="${x}"/>
or a "for" loop:
<%-- loop for i = 0, 1, 2, 3, 4 --%> <m:map var="forLoop" codec="_JSP:dynamicIterator"> <m:set property="hasNextCodec" value="@{_.index < 5}"/> <m:set property="nextCodec" value="Bean:get:index"/> </m:map> <c:forEach var="i" items="${forLoop}"> <m:out value="${i}"/> </c:forEach>
The following properties are supported:
name | description |
---|---|
collection | collection to iterate over |
hasNext | boolean value that indicates if this iterator has more elements to visit or not. If "hasNextCodec" is not set, then this takes precedence over "collection" if set. |
hasNextCodec | codec to be invoked for each "hasNext" operation. This is supposed to return true if the iterator has more elements to iterate over, or false otherwise. This has precendence over "hasNext" or "collection" if set. |
next | next object to be visited. If "nextCodec" is not set, then this takes precendence over "collection" if set. |
nextCodec | codec to be invoked for each "next" operation. This is supposed to return the next object to visit. This takes precedence over "next" or "collection" if set. |
index | 0-based iteration index increased each time iteration is made. |
You can use XMLMap:encode and XMLMap:decode to perform simple conversion of a NestedMap to/from XML. By default, it performs conversion according to the following rules:
For example, the following:
<m:map exportCodec="XMLMap:encode"> <m:set property="a">p</m:set> <m:map property="b"> <m:set property="c">q</m:set> <m:set property="d">r</m:set> </m:map> </m:map>
outputs:
<root> <a>p</a> <b> <c>q</c> <d>r</d> </b> </root>
and the following:
<m:map exportCodec="XMLMap:encode"> <m:map property="@_.*"> <m:set property="a">p0</m:set> <m:set property="b">q0</m:set> </m:map> <m:map property="@_.*"> <m:set property="a">p1</m:set> <m:set property="b">q1</m:set> </m:map> <m:map property="@_.*"> <m:set property="a">p2</m:set> <m:set property="b">q2</m:set> </m:map> </m:map>
outputs:
<root> <_> <item index="0"> <a>p0</a> <b>q0</b> </item> <item index="1"> <a>p1</a> <b>q1</b> </item> <item index="2"> <a>p2</a> <b>q2</b> </item> </_> </root>
You can convert generated XML back to NestedMap using XMLMap:decode:
<%-- this outputs "{_=[{a=p0, b=q0}, {a=p1, b=q1}, {a=p2, b=q2}]}" --%> <m:out codec="XML:parse|XMLMap:decode|Bean:get:root"> <m:map exportCodec="XMLMap:encode"> <m:map property="@_.*"> <m:set property="a">p0</m:set> <m:set property="b">q0</m:set> </m:map> <m:map property="@_.*"> <m:set property="a">p1</m:set> <m:set property="b">q1</m:set> </m:map> <m:map property="@_.*"> <m:set property="a">p2</m:set> <m:set property="b">q2</m:set> </m:map> </m:map> </m:out>
You can change the default behaviour by using optional "controlMap" (which is either a map or a form-encoded string). For example, you can change the default root name "root" by using controlMap set as "rootName=xxx":
<m:map exportCodec="XMLMap:encode:rootName=response"> <m:set property="a">p</m:set> <m:map property="b"> <m:set property="c">q</m:set> <m:set property="d">r</m:set> </m:map> </m:map>
outputs:
<response> <a>p</a> <b> <c>q</c> <d>r</d> </b> </response>
On decoding, you can specify a "nameMap" controlMap element which can be used to perform simple element name conversion; for example, if given XML has multiple elements:
<list> <item>a</item> <item>b</item> <item>c</item> </list>
You can still apply XMLMap:decode using the following controlMap:
<%-- this outputs {list={_=[a,b,c]}} --%> <m:out codec="XML:parse|XMLMap:decode:nameMap.item=@_.*"> <list> <item>a</item> <item>b</item> <item>c</item> </list> </m:out>
When XMLMap encounters an element named "xxx", the value of "nameMap.xxx" of the controlMap, if given, is used as the map property to assign the element value to, instead of default "xxx". In this case, each value of "item" element is assigned to "@_.*" property of the resulting map.
When a map key is not a valid XML element name (e.g., a number), then XMLMap performs the following conversion on encoding/decoding:
_JSP:getMessageMap creates a map that can be used to access resource messages instead of using JSTL <fmt:message>. You can create a message map as follows:
<m:set var="message" codec="_JSP:getMessageMap_"/>
Then the following two are equivalent:
${message['x']} <fmt:message key="x"/>
You can specifiy message parameters using ':' like codec syntax. The following two are equivalent:
${message['x:@{a}:b']} <fmt:message key="x"> <fmt:param value="${a}"/> <fmt:param value="b"/> </fmt:message>
Unlike <fmt:message>, the default value returned for missing messages is empty string:
This is empty:${message['undefined']} But this is not:<fmt:message key="undefined"/>
You can set your own default value by setting the "defaultValue" property of the message map:
<m:set target="${message}" property="defaultValue" value="MISSING"/> This is "MISSING":${message['undefined']}
To make the message map return the same default value as <fmt:message>, set the "defaultValue" property to "*". If necessary, you can also set the base name of the message resource by setting "baseName" property. You can apply "_JSP:getMessageMap" to a map that defines these properties:
<%-- creates a message map that behaves like <fmt:message> --%> <m:map var="message" codec="_JSP:getMessageMap"> <m:set property="defaultValue" value="*"/> </m:map>
You can use "JSON:encode" and "JSON:decode" codecs to encode/decode object (string/list/map) to/from string in JSON format. For example:
<m:map var="x"> <m:set property="a">'quoted'</m:set> <m:set property="b" codec="JSON:decode">{p:q, r:s}</m:set> <m:set property="@_.*" value="${3.2}"/> <m:set property="@_.*" value="${true}"/> </m:map> <%-- This outputs: '\'quoted\'' [3.2,true] {"a":"\'quoted\'","_":[3.2,true],"b":{"r":"s","p":"q"}} --%> <m:out value="${x.a}" codec="JSON:encode:quote='"/> <m:out value="${x._}" codec="JSON:encode"/> <m:out value="${x}" codec="JSON:encode"/>
Note that only booleans and numbers are encoded without quotes. If "${3.2}" above (which is evaluated as double) is replaced with string "3.2", then the output will be "3.2" with quotes.
For a NestedMap, you can use "__source" or "__json" property instead:
<m:map export="@{_.__json}"> <m:set property="__source">{"a":"\'quoted\'","_":[3.2,true],"b":{"r":"s","p":"q"}}</m:set> </m:map>
When necessary, it is possible to run Javascript code on the server using "Javascript:eval" codec (this requires "js.jar" from Rhino project in your CLASSPATH (e.g., "/WEB-INF/lib)). For example:
<%-- environment for Javascript --%> <m:map var="env"> <m:set property="x" value="123"/> </m:map> <%-- this prints "ok" --%> <m:out codec="Javascript:eval:@{env}"> // returns "ok" if d is an integer function checkInteger(d) { if (!d) { return "missing"; } else if (!d.match("[+-]?[0-9]+")) { return "format"; } else { return "ok"; } } // x is set by env checkInteger(x); </m:set>
It is also possible to compile Javascript code using "Javascript:compile" codec. The returned value can be used as the operand for "Javascript:eval". For example, the code above can be pre-compiled as follows:
<m:set var="compiled" codec="Javascript:compile"> function checkInteger(d) { if (!d) { return "missing"; } else if (!d.match("[+-]?[0-9]+")) { return "format"; } else { return "ok"; } } checkInteger(x); </m:set> <%-- evaluates compiled code --%> <m:out value="${compiled}" codec="Javascript:eval:@{env}"/>
NodeMap is a special kind of NestedMap that mirrors XML DOM Nodes. Please refer to Sun's documentation for more information about DOM Nodes. DOM Nodes are mapped to NestedMaps with "type", "name", "value", "attributes", and "_" list properties as follows:
A DOM Node can be converted to NodeMap by using "NodeMap:encode" codec, and a NodeMap can be converted to DOM Node by using "NodeMap:decode" codec. For example:
<m:map var="inputs" source="{a:alpha, b:beta, c:gamma}"/> <%-- convert a template to NodeMap and take the "input" part (note that the root element is "Document" --%> <m:set var="inputSegment" codec="XML:parse|NodeMap:encode|Bean:get:@_.0"> <input type="text" style="text-align:right" name="x" value="y" /> </m:set> <%-- replace name/value attributes for each entry of "inputs" and output as HTML --%> <c:forEach var="input" items="${inputs.__entryListSorted}"> <m:map source="${inputSegment}" codec="NodeMap:decode|XML:output:method=html"> <m:set property="@attributes.name" value="${input.key}"/> <m:set property="@attributes.value" value="${input.value}"/> </m:map> </c:forEach> <%-- similarly generated option list --%> <m:set var="selected" value="b"/> <m:set var="optionSegment" codec="XML:parse|NodeMap:encode|Bean:get:@_.0"> <option style="text-align:right" value="y">name</option> </m:set> <select style="text-align:right"> <c:forEach var="input" items="${inputs.__entryListSorted}"> <m:map source="${optionSegment}" codec="NodeMap:decode|XML:output:method=html"> <m:set property="@attributes.value" value="${input.key}"/> <m:set property="@_.0" value="${input.value}"/> <m:set property="@attributes.selected" value="selected" test="${input.key == selected}"/> </m:map> </c:forEach> </select>
outputs the following:
<input name="a" style="text-align:right" type="text" value="alpha"> <input name="b" style="text-align:right" type="text" value="beta"> <input name="c" style="text-align:right" type="text" value="gamma"> <select style="text-align:right"> <option style="text-align:right" value="a">alpha</option> <option selected style="text-align:right" value="b">beta</option> <option style="text-align:right" value="c">gamma</option> </select>
This section assumes that you are familiar with writing custom JSP tags. You need to have "yuzu.jar" in your CLASSPATH along with JSTL jar files and other servlet/jsp-related class files.
To build a custom YUZU tag that doesn't need custom attributes,
For example, the following code defines a tag that converts given tagvalue to lower case as String:
package com.mycompany.jsp.tag; import com.micronova.jsp.tag.*; public class LowerCaseTag extends YuzuTag { protected Object processValue(Object tagValue) throws Exception { if (tagValue != null) { tagValue = tagValue.toString().toLowerCase(); } return tagValue; } }
Then publish it by adding to the TLD file something like the following:
<tag> <name>lowerCase</name> <tag-class>com.mycompany.jsp.tag.LowerCaseTag</tag-class> <body-content>JSP</body-content> <attribute><name>var</name><required>false</required></attribute> <attribute><name>target</name><required>false</required></attribute> <attribute><name>property</name><required>false</required></attribute> <attribute><name>attribute</name><required>false</required></attribute> <attribute><name>scope</name><required>false</required></attribute> <attribute><name>value</name><required>false</required></attribute> <attribute><name>default</name><required>false</required></attribute> <attribute><name>className</name><required>false</required></attribute> <attribute><name>source</name><required>false</required></attribute> <attribute><name>exportCodec</name><required>false</required></attribute> <attribute><name>importCodec</name><required>false</required></attribute> <attribute><name>processCodec</name><required>false</required></attribute> <attribute><name>codec</name><required>false</required></attribute> <attribute><name>assignCodec</name><required>false</required></attribute> <attribute><name>test</name><required>false</required></attribute> <attribute><name>local</name><required>false</required></attribute> <attribute><name>assign</name><required>false</required></attribute> <attribute><name>export</name><required>false</required></attribute> <attribute><name>doesExport</name><required>false</required></attribute> </tag>
For JSP 2.0, add "<rtexprvalue>true</rtexprvalue>" to each "attribute" statement.
All YUZU attributes work with the new "lowerCase" tag. For example, the following code:
<m:map> <m:lowerCase property="lower" value="UpperCase"/> </m:map>
outputs:
lower=uppercase
To build a custom YUZU tag with custom attributes, the following extra steps are necessary:
For example, the following code defines a tag that "multiplies" (appends to itself) given tagvalue as String. It takes a custom integer attribute named "count".
package com.mycompany.jsp.tag; import com.micronova.jsp.tag.*; public class MultiplyTag extends YuzuTag { /** "count" attribute */ Integer _count; /** initialization. Make sure super.init() is called first. */ protected void init() { super.init(); /** default count is 2 */ _count = new Integer(2); } /** processes tagValue. */ protected Object processValue(Object tagValue) throws Exception { if (tagValue != null) { String tagValueString = tagValue.toString(); StringBuffer buffer = new StringBuffer(); for (int i = _count.intValue(); --i >= 0;) { buffer.append(tagValueString); } tagValue = buffer.toString(); } return tagValue; } /** attribute setter for "count".*/ public void setCount(Object expression) throws Exception { _count = (Integer)evaluateAttribute("count", expression, Integer.class, _count); } }
The method "evaluateAttribute()" takes the name of the attribute (for error output), an EL expression, the type of the value resulting from evaluating the EL expression, and the attribute's current value. Note that the "expression" is an Object, not a String, to make attribute attribute work ("evaluateAttribute()" returns the "expression" object as-is if called within tag body).
The TLD entry will be something like this:
<tag> <name>multiply</name> <tag-class>com.mycompany.jsp.tag.MultiplyTag</tag-class> <body-content>JSP</body-content> <attribute><name>var</name><required>false</required></attribute> <attribute><name>target</name><required>false</required></attribute> <attribute><name>property</name><required>false</required></attribute> <attribute><name>attribute</name><required>false</required></attribute> <attribute><name>scope</name><required>false</required></attribute> <attribute><name>value</name><required>false</required></attribute> <attribute><name>default</name><required>false</required></attribute> <attribute><name>className</name><required>false</required></attribute> <attribute><name>source</name><required>false</required></attribute> <attribute><name>exportCodec</name><required>false</required></attribute> <attribute><name>importCodec</name><required>false</required></attribute> <attribute><name>processCodec</name><required>false</required></attribute> <attribute><name>codec</name><required>false</required></attribute> <attribute><name>assignCodec</name><required>false</required></attribute> <attribute><name>test</name><required>false</required></attribute> <attribute><name>local</name><required>false</required></attribute> <attribute><name>assign</name><required>false</required></attribute> <attribute><name>export</name><required>false</required></attribute> <attribute><name>doesExport</name><required>false</required></attribute> <attribute><name>count</name><required>false</required></attribute> </tag>
For JSP 2.0, add "<rtexprvalue>true</rtexprvalue>" to each "attribute" statement.
This chapter only applies to the JSP 2.0 version of YUZU.
JSP 2.0 introduces EL functions, but unfortunately it does not support multiple function signatures, so the tag descriptor "m.tld" declares YUZU codecs as EL functions using the following naming convention by default:
m:CodecName_CodecMethod[_NumberOfArguments](...)
If "NumberOfArguments" suffix is omitted, it refers to the method with the smallest number of arguments (without optional arguments). For example, "m:URL_encode" is equivalent to "m:URL_encode_1", and is different from "m:URL_encode_2" which takes optional ENCODING argument. Note that the object to which the codec is applied is always the first argument. The following two are equivalent:
<m:out value="Hello World" exportCodec="URL:encode:utf-8|Hex:encode"/> <m:out value="${m:Hex_encode(m:URL_encode_2('Hello World', 'utf-8'))}"/>
Another problem is that EL functions are not well supported in dynamic EL evaluation yet (e.g., the prefix used to declare EL functions is only known at compile time). Because of this, YUZU uses hardcoded "fn" prefix for JSTL standard functions, and "m" prefix for YUZU codec functions when EL expressions are dynamically evaluated (i.e., in "@{...}" or "%{...}").
For dynamic EL evaluation, you can also use codec-style function names such as "URL:encode", or "com.yourcompany.codec.Codec:method". To handle multiple function signatures, you can append the number of arguments using underscore (e.g., "String:join_2"), or append "_max" for the method with the largest number of arguments, or "_min" for the method with the smallest number of arguments (this is the default). For example, "URL:encode_max" is equivalent to "URL:encode_2", and "URL:encode" is equivalent to "URL:encode_min" or "URL:encode_1".
There is no mechanism to pass implicit variables in JSP 2.0 EL functions yet, so you need to supply all variables explicitly. For example, the following are equivalent:
<m:out value="index.jsp" codec="_JSP:encodeURL"/> <m:out value="${m:JSP_encodeURL(pageContext, 'index.jsp')}"/>