全部もりもり書いてSeamカスタムタグをつくる

繰り返し系のタグで、「リストの中から1つ前の値が欲しい」時があるわけです。

1つ前の値と比較して、違っていたらxxする…とか。

福岡県
 北九州市
name age sex
taro 40 MAN
jiro 35 MAN
 福岡市
name age sex
hana 20 WOMAN
大分県
 別府市
name age sex
aiko 18 WOMAN

これをSeamで出力しようとすると、dataListやdataTable等の繰り返しタグを入れ子にして、
この例だと3段階の入れ子?にしないといけません。
リストの1つ前の値が取れれば、入れ子にせずにdataList1つだけで
できるのになぁ。
というわけでつくってみました。

こんな感じのタグです。

<rich:dataList2 var="u" preVar="p" value="#{users}">
  <s:div rendered="ここにEL式でuとpを使って比較"></s:div></rich:dataList2>

preVar属性に、前回(1繰り返し前)にvar属性で指定されたオブジェクトが入ります。

以下が、拡張タグのコードになります。


org.richfaces.component.html.HtmlDataList2

package org.richfaces.component.html;

import java.util.Iterator;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.model.DataModel;
import org.richfaces.component.UIDataList;

/**
 * @author tagawaman
 *
 */
@SuppressWarnings("all")
public class HtmlDataList2 extends UIDataList {

	private String _title;
	private String _rowClasses;
	private String _footerClass;
	private String _dir;
	private String _styleClass;
	private String _style;
	private String _lang;
	private String _type;
	private String _columnClasses;
	private String _headerClass;
	private String _preVar;
	public static final String COMPONENT_TYPE = "org.richfaces.DataList2";
	public static final String COMPONENT_FAMILY = "org.richfaces.DataList2";

	public HtmlDataList2() {
		_title = null;
		_rowClasses = null;
		_footerClass = null;
		_dir = null;
		_styleClass = null;
		_style = null;
		_lang = null;
		_type = null;
		_columnClasses = null;
		_headerClass = null;
		_preVar = null;
		setRendererType("org.richfaces.DataList2Renderer");
	}

	public void setTitle(String __title) {
		_title = __title;
	}

	public String getTitle() {
		if (null != _title)
			return _title;
		ValueBinding vb = getValueBinding("title");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setRowClasses(String __rowClasses) {
		_rowClasses = __rowClasses;
	}

	public String getRowClasses() {
		if (null != _rowClasses)
			return _rowClasses;
		ValueBinding vb = getValueBinding("rowClasses");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setFooterClass(String __footerClass) {
		_footerClass = __footerClass;
	}

	public String getFooterClass() {
		if (null != _footerClass)
			return _footerClass;
		ValueBinding vb = getValueBinding("footerClass");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setDir(String __dir) {
		_dir = __dir;
	}

	public String getDir() {
		if (null != _dir)
			return _dir;
		ValueBinding vb = getValueBinding("dir");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setStyleClass(String __styleClass) {
		_styleClass = __styleClass;
	}

	public String getStyleClass() {
		if (null != _styleClass)
			return _styleClass;
		ValueBinding vb = getValueBinding("styleClass");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setStyle(String __style) {
		_style = __style;
	}

	public String getStyle() {
		if (null != _style)
			return _style;
		ValueBinding vb = getValueBinding("style");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setLang(String __lang) {
		_lang = __lang;
	}

	public String getLang() {
		if (null != _lang)
			return _lang;
		ValueBinding vb = getValueBinding("lang");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setType(String __type) {
		_type = __type;
	}

	public String getType() {
		if (null != _type)
			return _type;
		ValueBinding vb = getValueBinding("type");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setColumnClasses(String __columnClasses) {
		_columnClasses = __columnClasses;
	}

	public String getColumnClasses() {
		if (null != _columnClasses)
			return _columnClasses;
		ValueBinding vb = getValueBinding("columnClasses");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setHeaderClass(String __headerClass) {
		_headerClass = __headerClass;
	}

	public String getHeaderClass() {
		if (null != _headerClass)
			return _headerClass;
		ValueBinding vb = getValueBinding("headerClass");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	public void setPreVar(String __preVal) {
		_preVar = __preVal;
	}

	public String getPreVar() {
		if (null != _preVar)
			return _preVar;
		ValueBinding vb = getValueBinding("preVar");
		if (null != vb)
			return (String) vb.getValue(getFacesContext());
		else
			return null;
	}

	protected void setupVariable(FacesContext faces, DataModel localModel,
			boolean rowSelected) {
		Map attrs = faces.getExternalContext().getRequestMap();
		if (rowSelected && isRowAvailable()) {
			setupVariable(getPreVar(), attrs, getNowVariable(getVar(), attrs));
			setupVariable(getVar(), attrs, localModel.getRowData());
			setupVariable(getStateVar(), attrs, getComponentState());
			setupVariable(getRowKeyVar(), attrs, getRowKey());
		} else {
			removeVariable(getPreVar(), attrs);
			removeVariable(getVar(), attrs);
			removeVariable(getStateVar(), attrs);
			removeVariable(getRowKeyVar(), attrs);
		}
	}

	private Object getNowVariable(String var, Map attrs) {
		return var != null ? attrs.get(var) : null;
	}

	private void setupVariable(String var, Map attrs, Object rowData) {
		if (var != null)
			attrs.put(var, rowData);
	}

	private void removeVariable(String var, Map attrs) {
		if (var != null)
			attrs.remove(var);
	}

	public Object saveState(FacesContext context) {
		Object values[] = new Object[12];
		values[0] = super.saveState(context);
		values[1] = _title;
		values[2] = _rowClasses;
		values[3] = _footerClass;
		values[4] = _dir;
		values[5] = _styleClass;
		values[6] = _style;
		values[7] = _lang;
		values[8] = _type;
		values[9] = _columnClasses;
		values[10] = _headerClass;
		values[11] = _preVar;
		return ((Object) (values));
	}

	public void restoreState(FacesContext context, Object state) {
		Object values[] = (Object[]) (Object[]) state;
		super.restoreState(context, values[0]);
		_title = (String) values[1];
		_rowClasses = (String) values[2];
		_footerClass = (String) values[3];
		_dir = (String) values[4];
		_styleClass = (String) values[5];
		_style = (String) values[6];
		_lang = (String) values[7];
		_type = (String) values[8];
		_columnClasses = (String) values[9];
		_headerClass = (String) values[10];
		_preVar = (String) values[11];
	}

	public String getFamily() {
		return "org.richfaces.DataList2";
	}
}

org.richfaces.renderkit.html.DataList2Renderer

package org.richfaces.renderkit.html;

import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.ajax4jsf.renderkit.*;
import org.richfaces.component.UIDataList;
import org.richfaces.renderkit.AbstractListRenderer;

/**
 * @author tagawaman
 * 
 */
public class DataList2Renderer extends AbstractListRenderer {

	public DataList2Renderer() {
	}

	private String convertToString(Object obj) {
		return obj != null ? obj.toString() : "";
	}

	private String convertToString(boolean b) {
		return String.valueOf(b);
	}

	private String convertToString(int b) {
		return b == -2147483648 ? "" : String.valueOf(b);
	}

	private String convertToString(long b) {
		return b == -9223372036854775808L ? "" : String.valueOf(b);
	}

	protected Class getComponentClass() {
		return org.richfaces.component.UIDataList.class;
	}

	public void doEncodeBegin(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {
		ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component);
		doEncodeBegin(writer, context, (UIDataList) component, variables);
	}

	public void doEncodeBegin(ResponseWriter writer, FacesContext context, UIDataList component, ComponentVariables variables)
			throws IOException {
		String clientId = component.getClientId(context);
		writer.startElement("ul", component);
		getUtils().writeAttribute(writer,"class","dr-list rich-datalist "
						+ convertToString(component.getAttributes().get("styleClass")));
		getUtils().writeAttribute(writer, "id", clientId);
		getUtils().writeAttribute(writer, "type", component.getAttributes().get("type"));
		getUtils().encodeAttributesFromArray(context, component,
				new String[] { "dir", "lang", "onclick", "ondblclick",
						"onkeydown", "onkeypress", "onkeyup", "onmousedown",
						"onmousemove", "onmouseout", "onmouseover",
						"onmouseup", "style", "title", "xml:lang" });
	}

	public void doEncodeChildren(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {
		ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component);
		doEncodeChildren(writer, context, (UIDataList) component, variables);
	}

	public void doEncodeChildren(ResponseWriter writer, FacesContext context, UIDataList component, ComponentVariables variables)
			throws IOException {
		encodeRows(context, component);
	}

	public boolean getRendersChildren() {
		return true;
	}

	public void doEncodeEnd(ResponseWriter writer, FacesContext context, UIDataList component, ComponentVariables variables)
			throws IOException {
		writer.endElement("ul");
	}

	public void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {
		ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component);
		doEncodeEnd(writer, context, (UIDataList) component, variables);
		ComponentsVariableResolver.removeVariables(this, component);
	}
}

org.richfaces.taglib.DataList2Tag

package org.richfaces.taglib;

import javax.faces.component.UIComponent;
import org.ajax4jsf.webapp.taglib.HtmlComponentTagBase;

/**
 * @author tagawaman
 * 
 */
public class DataList2Tag extends HtmlComponentTagBase {
	private String _footer;
	private String _rowClasses;
	private String _stateVar;
	private String _componentState;
	private String _rowKeyVar;
	private String _footerClass;
	private String _ajaxKeys;
	private String _rowKey;
	private String _rowIndex;
	private String _var;
	private String _rows;
	private String _type;
	private String _columnClasses;
	private String _header;
	private String _first;
	private String _headerClass;
	private String _preVar;

	public DataList2Tag() {
		_footer = null;
		_rowClasses = null;
		_stateVar = null;
		_componentState = null;
		_rowKeyVar = null;
		_footerClass = null;
		_ajaxKeys = null;
		_rowKey = null;
		_rowIndex = null;
		_var = null;
		_rows = null;
		_type = null;
		_columnClasses = null;
		_header = null;
		_first = null;
		_headerClass = null;
		_preVar = null;
	}

	public void setFooter(String __footer) {
		_footer = __footer;
	}

	public void setRowClasses(String __rowClasses) {
		_rowClasses = __rowClasses;
	}

	public void setStateVar(String __stateVar) {
		_stateVar = __stateVar;
	}

	public void setComponentState(String __componentState) {
		_componentState = __componentState;
	}

	public void setRowKeyVar(String __rowKeyVar) {
		_rowKeyVar = __rowKeyVar;
	}

	public void setFooterClass(String __footerClass) {
		_footerClass = __footerClass;
	}

	public void setAjaxKeys(String __ajaxKeys) {
		_ajaxKeys = __ajaxKeys;
	}

	public void setRowKey(String __rowKey) {
		_rowKey = __rowKey;
	}

	public void setRowIndex(String __rowIndex) {
		_rowIndex = __rowIndex;
	}

	public void setVar(String __var) {
		_var = __var;
	}

	public void setRows(String __rows) {
		_rows = __rows;
	}

	public void setType(String __type) {
		_type = __type;
	}

	public void setColumnClasses(String __columnClasses) {
		_columnClasses = __columnClasses;
	}

	public void setHeader(String __header) {
		_header = __header;
	}

	public void setFirst(String __first) {
		_first = __first;
	}

	public void setHeaderClass(String __headerClass) {
		_headerClass = __headerClass;
	}

	public String get_preVar() {
		return _preVar;
	}

	public void set_preVar(String preVar) {
		this._preVar = preVar;
	}

	public void release() {
		super.release();
		_footer = null;
		_rowClasses = null;
		_stateVar = null;
		_componentState = null;
		_rowKeyVar = null;
		_footerClass = null;
		_ajaxKeys = null;
		_rowKey = null;
		_rowIndex = null;
		_var = null;
		_rows = null;
		_type = null;
		_columnClasses = null;
		_header = null;
		_first = null;
		_headerClass = null;
		_preVar = null;
	}

	protected void setProperties(UIComponent component) {
		super.setProperties(component);
		setStringProperty(component, "rowClasses", _rowClasses);
		setStringProperty(component, "stateVar", _stateVar);
		setStringProperty(component, "componentState", _componentState);
		setStringProperty(component, "rowKeyVar", _rowKeyVar);
		setStringProperty(component, "footerClass", _footerClass);
		setStringProperty(component, "ajaxKeys", _ajaxKeys);
		setStringProperty(component, "rowKey", _rowKey);
		setIntegerProperty(component, "rowIndex", _rowIndex);
		setStringProperty(component, "var", _var);
		setIntegerProperty(component, "rows", _rows);
		setStringProperty(component, "type", _type);
		setStringProperty(component, "columnClasses", _columnClasses);
		setIntegerProperty(component, "first", _first);
		setStringProperty(component, "headerClass", _headerClass);
		setStringProperty(component, "preVar", _preVar);
	}

	public String getComponentType() {
		return "org.richfaces.DataList2";
	}

	public String getRendererType() {
		return "org.richfaces.DataList2Renderer";
	}
}

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
                              "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
	<component>
		<description />
		<component-type>org.richfaces.DataList2</component-type>
		<component-class>
			org.richfaces.component.html.HtmlDataList2
		</component-class>
		<component-extension>
			<component-family>org.richfaces.DataList2</component-family>
			<renderer-type>
				org.richfaces.DataList2Renderer
			</renderer-type>
		</component-extension>
	</component>
	<render-kit>
		<render-kit-id>HTML_BASIC</render-kit-id>
		<renderer>
			<component-family>org.richfaces.DataList2</component-family>
			<renderer-type>
				org.richfaces.DataList2Renderer
			</renderer-type>
			<renderer-class>
				org.richfaces.renderkit.html.DataList2Renderer
			</renderer-class>
		</renderer>
	</render-kit>
</faces-config>

rich.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib xmlns="http://java.sun.com/JSF/Facelet">
	<namespace>http://richfaces.org/rich</namespace>
	<tag>
		<tag-name>dataList2</tag-name>
		<component>
			<component-type>org.richfaces.DataList2</component-type>
			<renderer-type>
				org.richfaces.DataList2Renderer
			</renderer-type>
		</component>
	</tag>
</facelet-taglib>

rich.tld

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
                        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
	<tlib-version>1.2</tlib-version>
	<jsp-version>1.2</jsp-version>
	<short-name>rich</short-name>
	<uri>http://richfaces.org/rich</uri>
	<display-name>RichFaces</display-name>
	<description>RichFaces components</description>


	<tag>
		<name>dataList2</name>
		<tag-class>org.richfaces.taglib.DataList2Tag</tag-class>
		<body-content>JSP</body-content>
		<description />
		<attribute>
			<name>title</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Advisory title information about markup elements
				generated for this component
			</description>
		</attribute>
		<attribute>
			<name>rowClasses</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				A comma-delimited list of CSS style classes that is
				applied to popup table rows. A space separated list of
				classes may also be specified for any individual row.
				The styles are applied, in turn, to each row in the
				table. For example, if the list has two elements, the
				first style class in the list is applied to the first
				row, the second to the second row, the first to the
				third row, the second to the fourth row, etc. In other
				words, we keep iterating through the list until we reach
				the end, and then we start at the beginning again
			</description>
		</attribute>
		<attribute>
			<name>stateVar</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				The attribute provides access to a component state on
				the client side
			</description>
		</attribute>
		<attribute>
			<name>componentState</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				It defines EL-binding for a component state for saving
				or redefinition
			</description>
		</attribute>
		<attribute>
			<name>rowKeyVar</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				The attribute provides access to a row key in a Request
				scope
			</description>
		</attribute>
		<attribute>
			<name>rendered</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				If "false", this component is not rendered
			</description>
		</attribute>
		<attribute>
			<name>footerClass</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Space-separated list of CSS style class(es) that are be
				applied to any footer generated for this table
			</description>
		</attribute>
		<attribute>
			<name>dir</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Direction indication for text that does not inherit
				directionality. Valid values are "LTR" (left-to-right)
				and "RTL" (right-to-left)
			</description>
		</attribute>
		<attribute>
			<name>id</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Every component may have a unique id that is
				automatically created if omitted
			</description>
		</attribute>
		<attribute>
			<name>styleClass</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Corresponds to the HTML class attribute
			</description>
		</attribute>
		<attribute>
			<name>ajaxKeys</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				This attribute defines rows that are updated after an
				AJAX request
			</description>
		</attribute>
		<attribute>
			<name>rowKey</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				RowKey is a representation of an identifier for a
				specific data row
			</description>
		</attribute>
		<attribute>
			<name>style</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				CSS style(s) is/are to be applied when this component is
				rendered
			</description>
		</attribute>
		<attribute>
			<name>var</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				A request-scope attribute via which the data object for
				the current row will be used when iterating
			</description>
		</attribute>
		<attribute>
			<name>preVar</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				A request-scope attribute via which the data object for
				the pre-row will be used when iterating
			</description>
		</attribute>
		<attribute>
			<name>value</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				The current value for this component
			</description>
		</attribute>
		<attribute>
			<name>rows</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				A number of rows to display, or zero for all remaining
				rows in the table
			</description>
		</attribute>
		<attribute>
			<name>lang</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Code describing the language used in the generated
				markup for this component
			</description>
		</attribute>
		<attribute>
			<name>type</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Corresponds to the HTML DL type attribute
			</description>
		</attribute>
		<attribute>
			<name>columnClasses</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Comma-delimited list of CSS style classes that are be
				applied to the columns of this table. A space separated
				list of classes may also be specified for any individual
				column. If the number of elements in this list is less
				than the number of columns specified in the "columns"
				attribute, no "class" attribute is output for each
				column greater than the number of elements in the list.
				If the number of elements in the list is greater than
				the number of columns specified in the "columns"
				attribute, the elements at the position in the list
				after the value of the "columns" attribute are ignored
			</description>
		</attribute>
		<attribute>
			<name>first</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				A zero-relative row number of the first row to display
			</description>
		</attribute>
		<attribute>
			<name>headerClass</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				Space-separated list of CSS style class(es) that are be
				applied to any header generated for this table
			</description>
		</attribute>
		<attribute>
			<name>binding</name>
			<rtexprvalue>false</rtexprvalue>
			<description>
				The attribute takes a value-binding expression for a
				component property of a backing bean
			</description>
		</attribute>
	</tag>
</taglib>

のソースとほぼ同じなので、ほんとは継承して差分だけコーディング
したほうがいいのかも。時間があったら継承にしなおそっと。