Commits

Anonymous committed 36bfb13 Draft

jmesa upgraded to grails 2.0.4

Comments (0)

Files changed (76)

 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" path="src/java"/>
-	<classpathentry kind="src" path="src/groovy"/>
 	<classpathentry kind="src" path="grails-app/conf"/>
-	<classpathentry kind="src" path="grails-app/controllers"/>
-	<classpathentry kind="src" path="grails-app/domain"/>
-	<classpathentry kind="src" path="grails-app/services"/>
-	<classpathentry kind="src" path="grails-app/taglib"/>
-	<classpathentry kind="src" path="grails-app/utils"/>
-	<classpathentry kind="src" path="test/integration"/>
-	<classpathentry kind="src" path="test/unit"/>
+	<classpathentry kind="src" path="lib"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry exported="true" kind="src" path="/jmesa">
+	<classpathentry kind="src" path=".link_to_grails_plugins/release-1.0.0/src/groovy">
+		<attributes>
+			<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" path=".link_to_grails_plugins/release-1.0.0/src/java">
+		<attributes>
+			<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" path=".link_to_grails_plugins/svn-1.0.1/src/groovy">
 		<attributes>
 			<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
 		</attributes>
 	</classpathentry>
 	<classpathentry kind="con" path="com.springsource.sts.grails.core.CLASSPATH_CONTAINER"/>
-	<classpathentry exported="true" kind="con" path="GROOVY_DSL_SUPPORT"/>
 	<classpathentry kind="output" path="target-eclipse/classes"/>
 </classpath>
 		<link>
 			<name>.link_to_grails_plugins</name>
 			<type>2</type>
-			<locationURI>GRAILS_ROOT/2.0.4/projects/jmesa/plugins</locationURI>
+			<locationURI>GRAILS_ROOT/2.0.4/projects/Jmesa/plugins</locationURI>
 		</link>
 	</linkedResources>
 </projectDescription>

JmesaGrailsPlugin.groovy

 class JmesaGrailsPlugin {
     // the plugin version
-    def version = "0.1"
+    def version = "2.0.4"
     // the version or versions of Grails the plugin is designed for
     def grailsVersion = "2.0 > *"
     // the other plugins this plugin depends on
 
     // TODO Fill in these fields
     def title = "Jmesa Plugin" // Headline display name of the plugin
-    def author = "Your name"
-    def authorEmail = ""
+    def author = "jeff.jie"
+    def authorEmail = "bbmyth@gmail.com"
     def description = '''\
-Brief summary/description of the plugin.
-'''
+         Jmesa plugin is a dynamic html tabular represenration 
+         of data that allows you to filter,sort, paginate, 
+         export and edit your data.'''
 
     // URL to the plugin's documentation
     def documentation = "http://grails.org/plugin/jmesa"
+Jmesa- 2.0.4 
+
+Allows Grails applications to easily integrate  with the functionality .Utilizes Jmesa feature as an underlying
+mechanism so serves managing represenration of data in tabular form ,filter,sort, paginate, export and edit
+your data.I recommend you read the Jmesa documentation before continuing to get a feel for how this plugin 
+operates. 
+
+Concepts
+Sort: Allow sorting feature based on Domain class field name. 
+Paginate: Provide the number of record need to be display.
+Export/Import: Provide Export and Import of data in Pdf and Excel format.
+Filter: Allowing filtering of data based on domain class field name.
+
+
+Demonstration
+To get started a very basic sample application  we need to package the plugin ,install and run the application
+grails package-plugin
+grails install-plugin
+grails run-app 
+
+Installation
+Install the plugin by providing path to local file system where the plugin.zip file is located .
+grails install-plugin /path/to/grails-jmesa-2.0.4.zip
+
+
+Contributing
+All contribution welcome.
+For code changes please ensure you supply working tests and documentation.
+Requests for additional information to go along with this documentation are also welcomed.
+
+Credits
+JmesaGails plugin was written by jeff johnston and upgraded by SigmaInfo Solution.

grails-app/taglib/jmesa/JmesaTagLib.groovy

+package jmesa
+
+import org.jmesa.facade.tag.TagUtils
+import org.jmesa.util.SupportUtils
+
+import org.jmesa.web.WebContext
+import org.jmesa.facade.TableFacadeImpl
+import org.jmesa.facade.TableFacade
+import org.jmesa.view.html.component.HtmlTable
+import org.jmesa.util.ItemUtils
+import org.jmesa.view.html.component.HtmlColumn
+import org.jmesa.view.html.renderer.HtmlCellRenderer
+import org.jmesa.view.html.renderer.HtmlFilterRenderer
+import org.jmesa.view.html.renderer.HtmlHeaderRenderer
+import org.jmesa.web.HttpServletRequestWebContext
+import org.jmesa.view.html.HtmlComponentFactory
+
+/**
+ * author:jeff jie
+ *
+ */
+class JmesaTagLib {
+	static namespace = "jmesa"
+
+	//define some page scope attibute to share data between tags.for the limitation of Gsp tag.
+	def name_tableFacade = "jmesa_tableFacade"
+	def name_var = "jmesa_var"
+
+	//attributes belongs to facade
+	def facade_componentFactory = "facade_componentFacotry"
+	def facade_table = "facade_table"
+	def facade_pageItems = "facade_pageItems"
+
+	//def name_view = "jmesa_view"
+	def row_pageItem = "row_pageItem"
+
+	//tag clouses
+	def tableFacade = { attrs,body ->
+		def tableFacade = createTableFacade(attrs)
+
+		request[facade_pageItems] = []
+
+		Collection pi = tableFacade.coreContext.pageItems
+
+
+		if (pi.size() == 0) {
+			body()
+			request[facade_pageItems]?.clear()
+		} else {
+			pi.each{item ->
+				request[attrs.var] = item
+				body()
+			}
+		}
+
+		flash.remove(attrs.var)
+
+		tableFacade.table = request[facade_table];
+		tableFacade.toolbar = createInstance(attrs.toolbar)
+		tableFacade.view = createInstance(attrs.view)
+		tableFacade.coreContext.pageItems = request[facade_pageItems]
+
+		String html = tableFacade.view.render().toString();
+		out << html
+	}
+
+	def htmlTable = { attrs,body ->
+		if(!request[facade_table])
+			//then create the table
+			createTable(attrs)
+
+		body()
+	}
+
+	def htmlRow = { attrs,body ->
+
+		def var = request[name_var]   //get the var name
+		Object bean = request[var]
+		def pageItem = [(var):bean]
+		pageItem[ItemUtils.JMESA_ITEM] = bean
+		request[facade_pageItems] << pageItem
+		request[row_pageItem] = pageItem
+
+
+		HtmlTable table = request[facade_table]
+		if (table.row == null)
+			table.row = createRow(attrs)
+
+		body()
+	}
+
+	def htmlColumn = { attrs,body ->
+		def pageItems = request[facade_pageItems]
+		if (pageItems.size() == 1) {
+
+			def row = request[facade_table].row
+			def column = createColumn(attrs)
+			validateColumn(attrs.property)
+			row.addColumn column
+		}
+
+		request[row_pageItem][attrs.property] = getValue(attrs,body)
+	}
+
+	def getValue(attrs,body){
+		def name = request[name_var]
+		def value = request[name]
+		if(value){
+			// don't konw how to check out if the body is empty
+			def ret = body((name):value)
+			if (ret == "")
+				ret = ItemUtils.getItemValue(request[request[name_var]],attrs.property)
+			return ret
+		}
+		return null
+	}
+
+	def htmlColumns = { attrs,body ->
+		def pageItems = request[facade_pageItems]
+		def row = request[facade_table].row
+		if (pageItems.size() == 1) {
+			def htmlColumnsGenerator = createInstance(attrs.htmlColumnsGenerator)
+			SupportUtils.setWebContext (htmlColumnsGenerator,request[name_tableFacade].webContext)
+			SupportUtils.setCoreContext (htmlColumnsGenerator,request[name_tableFacade].coreContext)
+			def columns = htmlColumnsGenerator.getColumns(request[facade_componentFactory])
+			columns.each{
+				it.generatedOnTheFly = true
+				validateColumn(it.property)
+				row.addColumn it
+			}
+		}
+
+		def pageItem = request[row_pageItem]
+		if(pageItem.bean){
+			def columns = row.getColumns()
+			columns.each{
+				if (it.isGeneratedOnTheFly()){
+					if(it.property){
+						pageItem[it.property] = ItemUtils.getItemValue(request[request[name_var]],it.property)
+					}
+				}
+			}
+		}
+	}
+
+	//methods
+
+	def validateColumn(property){
+		if (property == null) {
+			return true // no coflicts
+		}
+
+		def pageItem = request[row_pageItem]
+		if (pageItem[property] != null) {
+			String msg = "The column property ${property} is not unique. One column value will overwrite another."
+			throw new IllegalStateException(msg)
+		}
+
+		if (request[name_var].equals(property)) {
+			String msg = "The column property ${property} is the same as the TableFacadeTag var attribute ${request[name_var]}."
+			throw new IllegalStateException(msg)
+		}
+
+		return true
+	}
+
+	def createTableFacade(attrs){
+		WebContext webContext = new HttpServletRequestWebContext(request)
+		TableFacade tableFacade = new TableFacadeImpl(attrs.id,null)
+
+		tableFacade.webContext = webContext
+		tableFacade.editable = attrs.editable == null ? false : attrs.editable.toBoolean()
+		tableFacade.items = attrs.items
+		tableFacade.maxRows = attrs.maxRows?.toInteger()
+		tableFacade.stateAttr = attrs.stateAttr
+		tableFacade.limit = attrs.limit
+		//tableFacade.var = attrs.var
+		request[name_var] = attrs.var
+
+		tableFacade.maxRowsIncrements = TagUtils.getTableFacadeMaxRowIncrements(attrs.maxRowsIncrements)
+		tableFacade.setExportTypes(null, TagUtils.getTableFacadeExportTypes(attrs.exportTypes))
+
+		tableFacade.autoFilterAndSort(attrs.autoFilterAndSort == null ? false : attrs.autoFilterAndSort.toBoolean())
+		tableFacade.preferences = createInstance(attrs.preferences)
+		tableFacade.messages = createInstance(attrs.messages)
+		tableFacade.columnSort = createInstance(attrs.columnSort)
+		tableFacade.rowFilter = createInstance(attrs.rowFilter)
+
+		tableFacade.addFilterMatcherMap(createInstance(attrs.filterMatcherMap))
+
+		def factory = new HtmlComponentFactory(tableFacade.webContext, tableFacade.coreContext)
+		request[facade_componentFactory] = factory
+		request[name_tableFacade] = tableFacade
+	}
+
+	def createTable(attrs){
+		def factory = request[facade_componentFactory]
+		HtmlTable table = factory.createTable()
+		table.caption = attrs.caption
+		table.captionKey = attrs.captionKey
+		table.theme = attrs.theme
+
+		if(attrs.tableRenderer)
+			table.tableRenderer = createInstance(attrs.tableRenderer)
+		def tableRenderer = table.tableRenderer
+
+		tableRenderer.width = attrs.width
+		tableRenderer.style = attrs.style
+		tableRenderer.styleClass = attrs.styleClass
+		tableRenderer.border = attrs.border
+		tableRenderer.cellpadding = attrs.cellpadding
+		tableRenderer.cellspacing = attrs.cellspacing
+
+		request[facade_table] = table
+	}
+
+
+	def createRow(attrs){
+		def factory = request[facade_componentFactory]
+		def row = factory.createRow();
+		row.uniqueProperty = attrs.uniqueProperty
+		row.highlighter = attrs.highlighter == null ? false : attrs.highlighter.toBoolean()
+
+
+		if(attrs.onclick)
+			row.onclick = createInstance(attrs.onclick)
+		if(attrs.onmouseover)
+			row.onmouseover = createInstance(attrs.onmouseover)
+		if(attrs.onmouseout)
+			row.onmouseout = createInstance(attrs.onmouseout)
+		if(attrs.rowRenderer)
+			row.rowRenderer = createInstance(attrs.rowRenderer)
+		def rowRenderer = row.rowRenderer
+
+		rowRenderer.style = attrs.style
+		rowRenderer.styleClass = attrs.styleClass
+		rowRenderer.evenClass = attrs.evenClass
+		rowRenderer.oddClass = attrs.oddClass
+		rowRenderer.highlightStyle = attrs.highlightStyle
+		return row
+	}
+
+
+	def createColumn(attrs){
+		def factory = request[facade_componentFactory]
+		HtmlColumn column = factory.createColumn(attrs.property)
+		column.title = attrs.title
+		column.titleKey = attrs.titleKey
+		//column.sortable = attrs.sortable != null
+		column.sortable = attrs.sortable == null ? false : attrs.sortable.toBoolean()
+
+		column.sortOrder = TagUtils.getColumnSortOrder(attrs.sortOrder);
+		column.filterable = attrs.filterable == null ? false : attrs.filterable.toBoolean()
+		column.editable = attrs.editable == null ? false : attrs.editable.toBoolean()
+		column.width = attrs.width
+
+		if(attrs.cellRenderer){
+			HtmlCellRenderer renderer =  createInstance(attrs.cellRenderer)
+			renderer.cellEditor = column.cellRenderer.cellEditor
+			column.cellRenderer = renderer
+
+		}
+		HtmlCellRenderer cr = column.cellRenderer
+		cr.style = attrs.style
+		cr.styleClass = attrs.styleClass
+
+		// worksheet
+
+		if(attrs.worksheetEditor){
+			cr.worksheetEditor = createInstance(cr.worksheetEditor)
+		}
+
+		// cell
+
+		if(attrs.cellEditor){
+			cr.cellEditor = createInstance(attrs.cellEditor)
+			SupportUtils.setPattern(cr.cellEditor, attrs.pattern)
+		}
+
+		// filter
+
+		if(attrs.filterRenderer){
+			HtmlFilterRenderer renderer = createInstance(attrs.filterRenderer)
+			renderer.filterEditor = column.filterRenderer.filterEditor
+			column.filterRenderer = renderer
+		}
+		HtmlFilterRenderer fr = column.filterRenderer
+		fr.style = attrs.filterStyle
+		fr.styleClass = attrs.filterClass
+
+		if(attrs.filterEditor){
+			fr.filterEditor = createInstance(attrs.filterEditor)
+		}
+
+		// header
+
+		if(attrs.headerRenderer){
+			HtmlHeaderRenderer renderer = createInstance(attrs.headerRenderer)
+			renderer.headerEditor = column.headerRenderer.headerEditor
+			column.headerRenderer = renderer
+		}
+		HtmlHeaderRenderer hr = column.headerRenderer
+		hr.style = attrs.headerStyle
+		hr.styleClass = attrs.headerClass
+
+		if(attrs.headerEditor){
+			hr.headerEditor = createInstance(attrs.headerEditor)
+		}
+
+		return column;
+	}
+
+	def createInstance(cls){
+		if(cls){
+			def loader = this.class.classLoader
+			return Class.forName(cls,true,loader).newInstance()
+		}
+		return null
+	}
+}

grails-jmesa-2.0.4.zip

Binary file added.

lib/jmesa.jar

Binary file added.
+drop the following jar files here.
+I remove the common jar file between grails and jmesa. at least,remove the groovy lib and Spring lib.
+---------------------------------
+jmesa.jar
+core-renderer-R8prel.jar
+itext-paulo-155.jar
+jcl104-over-slf4j-1.4.3.jar
+jexcel-2.6.6.jar
+poi-3.0-FINAL.jar
+slf4j-pi-1.4.3.jar
+slf4j-log4j12-1.4.3.jar
+tagsoup.-1.1.3.jar
+
+<plugin name='jmesa' version='2.0.4' grailsVersion='2.0 &gt; *'>
+  <author>jeff.jie</author>
+  <authorEmail>bbmyth@gmail.com</authorEmail>
+  <title>Jmesa Plugin</title>
+  <description>         Jmesa plugin is a dynamic html tabular represenration 
+         of data that allows you to filter,sort, paginate, 
+         export and edit your data.</description>
+  <documentation>http://grails.org/plugin/jmesa</documentation>
+  <type>JmesaGrailsPlugin</type>
+  <resources>
+    <resource>jmesa.JmesaTagLib</resource>
+  </resources>
+  <repositories>
+    <repository name='grailsCentral' url='http://plugins.grails.org' />
+    <repository name='http://repo.grails.org/grails/plugins' url='http://repo.grails.org/grails/plugins/' />
+    <repository name='http://repo.grails.org/grails/core' url='http://repo.grails.org/grails/core/' />
+    <repository name='grailsCore' url='http://svn.codehaus.org/grails/trunk/grails-plugins' />
+    <repository name='mavenCentral' url='http://repo1.maven.org/maven2/' />
+  </repositories>
+  <dependencies />
+  <plugins />
+  <runtimePluginRequirements />
+  <behavior />
+</plugin>

src/templates/jmesa.properties

+limit.rowSelect.maxRows=15
+
+html.table.component.theme=jmesa
+html.table.renderer.styleClass=table
+
+html.row.renderer.highlightClass=highlight
+html.row.renderer.evenClass=even
+html.row.renderer.oddClass=odd
+
+html.column.header.renderer.image.sortAsc=sortAsc.gif
+html.column.header.renderer.image.sortDesc=sortDesc.gif
+html.column.header.renderer.element=td
+html.column.filter.renderer.image.droplistHandle=droplistHandle.gif
+
+html.tbodyClass=tbody
+html.titleClass=title
+html.filterClass=filter
+html.headerClass=header
+html.toolbarClass=toolbar
+html.statusBarClass=statusBar
+html.imagesPath=/plugins/jmesa-${version}/images/table/
+html.rowcount.includePagination=false
+
+html.toolbar.maxRowsDroplist.increments=15,50,100
+html.toolbar.maxPageNumbers=5
+html.toolbar.pageNumberClass=pageNumber
+
+html.toolbar.image.csv=csv.gif
+html.toolbar.image.pdf=pdf.gif
+html.toolbar.image.excel=excel.gif
+html.toolbar.image.jexcel=excel.gif
+html.toolbar.image.clear=clear.gif
+html.toolbar.image.firstPage=firstPage.gif
+html.toolbar.image.firstPageDisabled=firstPageDisabled.gif
+html.toolbar.image.lastPage=lastPage.gif
+html.toolbar.image.lastPageDisabled=lastPageDisabled.gif
+html.toolbar.image.nextPage=nextPage.gif
+html.toolbar.image.nextPageDisabled=nextPageDisabled.gif
+html.toolbar.image.prevPage=prevPage.gif
+html.toolbar.image.prevPageDisabled=prevPageDisabled.gif
+html.toolbar.image.filter=filter.gif
+html.toolbar.image.separator=separator.gif
+html.toolbar.image.saveWorksheet=saveWorksheet.gif
+html.toolbar.image.saveWorksheetDisabled=saveWorksheetDisabled.gif
+html.toolbar.image.filterWorksheet=filterWorksheet.gif
+html.toolbar.image.filterWorksheetDisabled=filterWorksheetDisabled.gif
+
+html.snippets.initJavascriptLimit.useDocumentReady=false
+
+pdf.cssLocation=/plugins/jmesa-${version}/css/jmesa-pdf.css
+pdf.doctype=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

web-app/WEB-INF/tld/c.tld

+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 core library</description>
+  <display-name>JSTL core</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>c</short-name>
+  <uri>http://java.sun.com/jsp/jstl/core</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlCoreTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Catches any Throwable that occurs in its body and optionally
+        exposes it.
+    </description>
+    <name>catch</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+exception thrown from a nested action. The type of the
+scoped variable is the type of the exception thrown.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Simple conditional tag that establishes a context for
+	mutually exclusive conditional operations, marked by
+	&lt;when&gt; and &lt;otherwise&gt;
+    </description>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+	Simple conditional tag, which evalutes its body if the
+	supplied condition is true and optionally exposes a Boolean
+	scripting variable representing the evaluation of this condition
+    </description>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that determines whether or
+not the body content should be processed.
+        </description>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resulting value of the test condition. The type
+of the scoped variable is Boolean.        
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Retrieves an absolute or relative URL and exposes its contents
+        to either the page, a String in 'var', or a Reader in 'varReader'.
+    </description>
+    <name>import</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ImportTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The URL of the resource to import.
+        </description>
+        <name>url</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is Reader.
+        </description>
+        <name>varReader</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when accessing a relative
+URL resource that belongs to a foreign
+context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Character encoding of the content at the input
+resource.
+        </description>
+        <name>charEncoding</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	The basic iteration tag, accepting many different
+        collection types and supporting subsetting and other
+        functionality
+    </description>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ForEachTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Collection of items to iterate over.
+        </description>
+	<name>items</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.Object</type>
+    </attribute>
+    <attribute>
+        <description>
+If items specified:
+Iteration begins at the item located at the
+specified index. First item of the collection has
+index 0.
+If items not specified:
+Iteration begins with index set at the value
+specified.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+If items specified:
+Iteration ends at the item located at the
+specified index (inclusive).
+If items not specified:
+Iteration ends when index reaches the value
+specified.
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step items of
+the collection, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility. Its type depends
+on the object of the underlying collection.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of type
+javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested
+visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Iterates over tokens, separated by the supplied delimeters
+    </description>
+    <name>forTokens</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+String of tokens to iterate over.
+        </description>
+	<name>items</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+        <description>
+The set of delimiters (the characters that
+separate the tokens in the string).
+        </description>
+	<name>delims</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration begins at the token located at the
+specified index. First token has index 0.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration ends at the token located at the
+specified index (inclusive).
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step tokens
+of the string, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of
+type
+javax.servlet.jsp.jstl.core.LoopTag
+Status. This scoped variable has nested
+visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Like &lt;%= ... &gt;, but for expressions.
+    </description> 
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Expression to be evaluated.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Default value if the resulting value is null.
+        </description>
+        <name>default</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Determines whether characters &lt;,&gt;,&amp;,'," in the
+resulting string should be converted to their
+corresponding character entity codes. Default value is
+true.
+        </description>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+
+  <tag>
+    <description>
+        Subtag of &lt;choose&gt; that follows &lt;when&gt; tags
+        and runs only if all of the prior conditions evaluated to
+        'false'
+    </description>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+        Adds a parameter to a containing 'import' tag's URL.
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the query string parameter.
+        </description>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Value of the parameter.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Redirects to a new URL.
+    </description>
+    <name>redirect</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.RedirectTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The URL of the resource to redirect to.
+        </description>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when redirecting to a relative URL
+resource that belongs to a foreign context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Removes a scoped variable (from a particular scope, if specified).
+    </description>
+    <name>remove</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of the scoped variable to be removed.
+        </description>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+ <tag>
+    <description>
+        Sets the result of an expression evaluation in a 'scope'
+    </description>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable to hold the value
+specified in the action. The type of the scoped variable is
+whatever type the value expression evaluates to.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Expression to be evaluated.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Target object whose property will be set. Must evaluate to
+a JavaBeans object with setter property property, or to a
+java.util.Map object.
+        </description>
+        <name>target</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the property to be set in the target object.
+        </description>
+        <name>property</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Creates a URL with optional query parameters.
+    </description>
+    <name>url</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.UrlTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+processed url. The type of the scoped variable is
+String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+URL to be processed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when specifying a relative URL
+resource that belongs to a foreign context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Subtag of &lt;choose&gt; that includes its body if its
+	condition evalutes to 'true'
+    </description>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that determines whether or not the
+body content should be processed.
+        </description>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+  </tag>
+
+</taglib>

web-app/WEB-INF/tld/fmt.tld

+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 i18n-capable formatting library</description>
+  <display-name>JSTL fmt</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>fmt</short-name>
+  <uri>http://java.sun.com/jsp/jstl/fmt</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlFmtTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Sets the request character encoding
+    </description>
+    <name>requestEncoding</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of character encoding to be applied when
+decoding request parameters.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Stores the given locale in the locale configuration variable
+    </description>
+    <name>setLocale</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+A String value is interpreted as the
+printable representation of a locale, which
+must contain a two-letter (lower-case)
+language code (as defined by ISO-639),
+and may contain a two-letter (upper-case)
+country code (as defined by ISO-3166).
+Language and country codes must be
+separated by hyphen (-) or underscore
+(_).        
+	</description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Vendor- or browser-specific variant.
+See the java.util.Locale javadocs for
+more information on variants.
+        </description>
+        <name>variant</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of the locale configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Specifies the time zone for any time formatting or parsing actions
+        nested in its body
+    </description>
+    <name>timeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See
+java.util.TimeZone for more information on
+supported time zone formats.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Stores the given time zone in the time zone configuration variable
+    </description>
+    <name>setTimeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See java.util.TimeZone for
+more information on supported time zone
+formats.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the time zone of type
+java.util.TimeZone.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var or the time zone configuration
+variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Loads a resource bundle to be used by its tag body
+    </description>
+    <name>bundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.BundleTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+        </description>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Prefix to be prepended to the value of the message
+key of any nested &lt;fmt:message&gt; action.
+        </description>
+        <name>prefix</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Loads a resource bundle and stores it in the named scoped variable or
+        the bundle configuration variable
+    </description>
+    <name>setBundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+        </description>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which stores
+the i18n localization context of type
+javax.servlet.jsp.jstl.fmt.LocalizationC
+ontext.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var or the localization context
+configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Maps key to localized message and performs parametric replacement
+    </description>
+    <name>message</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.MessageTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Message key to be looked up.
+        </description>
+        <name>key</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Localization context in whose resource
+bundle the message key is looked up.
+        </description>
+        <name>bundle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+which stores the localized message.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Supplies an argument for parametric replacement to a containing
+        &lt;message&gt; tag
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Argument used for parametric replacement.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Formats a numeric value as a number, currency, or percentage
+    </description>
+    <name>formatNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Numeric value to be formatted.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the value is to be
+formatted as number, currency, or
+percentage.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+ISO 4217 currency code. Applied only
+when formatting currencies (i.e. if type is
+equal to "currency"); ignored otherwise.
+        </description>
+        <name>currencyCode</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Currency symbol. Applied only when
+formatting currencies (i.e. if type is equal
+to "currency"); ignored otherwise.
+        </description>
+        <name>currencySymbol</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the formatted output
+will contain any grouping separators.
+        </description>
+        <name>groupingUsed</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Maximum number of digits in the integer
+portion of the formatted output.
+        </description>
+        <name>maxIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Minimum number of digits in the integer
+portion of the formatted output.
+        </description>
+        <name>minIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Maximum number of digits in the
+fractional portion of the formatted output.
+        </description>
+        <name>maxFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Minimum number of digits in the
+fractional portion of the formatted output.
+        </description>
+        <name>minFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+which stores the formatted result as a
+String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Parses the string representation of a number, currency, or percentage
+    </description>
+    <name>parseNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+String to be parsed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the string in the value
+attribute should be parsed as a number,
+currency, or percentage.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern that determines
+how the string in the value attribute is to be
+parsed.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Locale whose default formatting pattern (for
+numbers, currencies, or percentages,
+respectively) is to be used during the parse
+operation, or to which the pattern specified
+via the pattern attribute (if present) is
+applied.
+        </description>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether just the integer portion of
+the given value should be parsed.
+        </description>
+        <name>integerOnly</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the parsed result (of type
+java.lang.Number).
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Formats a date and/or time using the supplied styles and pattern
+    </description>
+    <name>formatDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Date and/or time to be formatted.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the time, the date, or both
+the time and date components of the given
+date are to be formatted. 
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for dates. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a date or both a date and
+time (i.e. if type is missing or is equal to
+"date" or "both"); ignored otherwise.
+        </description>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for times. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a time or both a date and
+time (i.e. if type is equal to "time" or "both");
+ignored otherwise.
+        </description>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting style for dates and times.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Time zone in which to represent the formatted
+time.
+        </description>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the formatted result as a String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Parses the string representation of a date and/or time
+    </description>
+    <name>parseDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Date string to be parsed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the date string in the
+value attribute is supposed to contain a
+time, a date, or both.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for days
+which determines how the date
+component of the date string is to be
+parsed. Applied only when formatting a
+date or both a date and time (i.e. if type
+is missing or is equal to "date" or "both");
+ignored otherwise.
+        </description>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting styles for times
+which determines how the time
+component in the date string is to be
+parsed. Applied only when formatting a
+time or both a date and time (i.e. if type
+is equal to "time" or "both"); ignored
+otherwise.
+        </description>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern which
+determines how the date string is to be
+parsed.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Time zone in which to interpret any time
+information in the date string.
+        </description>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Locale whose predefined formatting styles
+for dates and times are to be used during
+the parse operation, or to which the
+pattern specified via the pattern
+attribute (if present) is applied.
+        </description>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable in
+which the parsing result (of type
+java.util.Date) is stored.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>

web-app/css/jmesa-pdf.css

+@page { 
+	size: 11in 8.5in;
+	margin: 0.25in;
+	border: 1px solid silver;
+	padding-top: 5px;
+}	
+
+.jmesa {
+	margin: 0;
+	padding: 0;
+}
+
+.jmesa caption {
+	caption-side: top;
+	color: #444444;
+	font-weight: bold;
+	font-size: 1em;
+	text-align: left;
+	padding-left: 5px;
+}
+
+.jmesa .table {
+	width: 100%;
+	border: none;
+	-fs-table-paginate: paginate;
+	padding: 2px;
+}
+
+.jmesa .header td {
+	white-space: nowrap;
+    background-color: #729fcf;
+    color: white;
+    font-size: 11px;
+    font-weight: bold;
+    padding: 4px 3px 4px 3px;
+    border-right-style: solid;
+    border-right-width: 1px;
+    border-color: white;
+}
+
+.jmesa .odd a, .jmesa .even a {
+	color: black;
+}
+
+.jmesa .odd td, .jmesa .even td {
+    font-family: verdana, arial, helvetica, sans-serif;
+	font-size: 11px;
+    padding: 2px 3px 2px 3px;
+}
+
+.jmesa .odd {
+	background-color: #ffffff;
+}
+
+.jmesa .even {
+	background-color: #e3e3e3;
+}
+
+.jmesa .statusBar td {
+    font-family: verdana, arial, helvetica, sans-serif;
+	font-size: 11px;
+    border-top: 1px solid silver;
+    background-color: #efebe7;
+    padding: 2px;
+}
+

web-app/css/jmesa.css

+.jmesa {
+    margin: 0;
+    padding: 0;
+}
+
+.jmesa caption {
+    caption-side: top;
+    color: #444444;
+    font-weight: bold;
+    font-size: 1em;
+    text-align: left;
+    padding-left: 5px;
+}
+
+.jmesa .table {
+    border: 1px solid silver;
+    padding: 2px;
+}
+
+.toolbar table {
+    margin-right: auto;
+    margin-left: 0px;
+}
+
+.jmesa .toolbar td {
+    padding: 0px 1px 0px 1px;
+}
+
+.jmesa .toolbar select {
+    font-size: 11px;
+    border: solid 1px #c4c3c2;
+}
+
+.jmesa .toolbar .pageNumber {
+    font-size: 13px;
+    font-weight: bold;
+    color: #c4634d;
+}
+
+.jmesa .toolbar .pageNumber a {
+    font-size: 13px;
+    font-weight: normal;
+    color: black;
+}
+
+.jmesa .toolbar img {
+    border:0px;
+}
+
+.jmesa .filter td {
+    padding: 2px 2px 3px 2px;
+}
+
+.jmesa .tbody input {
+    padding: 0;
+    margin: 0;
+}
+
+.jmesa .filter .dynFilter {
+    position: relative;
+    font-family: verdana, arial, helvetica, sans-serif;
+    font-size: 11px;
+    padding: 0;
+    margin: 0;
+    border: 1px solid #c0c0c0;
+    background-color: #efebe7;
+    height: 15px;
+    white-space: nowrap;
+    cursor: pointer;
+}
+
+.jmesa .filter #dynFilterDiv {
+    position: absolute;
+    top: -3px;
+    left: -2px;
+    padding: 0;
+    margin: 0;
+    height: 17px;
+    border: 1px solid #c0c0c0;
+    background-color: #e1ebf4;
+}
+
+.jmesa .filter #dynFilterInput {
+    font-family: verdana, arial, helvetica, sans-serif;
+    font-size: 12px;
+    padding: 0;
+    margin: 0;
+    border-style: none;
+    background-color: #e1ebf4;
+}
+
+.jmesa .filter #dynFilterDroplistDiv {
+    position: absolute;
+    top: -2px;
+    left: -2px;
+    padding: 0;
+    margin: 0;
+    height: 17px;
+    background-color: #e1ebf4;
+    z-index: 2;
+}
+
+.jmesa .filter #dynFilterDroplist {
+    font-family: verdana, arial, helvetica, sans-serif;
+    font-size: 12px;
+    padding: 0;
+    margin: 0;
+    border: 1px solid #c0c0c0;
+    background-color: #e1ebf4;
+}
+
+.jmesa .header td {
+    white-space: nowrap;
+    background-color: #729fcf;
+    color: white;
+    font-size: 11px;
+    font-weight: bold;
+    padding: 4px 3px 4px 3px;
+    border-right-style: solid;
+    border-right-width: 1px;
+    border-color: white;
+}
+
+.jmesa .odd a,.jmesa .even a {
+    color: black;
+}
+
+.jmesa .odd td,.jmesa .even td {
+    font-family: verdana, arial, helvetica, sans-serif;
+    font-size: 11px;
+    padding: 2px 3px 2px 3px;
+}
+
+.jmesa .odd td {
+    border: 1px solid #ffffff;
+}
+
+.jmesa .even td {
+    border: 1px solid #e3e3e3;
+}
+
+.jmesa .odd {
+    background-color: #ffffff;
+}
+
+.jmesa .even {
+    background-color: #e3e3e3;
+}
+
+.jmesa .highlight td {
+    font-family: verdana, arial, helvetica, sans-serif;
+    font-size: 11px;
+    padding: 3px 4px 3px 4px;
+    background-color: #fdecae;
+}
+
+.jmesa .highlight a {
+    color: black;
+}
+
+.jmesa .statusBar td {
+    font-family: verdana, arial, helvetica, sans-serif;
+    font-size: 11px;
+    border-top: 1px solid silver;
+    background-color: #efebe7;
+    padding: 2px;
+}
+
+.jmesa .dropShadow {
+    padding: 10px 14px 14px 10px;
+}
+