/*
* ColumnsHandler.java Date created: 07.12.2007
* Last modified by: $Author$
* $Revision$ $Date$
*/
package org.richfaces.taglib;
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.servlet.jsp.JspTagException;
import org.richfaces.iterator.ForEachIterator;
import org.richfaces.iterator.SimpleForEachIterator;
import com.sun.facelets.FaceletContext;
import com.sun.facelets.tag.MetaRuleset;
import com.sun.facelets.tag.MetaTagHandler;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.jsf.ComponentConfig;
/**
* TODO Class description goes here.
*
* @author "Andrey Markavtsov"
*
*/
public class ComponentHandler extends MetaTagHandler {
com.sun.facelets.tag.jsf.ComponentHandler handler;
/** value attribute */
private TagAttribute value;
/** end attribute */
private TagAttribute columns;
/** begin attribute */
private TagAttribute begin;
/** var attribute */
private TagAttribute var;
/** index attribute */
private TagAttribute index;
/** end attribute */
private TagAttribute end;
/** Iterator for columns's tag value attribute */
protected ForEachIterator items; // our 'digested' items
/** Value attribute value */
protected Object rawItems; // our 'raw' items
/** Var attr - defines page variable for current item */
private String _indexId;
/** Integer value begin attr */
private Integer _begin;
/** Integer value end attr */
private Integer _end;
/** Integer value of end attr. */
private Integer _columns;
/** String value of var attr */
private String _itemId = null;
/** Current column counter */
private Integer _index = 0;
/** Expression for var item */
private IteratedExpression iteratedExpression;
/**
* TODO Description goes here.
*
* @param config
*/
public ComponentHandler(ComponentConfig config) {
super(config);
handler = new ColumnTagHandler(config);
}
/**
* Extracts tags attributes values
*/
private void initVariables(FaceletContext ctx) {
initColumnsCount(ctx);
initIndex(ctx);
initVar(ctx);
initBegin(ctx);
initEnd(ctx);
}
/**
* Method prepares all we need for starting of tag rendering
*
* @throws JspTagException
*/
private void prepare(FaceletContext ctx) {
initVariables(ctx);
try {
this.value = getAttribute("value");
// produce the right sort of ForEachIterator
if (value != null) {
// If this is a deferred expression, make a note and get
// the 'items' instance.
rawItems = value.getObject(ctx);
// extract an iterator over the 'items' we've got
items = SimpleForEachIterator
.supportedTypeForEachIterator(rawItems);
} else {
// no 'items', so use 'begin' and 'end'
items = SimpleForEachIterator
.beginEndForEachIterator(_columns - 1);
}
} catch (Exception e) {
// TODO: handle exception
}
correctFirst(ctx);
}
/**
* Inits first iteration item
*/
private void correctFirst(FaceletContext ctx) {
if (items != null) {
if (_begin > 0 && (_index < _begin)) {
while ((_index < _begin && hasNext())) {
next(ctx);
}
if (!hasNext()) {
_index = 0;
}
}
}
}
/**
* Return true if we didn't complete column's count
*
* @return
* @throws JspTagException
*/
private boolean hasNext() {
try {
if (_end != 0) {
return (_index < _end) ? items.hasNext() : false;
} else {
return items.hasNext();
}
} catch (Exception e) {
return false;
}
}
/**
* Iterate to next column
*
* @return
* @throws JspTagException
*/
private Object next(FaceletContext ctx) {
try {
Object o = items.next();
_index++;
return o;
} catch (Exception e) {
return null;
}
}
/**
* Extracts integer value from end attr
*/
private void initColumnsCount(FaceletContext ctx) {
this.columns = getAttribute("columns");
if (columns != null) {
try {
_columns = Integer.parseInt((String) columns.getObject(ctx));
if (_columns < 0) {
_columns = 0; // If end is negative set up zero
}
} catch (Exception e) {
_columns = 0;
}
} else {
_columns = 0;
}
}
/**
* Extracts integer value from begin attr
*/
private void initBegin(FaceletContext ctx) {
this.begin = getAttribute("begin");
if (begin != null) {
try {
Object o = begin.getObject(ctx);
if (o instanceof Number) {
_begin = ((Number)o).intValue();
}else if (o instanceof String) {
_begin = Integer.parseInt((String) o);
}
_begin--;
if (_begin < 0) {
_begin = 0; // If end is negative set up zero
}
} catch (Exception e) {
_begin = 0;
}
} else {
_begin = 0;
}
}
/**
* Extracts integer value from end attr
*/
private void initEnd(FaceletContext ctx) {
this.end = getAttribute("end");
if (end != null) {
try {
Object o = end.getObject(ctx);
if (o instanceof Number) {
_end = ((Number)o).intValue();
}else if ( o instanceof String) {
_end = Integer.parseInt((String) o);
}
if (_end < 0) {
_end = 0; // If end is negative set up zero
}
} catch (Exception e) {
_end = 0;
}
} else {
_end = 0;
}
}
/**
* Extracts string value from var attr
*/
private void initVar(FaceletContext ctx) {
this.var = getAttribute("var");
if (var != null) {
try {
_itemId = (String) var.getObject(ctx);
} catch (ClassCastException e) {
_itemId = null;
}
}
}
/**
* Extracts string value from index attr
*/
private void initIndex(FaceletContext ctx) {
this.index = getAttribute("index");
if (index != null) {
try {
_indexId = (String) index.getObject(ctx);
} catch (ClassCastException e) {
_indexId = null;
}
}
}
/* (non-Javadoc)
* @see org.richfaces.taglib.ComponentHandler#apply(com.sun.facelets.FaceletContext, javax.faces.component.UIComponent)
*/
//@Override
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, ELException {
prepare(ctx); // prepare data
try {
while (hasNext()) { // for each
exposeVariables(ctx, _index);
//super.apply(ctx, parent);
handler.apply(ctx, parent);
next(ctx);
}
} catch (Exception e) {
// TODO: handle exception
} finally {
release();
unExposeVariables(ctx);
}
}
protected void applyNextHandler(FaceletContext ctx, UIComponent c)
throws IOException, FacesException, ELException {
// TODO Auto-generated method stub
//super.applyNextHandler(ctx, c);
}
/**
* Sets page request variables
*
* @throws JspTagException
*/
private void exposeVariables(FaceletContext ctx, int k) {
VariableMapper vm = ctx.getVariableMapper();
if (_itemId != null) {
if (vm != null) {
if (value != null) {
ValueExpression srcVE = value.getValueExpression(ctx,
Object.class);
ValueExpression ve = getVarExpression(ctx, srcVE, k);
vm.setVariable(_itemId, ve);
}
}
}
// Set up index variable
if (_indexId != null) {
if (vm != null) {
ValueExpression ve = new IteratedIndexExpression(k);
vm.setVariable(_indexId, ve);
}
}
}
/**
* Removes page attributes that we have exposed and, if applicable, restores
* them to their prior values (and scopes).
*/
private void unExposeVariables(FaceletContext ctx) {
VariableMapper vm = ctx.getVariableMapper();
// "nested" variables are now simply removed
if (_itemId != null) {
if (vm != null)
vm.setVariable(_itemId, null);
}
if (_indexId != null) {
if (vm != null)
vm.setVariable(_indexId, null);
}
}
/**
* Return expression for page variables
*
* @param expr
* @return
*/
private ValueExpression getVarExpression(FaceletContext ctx,
ValueExpression expr, int k) {
Object o = expr.getValue(ctx.getFacesContext().getELContext());
if (o.getClass().isArray() || o instanceof List) {
return new IndexedValueExpression(expr, k);
}
if (o instanceof Collection || o instanceof Iterator
|| o instanceof Enumeration || o instanceof Map
|| o instanceof String) {
if (iteratedExpression == null) {
iteratedExpression = new IteratedExpression(expr, ",");
}
return new IteratedValueExpression(iteratedExpression, k);
}
throw new ELException("FOREACH_BAD_ITEMS");
}
/**
* Release iteration variables
*/
private void release() {
this.items = null;
this._index = 0;
}
}