Java tutorial
/** * License Agreement. * * Rich Faces - Natural Ajax for Java Server Faces (JSF) * * Copyright (C) 2007 Exadel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * 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.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.servlet.jsp.JspTagException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.richfaces.el.ELBuilder; import org.richfaces.iterator.ForEachIterator; import org.richfaces.iterator.SimpleForEachIterator; import com.sun.facelets.FaceletContext; import com.sun.facelets.FaceletHandler; import com.sun.facelets.tag.MetaRule; import com.sun.facelets.tag.MetaRuleset; import com.sun.facelets.tag.MetaTagHandler; import com.sun.facelets.tag.Metadata; import com.sun.facelets.tag.MetadataTarget; import com.sun.facelets.tag.Tag; import com.sun.facelets.tag.TagAttribute; import com.sun.facelets.tag.TagAttributes; import com.sun.facelets.tag.jsf.ComponentConfig; /** * TODO Class description goes here. * * @author "Andrey Markavtsov" * */ public class ColumnsHandler extends MetaTagHandler { private static final Log log = LogFactory.getLog(ColumnsHandler.class); com.sun.facelets.tag.jsf.ComponentHandler handler; private static final String ITERATION_INDEX_VARIABLE = "__richfaces_iteration_index_variable"; private static final String ITERATION_INDEX_EXPRESSION = "#{" + ITERATION_INDEX_VARIABLE + "}"; private static final String F_GENERATION_SERIES_ATTRIBUTE = "org.richfaces.F_COLUMNS_GENERATION_SERIES"; /** 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; class IterationContext { /** Iterator for columns's tag value attribute */ public ForEachIterator items; // our 'digested' items /** Value attribute value */ public Object rawItems; // our 'raw' items /** Var attr - defines page variable for current item */ public String _indexId; /** Integer value begin attr */ public Integer _begin; /** Integer value end attr */ public Integer _end; /** Integer value of end attr. */ public Integer _columns; /** String value of var attr */ public String _itemId = null; /** Current column counter */ public Integer _index = 0; /** Expression for var item */ public IteratedExpression iteratedExpression; public String valueExpr; public String getVarReplacement() { if (valueExpr == null) { return String.valueOf(index); } else if (items.getVarReplacement() != null) { return items.getVarReplacement(); } return valueExpr + "[" + _index + "]"; } public String getIndexReplacement() { return String.valueOf(_index); } }; ThreadLocal<IterationContext> iterationContextLocal = new ThreadLocal<IterationContext>(); public IterationContext getIterationContext() { return iterationContextLocal.get(); } /** * TODO Description goes here. * * @param config */ public ColumnsHandler(final ComponentConfig config) { super(config); final ComponentConfig columnConfig; TagAttribute idAttribute = config.getTag().getAttributes().get("id"); if (idAttribute != null && idAttribute.isLiteral()) { columnConfig = new ComponentConfig() { private Tag tag; { Tag initialTag = config.getTag(); TagAttribute[] allInitialAttributes = initialTag.getAttributes().getAll(); TagAttribute[] attributes = new TagAttribute[allInitialAttributes.length]; for (int i = 0; i < allInitialAttributes.length; i++) { TagAttribute initialAttribute = allInitialAttributes[i]; String localName = initialAttribute.getLocalName(); String attributeValue = initialAttribute.getValue(); if ("id".equals(localName)) { attributeValue += ITERATION_INDEX_EXPRESSION; } attributes[i] = new TagAttribute(initialAttribute.getLocation(), initialAttribute.getNamespace(), localName, initialAttribute.getQName(), attributeValue); } TagAttributes tagAttributes = new TagAttributes(attributes); this.tag = new Tag(initialTag, tagAttributes); } public String getComponentType() { return config.getComponentType(); } public String getRendererType() { return config.getRendererType(); } public FaceletHandler getNextHandler() { return config.getNextHandler(); } public Tag getTag() { return tag; } public String getTagId() { return config.getTagId(); } }; } else { columnConfig = config; } handler = new ColumnTagHandler(columnConfig) { @Override protected MetaRuleset createMetaRuleset(Class type) { MetaRuleset ruleset = super.createMetaRuleset(type); ruleset.addRule(new MetaRule() { @Override public Metadata applyRule(final String name, final TagAttribute attribute, MetadataTarget meta) { if (ColumnsAttributes.FILTER_ATTRIBUTES.indexOf(name) != -1 || ColumnsAttributes.SORT_ATTRIBUTES.indexOf(name) != -1) { return new Metadata() { @Override public void applyMetadata(FaceletContext ctx, Object instance) { if (!attribute.isLiteral()) { String expr = attribute.getValue(); IterationContext itContext = iterationContextLocal.get(); ValueExpression ve = ELBuilder.createValueExpression(expr, Object.class, ctx.getExpressionFactory(), ctx, itContext._itemId, itContext._indexId, itContext.getVarReplacement(), itContext.getIndexReplacement()); ((UIComponent) instance).setValueExpression(name, ve); } else { ((UIComponent) instance).getAttributes().put(name, attribute.getValue()); } } }; } return null; } }); return ruleset; } @Override protected void applyNextHandler(FaceletContext ctx, UIComponent c) throws IOException, FacesException, ELException { c.getAttributes().put(F_GENERATION_SERIES_ATTRIBUTE, RequestUniqueIdGenerator.generateId(ctx.getFacesContext())); super.applyNextHandler(ctx, c); } }; } /** * 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); IterationContext itContext = getIterationContext(); try { this.value = getAttribute("value"); // produce the right sort of ForEachIterator if (this.value != null) { itContext.valueExpr = ELBuilder.getVarReplacement(this.value.getValue()); // If this is a deferred expression, make a note and get // the 'items' instance. itContext.rawItems = this.value.getObject(ctx); // extract an iterator over the 'items' we've got itContext.items = SimpleForEachIterator.supportedTypeForEachIterator(itContext.rawItems); } else { // no 'items', so use 'begin' and 'end' itContext.items = SimpleForEachIterator.beginEndForEachIterator(itContext._columns - 1); } } catch (Exception e) { log.error(e.getLocalizedMessage(), e); // TODO: handle exception } correctFirst(ctx); } /** * Inits first iteration item */ private void correctFirst(FaceletContext ctx) { IterationContext itContext = getIterationContext(); if (itContext.items != null) { if (itContext._begin > 0 && (itContext._index < itContext._begin)) { while ((itContext._index < itContext._begin && hasNext())) { next(ctx); } if (!hasNext()) { itContext._index = 0; } } } } /** * Return true if we didn't complete column's count * * @return * @throws JspTagException */ private boolean hasNext() { IterationContext itContext = getIterationContext(); try { if (itContext._end != 0) { return (itContext._index < itContext._end) ? itContext.items.hasNext() : false; } else { return itContext.items.hasNext(); } } catch (Exception e) { return false; } } /** * Iterate to next column * * @return * @throws JspTagException */ private Object next(FaceletContext ctx) { IterationContext itContext = getIterationContext(); try { Object o = itContext.items.next(); itContext._index++; return o; } catch (Exception e) { return null; } } /** * Extracts integer value from end attr */ private void initColumnsCount(FaceletContext ctx) { IterationContext itContext = getIterationContext(); this.columns = getAttribute("columns"); if (columns != null) { try { itContext._columns = Integer.parseInt((String) columns.getObject(ctx)); if (itContext._columns < 0) { itContext._columns = 0; // If end is negative set up zero } } catch (Exception e) { itContext._columns = 0; } } else { itContext._columns = 0; } } /** * Extracts integer value from begin attr */ private void initBegin(FaceletContext ctx) { IterationContext itContext = getIterationContext(); this.begin = getAttribute("begin"); if (begin != null) { try { Object o = begin.getObject(ctx); if (o instanceof Number) { itContext._begin = ((Number) o).intValue(); } else if (o instanceof String) { itContext._begin = Integer.parseInt((String) o); } itContext._begin--; if (itContext._begin < 0) { itContext._begin = 0; // If end is negative set up zero } } catch (Exception e) { itContext._begin = 0; } } else { itContext._begin = 0; } } /** * Extracts integer value from end attr */ private void initEnd(FaceletContext ctx) { IterationContext itContext = getIterationContext(); this.end = getAttribute("end"); if (end != null) { try { Object o = end.getObject(ctx); if (o instanceof Number) { itContext._end = ((Number) o).intValue(); } else if (o instanceof String) { itContext._end = Integer.parseInt((String) o); } if (itContext._end < 0) { itContext._end = 0; // If end is negative set up zero } } catch (Exception e) { itContext._end = 0; } } else { itContext._end = 0; } } /** * Extracts string value from var attr */ private void initVar(FaceletContext ctx) { IterationContext itContext = getIterationContext(); this.var = getAttribute("var"); if (var != null) { try { itContext._itemId = (String) var.getObject(ctx); } catch (ClassCastException e) { itContext._itemId = null; } } } /** * Extracts string value from index attr */ private void initIndex(FaceletContext ctx) { IterationContext itContext = getIterationContext(); this.index = getAttribute("index"); if (index != null) { try { itContext._indexId = (String) index.getObject(ctx); } catch (ClassCastException e) { itContext._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 { IterationContext iterationContext = new IterationContext(); iterationContextLocal.set(iterationContext); clearOldColumns(ctx.getFacesContext(), parent); prepare(ctx); // prepare data try { while (hasNext()) { // for each exposeVariables(ctx); handler.apply(ctx, parent); next(ctx); } } catch (Exception e) { log.error(e.getLocalizedMessage(), e); // TODO: handle exception } finally { release(); unExposeVariables(ctx); } } private void clearOldColumns(FacesContext context, UIComponent parent) { if (parent.getChildCount() > 0) { Integer generatedId = RequestUniqueIdGenerator.generateId(context); Iterator<UIComponent> childrenIt = parent.getChildren().iterator(); while (childrenIt.hasNext()) { UIComponent c = childrenIt.next(); Object generationSeries = c.getAttributes().get(F_GENERATION_SERIES_ATTRIBUTE); if (generationSeries != null && !generationSeries.equals(generatedId)) { childrenIt.remove(); } } } } /** * Sets page request variables * * @throws JspTagException */ private void exposeVariables(FaceletContext ctx) { IterationContext itContext = getIterationContext(); VariableMapper vm = ctx.getVariableMapper(); int k = itContext._index; if (itContext._itemId != null) { if (vm != null) { if (value != null) { ValueExpression srcVE = value.getValueExpression(ctx, Object.class); ValueExpression ve = getVarExpression(ctx, srcVE); vm.setVariable(itContext._itemId, ve); } } } // Set up index variable if (itContext._indexId != null) { if (vm != null) { ValueExpression ve = new IteratedIndexExpression(k); vm.setVariable(itContext._indexId, ve); } } int componentsCount = itContext._index - itContext._begin; if (componentsCount != 0) { ValueExpression ve = ctx.getExpressionFactory() .createValueExpression(UIViewRoot.UNIQUE_ID_PREFIX + componentsCount, String.class); vm.setVariable(ITERATION_INDEX_VARIABLE, ve); } } /** * Removes page attributes that we have exposed and, if applicable, restores * them to their prior values (and scopes). */ private void unExposeVariables(FaceletContext ctx) { IterationContext itContext = getIterationContext(); VariableMapper vm = ctx.getVariableMapper(); // "nested" variables are now simply removed if (itContext._itemId != null) { if (vm != null) vm.setVariable(itContext._itemId, null); } if (itContext._indexId != null) { if (vm != null) vm.setVariable(itContext._indexId, null); } vm.setVariable(ITERATION_INDEX_VARIABLE, null); } /** * Return expression for page variables * * @param expr * @return */ private ValueExpression getVarExpression(FaceletContext ctx, ValueExpression expr/*, IterationContext itContext*/) { IterationContext itContext = getIterationContext(); Object o = expr.getValue(ctx.getFacesContext().getELContext()); int k = itContext._index; 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 (itContext.iteratedExpression == null) { itContext.iteratedExpression = new IteratedExpression(expr, ","); } return new IteratedValueExpression(itContext.iteratedExpression, k); } throw new ELException("FOREACH_BAD_ITEMS"); } /** * Release iteration variables */ private void release() { IterationContext itContext = getIterationContext(); itContext.items = null; itContext._index = 0; } }