Chapter 4. JSP and Custom Tags

4.1. Aranea Standard Tag Library

Aranea supports JSP rendering by providing a JSP 1.2 custom tag library that tries to abstract away from HTML and allow programming in terms of widgets, layouts and logical GUI elements. The tag library URI is "http://araneaframework.org/tag-library/standard" and it is contained in aranea-presentation.jar, so putting this JAR in the classpath (e.g. WEB-INF/lib) is enough to put it to work. Library tags support JSP Expression Language that is used in JSTL 1.0.

Aranea examples use JSP XML form and in such form importing the library should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" 
  xmlns:ui="http://araneaframework.org/tag-library/standard" version="1.2">
  ...
</jsp:root>

In a usual JSP file it should look like this:

<%@ taglib uri="http://araneaframework.org/tag-library/standard" prefix="ui" %>
...

The suggested prefix for the tag library is "ui".

There is otherwise identical taglib that has <rtexprvalue> set to true for each tag attribute. URI for that taglib is http://araneaframework.org/tag-library/standard_rt. When using JSP version 2.0 or higher, this taglib should be used, otherwise EL in attributes is rejected by containers.

4.2. System Tags

Aranea JSP rendering should start from some root JSP (root template) that will include the root widget(s) (which typically are some kind of flowcontainers or menus). To support widgets and other custom tags one needs to make sure that the template looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<jsp:root 
  xmlns:jsp="http://java.sun.com/JSP/Page" 
  xmlns:ui="http://araneaframework.org/tag-library/standard" version="1.2">
  <ui:widgetContext>
    <html>
      <head>
        <title>Aranea Template Application</title>
         
        <ui:importScripts/>      
        <ui:importStyles/>      
   
      </head>
    
        <ui:body>
          <ui:systemForm method="POST">
            <h1>Aranea Application</h1>
              
            <ui:messages/>

            <ui:widgetInclude id="root"/>
          </ui:systemForm>
          
      </ui:body>   
    </html>
  </ui:widgetContext>
</jsp:root>

Next are described all these tags except <ui:widgetInclude>, which is described in the following section.

4.2.1. <ui:importScripts>

Aranea comes bundled with different external resources: javascript libraries, stylesheets and images. To automate the process of loading the javascript files without the manual copying of them to specific webapp locations, a special filter is used. The filter is able to read files from aranea jar files.

<ui:importScripts> depends on the filter StandardServletFileImportFilterService being set. The filter provides the functionality of reading files from the jars on the server.

If no attributes specified, the default group of javascript files are loaded.

Attributes

AttributeRequiredDescription
filenoWrites HTML <script> tag to load the specific file.
groupnoWrites HTML <script> tag to load a group of javascript files.

Here is the list of all available values for the group attribute:

  1. all - imports all of the groups described below.
  2. core-all - imports the core Aranea scripts, in addition, popup, modalbox, back-button support (rsh) scripts.
  3. core - imports only core aranea scripts that are always needed.
  4. calendar - imports only DHTML calendar scripts.
  5. calendar_et - imports only DHTML calendar scripts with an interface in estonian language.
  6. modalbox - imports only ModalBox scripts.
  7. rsh - imports only back-button support scripts.
  8. prototip - imports only Prototip scripts.
  9. ajaxupload - imports only AJAX upload functionality scripts.
  10. logger - imports only log4javascript scripts.

Note

Since 1.2.1 these Aranea JavaScript files (groups) are compressed for faster download. However, it also possible to see these scripts in more readable form by appenging "-devel" to these group names, e.g. all vs. all-devel. These groups don't have the devel version:

  • calendar
  • calendar_et
  • prototip
  • ajaxupload
  • logger (always compressed)

If you are used to including aranea*.js scripts one-by-one then your scripts will be automatically compressed. To include original scripts, insert "src/" right before the file name, e.g.

<ui:importScripts file="js/aranea/aranea.js"/>

to:

<ui:importScripts file="js/aranea/src/aranea.js"/>

To use TinyMCE editor, you need to include its scripts like this:

<ui:importScripts file="js/tiny_mce/tiny_mce.js"/>

Examples

<?xml version="1.0" encoding="UTF-8"?>
<ui:importScripts/> <!-- imports files from 'all' group -->
<ui:importScripts group="logger"/> <!-- imports additional debug scripts (js logger) -->

4.2.2. <ui:importStyles>

Aranea comes bundled with CSS files to provide custom look for different predefined components (the template app, calendar, htmleditor, etc.). Just as with javascript, to use them one would have to extract them from the jars and use them just like any other css file would be used. To automate this process with aranea css files one can use the <ui:importStyles> tag to include the css files automatically.

<ui:importStyles> depends on the filter StandardServletFileImportFilterService being set. The filter provides the functionality of reading files from the jars on the server.

If no are attributes specified, the default group (i.e. all) of css files are loaded.

Attributes

AttributeRequiredDescription
filenoWrites out the HTML's CSS handling link to load the specific file.
groupnoWrites out the HTML's CSS handling link to load the group of files.
medianoMedia type to which imported styles are applied.

Here is the list of all available values for the group attribute:

  1. all - imports all of the styles (CSS) from the groups described below.
  2. aranea - imports only Aranea styles (aranea.css for the page loading message, and comboselect.css for multiselect combo box.
  3. calendar - imports only DHTML calendar styles.
  4. contextmenu - imports only Aranea context menu styles.
  5. modalbox - imports only ModalBox styles.
  6. prototip - imports only Prototip styles.

4.2.3. <ui:body>

This tag will render an HTML <body> tag with Aranea JSP specific onload and onunload events attached. It usually writes out some other page initialization scripts too, depending on the circumstances. It must be present in a JSP template, otherwise most client-side functionality will cease to function.

Attributes

AttributeRequiredDescription
onloadnoOverwrite the standard Aranea JSP HTML body onload event. Use with caution.
onunloadnoOverwrite the standard Aranea JSP HTML body onload event. Use with caution.
idnoHTML BODY id.
dirnoHTML BODY dir attribute.
langnoHTML BODY lang attribute.
titlenoHTML BODY title attribute.

4.2.4. <ui:systemForm>

This tag will render an HTML <form> tag along with some Aranea-specific hidden fields. When making custom web applications it is strongly suggested to have only one system form in the template and have it submit using POST. This will ensure that no matter what user does no data is ever lost. However Aranea does not impose this idiom and one may just as well submit using GET, define system forms in widgets and use usual HTML links instead of JavaScript. See Section 4.2, “System Tags” for usage example and Section 3.5.20, “System Form Field Storage Filter” about a filter that provides some essential hidden fields.

Attributes

AttributeRequiredDescription
idnoThe HTML "id" of the <form> tag that may be used in JavaScript. It will be autogenerated if omitted.
methodyesHTTP submit method, either GET or POST.
enctypenoSame as HTML <form> attribute enctype, defines how form data is encoded.

Variables

VariableDescriptionType
systemFormIdSystemForm FORM id.String

4.2.5. <ui:messages>

This tag will render messages of given type if they are present in current MessageContext. When type is not specified, all types of messages are rendered. As MessageContext is typically used for error messages, it is common to render these messages somewhere near top of the page, where they can easily be spotted.

Attributes

AttributeRequiredDescription
typenoMessage type.
styleClassnoCSS class applied to rendered messages, default being aranea-messages.
divIdnoSets the id of the HTML <div> inside which the messages are rendered. If left unspecified, no id is assigned.
stylenoCSS inline style applied to rendered messages. Use styleClass instead.

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
<ui:messages type="info"/>
<ui:messages type="error" styleClass="custom-error-message-class"/>
<ui:messages/>
...

4.3. Basic Tags

4.3.1. <ui:attribute>

Defines an attribute of the containing element, where possible. See also Section 4.3.3, “<ui:element>”. Most form element tags accept attributes set by this tag too, see the section called “Examples”.

AttributeRequiredDescription
nameyesAttribute name.
valueyesAttribute value.

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
  <!-- set the onkeypress attribute for HTML input produced by ui:textInput-->
  <ui:textInput>
    <ui:attribute name="onkeypress" value="upperCase(this);"/>
  </ui:textInput>
...

4.3.2. <ui:elementContent>

Defines an HTML element content, meaning the body of the HTML element where text and other tags go.

4.3.3. <ui:element>

Defines HTML node, can be used together with <ui:attribute> and <ui:elementContent> to define a full HTML node.

AttributeRequiredDescription
namenoHTML element name.

Examples

<?xml version="1.0" encoding="UTF-8"?>
<ui:element name="span">
  <ui:attribute name="class" value="fancy"/>
  <ui:elementContent>Contents of fancy span.</ui:elementContent>
</ui:element>

4.3.4. <ui:keyboardHandler>

Registers a simple javascript keyboard handler.

AttributeRequiredDescription
scopenoWhen a keyboard event happens, it is usually associated with a certain form element / form / widget / etc. The object with which an event is associated is identified by a hierarchical id (e.g. there may be widget 'somelist', containing form 'somelist.form', containing textbox 'somelist.form.textbox'. The scope is a prefix of that id that must match in order for the handler to be triggered. For example, the handler with scope='somelist.form.textbox' will be triggered only when the event in the textbox occurs, but the handler with scope="somelist" will be triggered when any event in any of the elements inside any of the forms of "somelist" occurs. I.e. for any element with ID beginning with 'somelist'. When scope is not specified, a global handler is registered, that reacts to an event in any form/widget.
handleryesA javascript handler function that takes two parameters - the event object and the element id for which the event was fired. Example:
function(event, elementId) { alert(elementId); }
keyCodenoKeycode to which the event must be triggered. 13 means enter. Either keyCode or key must be specified, but not both.
keynoKey, to which the event must be triggered. Key is specified as a certain 'alias'. The alias may be an ASCII character or a digit (this will denote the corresponding key on a US keyboard), a space (' '), or one of the following: 'return', 'escape', 'backspace', 'tab', 'shift', 'control', 'space', 'f1', 'f2', ..., 'f12'.
keyCombonoKey combination, which should trigger the event. It can is specified with key aliases separated with "+" signs. For example "ctrl+alt+f1", "alt+r" etc.

Examples

<!-- Globally-scoped F2 listener -->
<ui:keyboardHandler 
  scope="" 
  key="f2" 
  handler="function() { alert('You pressed F2. Do it again if you dare!');}"/>

4.3.5. <ui:eventKeyboardHandler>

Registers a 'server-side' keyboard handler that sends an event to the specified widget.

AttributeRequiredDescription
scopenoSection 4.3.4, “<ui:keyboardHandler>”
widgetIdnoId of Widget that is target of event produced by keyboard handler.
eventIdnoId of event that should be sent to target widget.
eventParamnoEvent parameters
updateRegionsnoEnumerates the regions of markup to be updated in this widget scope. Please see <ui:updateRegion> for details.
globalUpdateRegionsnoEnumerates the regions of markup to be updated globally. Please see <ui:updateRegion> for details.
keyCodenoKeycode to which the event must be triggered. 13 means enter. Either keyCode or key must be specified, but not both.
keynoKey, to which the event must be triggered. Key is specified as a certain 'alias'. The alias may be an ASCII character or a digit (this will denote the corresponding key on a US keyboard), a space (' '), or one of the following: 'return', 'escape', 'backspace', 'tab', 'shift', 'control', 'space', 'f1', 'f2', ..., 'f12'.
keyCombonoKey combination, which should trigger the event. It can is specified with key aliases separated with "+" signs. For example "ctrl+alt+f1", "alt+r" etc.

Examples

<!-- F2 listener that sends event 'add' to context widget upon activation -->
<ui:eventKeyboardHandler eventId="add" key="f2" widgetId="${widgetId}"/>

4.4. Widget Tags

4.4.1. <ui:widgetContext>

This tag should generally be the root of every widget JSP. It makes the widget view model accessible as an EL variable. It can also be used to render a descendant widget in the same JSP with the current widget. In the latter case you should set the id attribute to the identifier path of the descendant widget in question. Note that all widget-related tags inside of this tag will assume that the widget in question is their parent or ancestor (that is all the identifier paths will start from it).

Attributes

AttributeRequiredDescription
idnoA dot-separated widget identifier path leading from the current context widget to the new one.

Variables

VariableDescription
widgetThe context widget instance. Can be used to access JavaBean property data from the widget (e.g. ${widget.foo} will translate to a getFoo() widget call}.
widgetIdThe full dot-separated identifier of the context widget.
viewDataThe view data of the context widget (see BaseApplicationWidget.putViewData()).
viewModelThe view model of the context widget.
scopedWidgetIdThe scoped id of the context widget.

Examples

The most common usage of <ui:widgetContext> is as root tag for widget JSPs:
<?xml version="1.0" encoding="UTF-8"?>
...
  <ui:widgetContext>
    ...
    <c:out value="${viewData.myMessage}"/>
    ...
  </ui:widgetContext>
...
The other use case is to render a descendant widget:
<?xml version="1.0" encoding="UTF-8"?>
...
  <ui:widgetContext>
    ...
    <ui:widgetContext id="child.ofMyChild">
      <c:out value="${viewData.messageFromChildOfMyChild}"
    </ui:widgetContext>
    ...
  </ui:widgetContext>
...

4.4.2. <ui:widget>

This tag is used when one needs to render a child or descendant widget while still retaining in both current widget context and JSP. It publishes the widget view model and full identifier as EL variables, but does little else and does not setup a widget context (e.g. <ui:widgetInclude> tag will not take it into account).

Attributes

AttributeRequiredDescription
idyesA dot-separated widget identifier path leading from the current context widget to the target widget.

Variables

VariableDescription
widgetThe widget instance. Can be used to access JavaBean property data from the widget (e.g. ${widget.foo} will translate to a getFoo() widget call}.
widgetIdThe full dot-separated identifier of the widget.
viewDataThe view data of the widget (see BaseApplicationWidget.putViewData()).
viewModelThe view model of the widget.
scopedWidgetIdThe scoped id of the context widget.

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
  <ui:widgetContext>
    ...
    <ui:widget id="child.ofMyChild">
      <c:out value="${viewData.messageFromChildOfMyChild}"
          <ui:widgetInclude id="child"/>
    </ui:widget>
    ...
  </ui:widgetContext>
...

4.4.3. <ui:widgetInclude>

This tag is used to render some child or descendant widget. It will call the widget's render() method, which will allow the target widget to choose how to render itself.

Attributes

AttributeRequiredDescription
idyesA dot-separated widget identifier path leading from the current context widget to the target widget.
pathnoPath to JSP, relative to jspPath of StandardJspFilterService.

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
  <ui:widgetContext>
    ...
    <ui:widgetInclude id="child.ofMyChild"/>
    ...
  </ui:widgetContext>
...

4.5. Event-producing Tags

4.5.1. <ui:eventButton> and <ui:eventLinkButton>

These tags will render a button (or a link) that when clicked will send a specified event to the target widget with an optional String parameter.

Attributes

AttributeRequiredDescription
idnoHTML "id" of the element that can be used to access it via DOM.
labelIdnoThe key of the localizable label that will be displayed on the button.
eventIdnoThe identifier of the event that will be sent to the target widget.
eventParamnoString event parameter that will accompany the event.
eventTargetnoID of receiving widget. Almost never set directly. Defaults to current context widget.
disablednoIf set to a not null value will show the button disabled.
renderModenoAllowed values are (button | input) - the corresponding HTML tag will be used for rendering. Default is button. This attribute only applies to <ui:eventButton>, <ui:eventLinkButton> is always rendered with HTML link.
styleClassnoThe CSS class that will override the default one.
updateRegionsnoComma separated list of update regions that should be updated upon button receiving event. This attribute is only needed when using AJAX features—ordinary HTTP requests always update whole page.
globalUpdateRegionsnoComma separated list of global update regions that should be updated upon button receiving event. This attribute is only needed when using AJAX features—ordinary HTTP requests always update whole page.
onClickPreconditionnoPrecondition for deciding whether onclick event should go server side or not. If left unspecified, this is considered to be true.
tabindexnoThis attribute specifies the position of the current element in the tabbing order for the current document. This value must be a number between 0 and 32767.

HTML, Styles and JavaScript

The eventButton tag writes out an HTML <button> closed tag with a default CSS class of "aranea-button".

The eventLinkButton tag writes out an HTML <a> open tag with a default CSS class of "aranea-link-button".

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
  <ui:widgetContext>
    ...
    <ui:eventButton eventId="test" eventParam="${bean.id}"/>
    <ui:eventLinkButton eventId="edit" eventParam="${bean.id}">
      <img src="editButton.png"/>
    </ui:eventLinkButton>
    ...
  </ui:widgetContext>
...

4.5.2. <ui:onLoadEvent>

This tag will register events that are executed when HTML page body has completely loaded. This tag can be used multiple times, all specified events will be added to event queue and executed in order of addition.

Attributes

AttributeRequiredDescription
eventyesEvent to register.

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
    <ui:onLoadEvent event="activateFlashLights();"/>
    <ui:onLoadEvent event="changeMenuBackGroundColor();"/>
...

4.5.3. <ui:registerPopups>

This tag checks presence of server-side session-threads that represent popups and adds system loadevent for opening them in new browser window at client-side. For tag to have an effect, HTML page BODY tag must have attribute onload event set to AraneaPage (See Aranea Clientside Javascript) onload event. Also, this tag only works inside <ui:systemForm> tag.

Attributes

This tag has no attributes.

Examples

<?xml version="1.0" encoding="UTF-8"?>
...
<ui:body>
  <ui:systemForm method="POST">
    <ui:registerPopups/>
  </ui:systemForm>
</ui:body>
...

4.6. HTML entity Tags

HTML entities can be inserted by using the predefined entity tags or using the <ui:entity> for entities that have not been defined by Aranea JSP library.

The entity tag accepts a attribute code which is used as &code; to get the HTML entity.

AttributeRequiredDescription
codenoHTML entity code, e.g. nbsp or #012.
countnoNumber of times to repeat the entity.

4.6.1. Predefined entity tags

The following predefined entities also accept the count attribute. It defines the number of times to repeat the entity.

TagDescription
<ui:acute>HTML &acute; entity.
<ui:copyright>HTML &copyright; entity.
<ui:gt>HTML &gt; entity.
<ui:laquo>HTML &laquo; entity.
<ui:lt>HTML &lt; entity.
<ui:nbsp>HTML &nbsp; entity.
<ui:raquo>HTML &raquo; entity.
<ui:acute>HTML &acute; entity.

4.7. Putting Widgets to Work with JSP

Now we have defined enough JSP tags to render our example widget (see Section 2.7.8, “Putting It All Together”):

<?xml version="1.0" encoding="UTF-8"?>
<jsp:root 
  xmlns:jsp="http://java.sun.com/JSP/Page" 
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:ui="http://araneaframework.org/tag-library/standard" version="1.2">
  <ui:widgetContext>
    <h3>Test widget</h3>
    
    Data field: <c:out value="${viewData.myData.field}"/>
    <ui:eventButton labelId="#Test" eventId="test"/>      
  </ui:widgetContext>
</jsp:root>

We can use just usual JSTL Core library tags to access the widget view data, as long as the <ui:widgetContext> is present via the viewData EL variable.

4.8. Layout Tags

4.8.1. <ui:layout>

Represents a layout. Layouts allow to describe the way content will be placed on the page.

AttributeRequiredApplicable to:
widthnoLayout width.
rowClassesnoDefault style of rows in this layout.
cellClassesnoDefault style of cells in this layout.
styleClassnoCSS class for tag.

Variables

VariableDescriptionType
rowClassProviderProvides row class, usually should not be used from JSP.RowClassProvider
cellClassProviderProvides cell class, usually should not be used from JSP.CellClassProvider

4.8.2. <ui:row>

Represents a row in layout.

AttributeRequiredApplicable to:
heightnoRow height.
cellClassesnoDefault style of cells in this row..
styleClassnoCell css class, defines the way the cell will be rendered.
overrideLayoutnoBoolean that determines whether row's own styleClass completely overrides styleClass provided by surrounding layout (default behaviour), or is appended to layout's styleClass.

Variables

VariableDescriptionType
cellClassProviderProvides cell class, usually should not be used from JSP.CellClassProvider

4.8.3. <ui:cell>

Represents a cell in layout.

AttributeRequiredApplicable to:
heightnoRow height.
widthnoRow width.
colSpannoCell colspan, same as in HTML.
rowSpannoCell rowspan, same as in HTML.
styleClassnoCell css class, defines the way the cell will be rendered.
overrideLayoutnoBoolean that determines whether cells's own styleClass completely overrides styleClass provided by surrounding layout or row (default behaviour), or is appended to layout's or row's styleClass.

Examples

Layouts, rows and cells are used together like this:
<?xml version="1.0" encoding="UTF-8"?>
...
  <ui:layout rowClasses="even,odd" cellClasses="one,two,three,four">
    <ui:row>
      <ui:cell>
         <!-- cell content -->
      </ui:cell>
    </ui:row>
  </ui:layout>
...

4.8.4. <ui:updateRegion>, <ui:updateRegionRow>, and <ui:updateRegionRows>

These three tags define the update regions in the output that can be updated via AJAX requests. The update regions chosen to be updated when some event occurs is decided by tags that take the updateRegion attribute (See Section 5.2.1, “Common attributes for all form element rendering tags.”).

The <ui:updateRegion> should be used when defining updateregion when the region is not contained in HTML table (layout). The <ui:updateRegionRow> is basically a table row (td) and is for updating a table row. The <ui:updateRegionRows> is for defining a region which is an HTML table body, and contains table rows itself. Updating only single cells is not possible due to browser incompatibilities.

AttributeRequiredDescription
id no The id of the region. Will be used to reference the region when POST'ing a form.
globalId no When not using the globalId, the full id will be formed by concatenating the context widget id with the specified id. If for a reason you would want to avoid that, then you specify the id with the globalId attribute.

Either id or globalId attribute is required.

Examples

<?xml version="1.0" encoding="UTF-8"?>
<!-- First update region, placed outside HTML table -->
<ui:updateRegion id="outsideTable">
</ui:updateRegion>

<ui:layout>
  <!-- Second update region, placed inside HTML table -->
  <ui:updateRegionRows id="insideTable">
    <ui:row>
      ...
    </ui:row>
    <!-- Third update region for updating a row, placed inside HTML table -->
    <ui:updateRegionRow id="aRow">
      <ui:cell>...</ui:cell>
      <ui:cell>...</ui:cell>
    </ui:updateRegionRow/>
  </ui:updateRegionRows>
</ui:layout>

<!-- Button that makes a background submit of specified event. 
     When response arrives specified updateregions are updated -->
<ui:eventButton id="test" updateRegions="outsideTable,insideTable"/>

4.9. Presentation Tags

Aranea JSP library contains synonyms for some (deprecated) HTML presentation tags.

4.9.1. <ui:bold>

Acts as the HTML <b> tag.

4.9.2. <ui:italic>

Acts as <i> HTML tag.

4.9.3. <ui:font>

Acts as <font> HTML tag.

AttributeRequiredApplicable to:
face no The font face of the font.
color no The color of the font.

4.9.4. <ui:style>

Sets a CSS class for the tag content, acts as a <span> HTML tag with the class atribute set.

AttributeRequiredApplicable to:
styleClass no CSS class for tag.

4.9.5. <ui:newline>

Puts a visual new line (<br/>).

4.9.6. <ui:tooltip>

Defines tooltip that is shown when web application user hovers mouse over element to which the tooltip is attached.

AttributeRequiredApplicable to:
element yes HTML id of DOM element that is target of the tooltip.
text yes Tooltip content.
options no Options for tooltip (including tooltip classname, title, etc -- see prototip.js for details).

4.9.7. <ui:basicButton>

Represents an HTML form button.

AttributeRequiredApplicable to:
renderMode no Allowed values are (button | input) - the corresponding HTML tag will be used for rendering. Default is button.
id no Button id, allows to access button from JavaScript.
labelId no Id of button label.
onclick no onClick Javascript action.
styleClass no CSS class for button.
style no Inline CSS style for button.

4.9.8. <ui:basicLinkButton>

Represents a link with an onClick JavaScript action.

AttributeRequiredApplicable to:
id no Button id, allows to access button from JavaScript.
styleClass no CSS class for tag.
style no Inline CSS style for tag.
onclick no onClick Javascript action.
labelId no Id of button label.

4.9.9. <ui:link>

Usual HTML link, acts as a <a> HTML tag.

AttributeRequiredApplicable to:
disabledStyleClass no CSS class for disabled link.
id no Link id, allows to access link from JavaScript.
href no Link target URL.
target no Link target, same as <a> HTML tag target attribute.
disabled no Controls whether the link is disabled, disabled link doesn't link anywhere.
styleClass no CSS class for tag.
style no Inline CSS style for tag.

4.10. Programming JSPs without HTML

Aranea standard tag library should mostly be enough to shelter end-users from the need to write HTML inside JSPs. Snippets of HTML are alright but using it too often tends to lead to inflexible UI; instead of embedding HTML in JSPs custom tags should be written if the need arises.

When writing JSPs without embedded HTML, programmers best friends are styleClass attributes of presentation tags, allowing tuning of tag appearances and layout tags.

Layout tags are tags extending BaseLayoutTag. Layout tags allow placing of rows inside them (and rows allow using of cells inside). Standard layout tag (<ui:layout>) outputs HTML table, and standard row and cell tags output HTML tr and td tags, respectively. This is by no means a requirement for layout tags—there are probably ways to achieve the same behaviour with correctly styled HTML div tags; but the tables should do just fine for majority of needs.

4.11. Customizing Tag Styles

Presentation tags (tags extending PresentationTag or implementing StyledTagInterface) have attribute styleClass that specifies the CSS style class used for rendering the tag. When styleClass attribute for tag is not specified, some default style bundled with Aranea is used; or in some cases no HTML class attribute is output at all—allowing cascading styles from some parent (HTML) tag to take over the presentation.

Presentation tags also have style attribute for specifying inline style for tag. Using it is discouraged—tweaking style classes to fit ones specific needs is highly recommended.

Some tags may have more than one attributes for defining tag style. For example <ui:layout> tag and other layout tags that extend LayoutHtmlTag or BaseLayoutTag have attributes rowClasses and cellClasses that specify the default styles for <ui:row> and <ui:cell> tags used within the layout. These can be overriden with row and cell own styleClass attribute.

To actually use new style(s) for some tag one often can just write a new CSS style (i.e. "somestyle { background: #ffc; color: #900; text-decoration: none; }")—apply that and be done with it. For more complicated tags, one may need to take a quick peek at tag source code to see what HTML tags are output and design their styles accordingly. Most of the time that should not be necessary.

Changing default tag styles can be done in two ways—modifying CSS files or extending the tag one wants to customize with dynamic initializer like this:

{
    styleClass = "some-wanted-style";
}

needless to say, first method is very much preferred because creating custom tags just for changing tag styles is quite pointless.

There is also a renderMode attribute; in current tag library there are very few tags supporting this attribute. One of those is ButtonHtmlTag (<ui:basicButton>)—its renderMode should have value "input" or "button" (default) and it specifies whether the button should be rendered in HTML with <input type=button ... > or <button ... > tag. In the future, number of JSP tags having renderMode attribute will probably increase (this can be used to get rid of multiple JSP tags for rendering different types of (multi)selects, inputs and displays).

Attributes defining tag styles

AttributeRequiredApplicable to:
styleInline CSS style applied to tag. Avoid.Presentation tags.
styleClassCSS class applied to tag.Presentation tags.
rowClassCSS class applied to rows inside the tag.Layout tags.
cellClassCSS class applied to cells inside the tag.Layout tags, row tags.
renderModeDefines the renderMode used for rendering the tag.<ui:basicButton>, <ui:eventButton>, <ui:button>.

4.12. Making New JSP Tags

JSP tags are very application specific, need for additional or modified JSP tags arises quite often. Due to presentational nature of HTML and Javascript, extending the tags that really output HTML instead of providing some information to subtags is messy. We look here at some more general tags and contracts that should be followed when writing Aranea JSP tags.

4.12.1. Utilities and base classes

Custom tags should extend at least org.araneaframework.jsp.tag.BaseTag that provides methods for registering subtags, manipulation of pagecontext and attribute evaluation.

import java.io.Writer;
import org.araneaframework.jsp.tag.entity.NbspEntityHtmlTag;
import org.araneaframework.jsp.util.JspUtil;

public class DummyTag extends BaseTag {
  public static String KEY = "org.araneaframework.jsp.tag.DummyTag";
  
  BaseTag subTag;
  
  @Override
  protected int doStartTag(Writer out) throws Exception {
    int result = super.doStartTag(out);

    // make this tag implementation accessible to subtags which 
    // is quite pointless since this tag does not implement any useful interface.
    // it demonstrates Aranea JSP convention for providing info to subtags
    addContextEntry(KEY, this);
    
    // write some real output that ends up at the served web page
    JspUtil.writeOpenStartTag(out, "div");
    JspUtil.writeAttribute(out, "id", "dummyDivId");
    JspUtil.writeCloseStartTag(out);
    
    // it is possible to register in JAVA code too, this one just writes out nbsp entity.
    subTag = new NbspEntityHtmlTag();
    registerSubtag(subTag);
    executeStartSubtag(subTag);
    
    return result;
  }

  @Override
  protected int doEndTag(Writer out) throws Exception {
    executeEndTagAndUnregister(subTag);
    
    JspUtil.writeEndTag(out, "div");
    
    return super.doEndTag(out);
    // Now everything about this tag ceases to exist, 
    // context entries are removed, souls are purged.
  }
}

org.araneaframework.jsp.util.JspUtil that was used here is an utility class containing some functions for writing out (XML) tags with somewhat less room for errors than just out.write(). Other notable methods provided by BaseTag are getOutputData() that returns response data, getConfiguration() and getLocalizationContext(). For tags with attributes, attribute evaluation functions that support Expression Language (EL) expressions are provided in BaseTag. Typical usage of these functions is following:

public void setWidth(String width) throws JspException {
  this.width = (String)evaluate("width", width, String.class);
}

Another common base tag for tags that output real HTML is org.araneaframework.jsp.PresentationTag. The DummyTag should really extend it too, since it outputs some HTML. PresentationTag defines style and styleClass attributes that can be applied to most HTML tags.

Important tag cleanup method is doFinally() that is called after rendering. It should be used to clear references to objects that should no longer be referenced after rendering. As in containers tag instances can live very long time, they can leak quite a lot of memory unless resources are deallocated.

4.12.2. Inheriting tag attributes from base tags.

Custom tags extending Aranea tags are able to accept all supertag attributes, but these must be also defined in TLD, otherwise the JSP containers will complain. As some base tags may be abstract, information about their attributes cannot be deduced from Aranea JSP standard TLD. To address this problem, Aranea distribution does the following: aranea.jar and aranea-jsp.jar include the file META-INF/aranea-standard.tcd (TCD stands for Tag Class Descriptor) which includes the attribute information for all Aranea Standard JSP classes. To make use of this information, one first generates TLD for custom tag classes and then merges the TCD information into it. It is done with org.araneaframework.buildutil.TcdAndTldMerger utility included in aranea.jar (since 1.0.10, previously it had to be compiled separately after downloading distribution). All custom compiled tag classes as well as Aranea JSP tag classes must be available on classpath when using this utility.

Example of using the TcdAndTldMerger utility:

<target name="tld">
  <!-- generate TLD without parent attribute information -->
  <webdoclet destdir="somedir" force="false" >
    <fileset dir="${src.dir}" includes="**/*Tag.java"/>

    <jsptaglib validatexml="true"
      shortName="shortName"
      filename="filename.tld"
      uri="customuri"
      description="description"
    />
  </webdoclet>

  <!-- invoke the TcdAndTldMerger utility -->
  <java classname="org.araneaframework.buildutil.TcdAndTldMerger" fork="true">
    <arg value="META-INF/aranea-standard.tcd"/>    <!-- Tag class descriptor to merge with -->
    <arg value="somedir/filename.tld"/>            <!-- Source TLD -->
    <arg value="somedir/filename.tld"/>            <!-- Destination TLD -->
    <classpath>
    <path refid="araneaclasspath"/>
      <path refid="compiledcustomtagclasses"/>
      <path refid="varia">
    </classpath>
  </java>

</target>

When running given target, one should see messages similar to following:

8 attributes for 'custom.RandomTag' found from 'org.araneaframework.jsp.tag.presentation.PresentationTag'.

4.12.3. Widgets and events

Sending events to widgets is accomplished with javascript submit functions, helpful utility being org.araneaframework.jsp.util.JspUtil and org.araneaframework.jsp.util.JspWidgetCallUtil. First one would construct org.araneaframework.jsp.UiEvent and (in case of HTML element which receives only one event) calls JspUtil.writeEventAttributes(Writer out, UiEvent event) and afterwards writeSubmitScriptForEvent(Writer out, String attributeName).

//public UiEvent(String eventId, String eventTargetWidget, String eventParameter)
UiEvent event = new UiEvent("hello", "contextWidgetId", "name");
// long way to ouput custom attributes version
JspUtil.writeEventAttributes(out, event);
JspWidgetCallUtil.writeSubmitScriptForEvent(out, attributeName);
// short version
JspWidgetCallUtil.writeSubmitScriptForEvent(out, "onclick", event);

// both will output something like this:
    // arn-evntId="hello" 
    // arn-trgtwdgt="contextWidgetId" 
    // arn-evntPar="name" 
    // onclick="return _ap.event(this);"

4.12.4. Layouts

New layouts are mostly concerned with styles or render layouts with some additional tags instead plain table, tr, td. As simple example, we define a layout that applies a class "error" to cells which contain invalid FormElement. Note that approach we use only works when cell tag is aware of the surrounding FormElement at the moment of rendering, meaning that FormElement is rendered in JSP something like this:

<?xml version="1.0" encoding="UTF-8"?>
...
<ui:formElement id="someId">
    <ui:cell>
        <ui:label/>
    </ui:cell>

    <ui:cell>
        <ui:textInput/>
    </ui:cell>
</ui:formElement>
...

What is needed foremost is a decorator for cells that are used inside invalid FormElement.

public class ErrorMarkingCellClassProviderDecorator implements CellClassProvider {
  protected CellClassProvider superProvider;
  protected PageContext pageContext;

  // constructs a decorator for superProvider, makes pageContext accessible
  public ErrorMarkingCellClassProviderDecorator(CellClassProvider superProvider, PageContext pageContext) {
    this.superProvider = superProvider;
    this.pageContext = pageContext;
  }

  public String getCellClass() throws JspException {
    FormElement.ViewModel formElementViewModel = (FormElement.ViewModel)
      pageContext.getAttribute(FormElementTag.VIEW_MODEL_KEY, PageContext.REQUEST_SCOPE);
    // superProvider.getCellClass() may only be called once, otherwise moves on to next cell's style
    String superClass = superProvider.getCellClass();

    if (formElementViewModel != null && !formElementViewModel.isValid()) {
      if (superClass != null)
        return superClass + " error";
      else
        return "error";
    }

    return superClass;
  }
}

Actual layout tag that decorates its cells according to described logic:

public class CustomLayoutTag extends LayoutHtmlTag {
  protected int doStartTag(Writer out) throws Exception {
    int result = super.doStartTag(out);
    addContextEntry(CellClassProvider.KEY, new ErrorMarkingCellClassProviderDecorator(this, pageContext));

    return result;
  }
}