/**
* 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 com.sun.facelets.FaceletContext;
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.TagAttribute;
import com.sun.facelets.tag.jsf.ComponentConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.el.ELBuilder;
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 java.io.IOException;
import java.util.Iterator;
/**
* TODO Class description goes here.
*
* @author "Andrey Markavtsov"
*
*/
public class ColumnsHandler extends MetaTagHandler {
private static final Log log = LogFactory.getLog(ColumnsHandler.class);
private com.sun.facelets.tag.jsf.ComponentHandler handler;
static final String ITERATION_INDEX_VARIABLE = "__richfaces_iteration_index_variable";
private static final String F_GENERATION_SERIES_ATTRIBUTE = "org.richfaces.F_COLUMNS_GENERATION_SERIES";
/** value attribute */
private TagAttribute value;
/** index attribute */
private TagAttribute index;
private ThreadLocal<ColumnsHandlerIterationContext> iterationContextLocal = new ThreadLocal<ColumnsHandlerIterationContext>();
private ColumnsHandlerIterationContext 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 ColumnHandlerComponentConfig(config);
} 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();
ColumnsHandlerIterationContext itContext = iterationContextLocal.get();
ValueExpression ve = ELBuilder.createValueExpression(expr, Object.class, ctx.getExpressionFactory(), ctx,
itContext.getItemId(), itContext.getIndexId(),
itContext.getVarReplacement(index), 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);
}
};
}
/**
* Method prepares all we need for starting of tag rendering
*
* @param ctx
*/
private void prepare(FaceletContext ctx) {
ColumnsHandlerIterationContext itContext = getIterationContext();
try {
this.index = getAttribute("index");
itContext.setIndex(ctx, this.index);
itContext.setColumnsCount(ctx, getAttribute("columns"));
itContext.setVar(ctx, getAttribute("var"));
itContext.setBegin(ctx, getAttribute("begin"));
itContext.setEnd(ctx, getAttribute("end"));
this.value = getAttribute("value");
itContext.setValue(ctx, this.value);
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
// TODO: handle exception
}
itContext.correctFirst();
}
/*
* (non-Javadoc)
*
* @see org.richfaces.taglib.ComponentHandler#apply(com.sun.facelets.FaceletContext,
* javax.faces.component.UIComponent)
*/
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, ELException {
clearOldColumns(ctx.getFacesContext(), parent);
ColumnsHandlerIterationContext iterationContext = new ColumnsHandlerIterationContext();
iterationContextLocal.set(iterationContext);
prepare(ctx);
try {
while (iterationContext.hasNext()) {
exposeVariables(ctx);
handler.apply(ctx, parent);
iterationContext.next();
}
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
// TODO: handle exception
} finally {
iterationContext.release();
unExposeVariables(ctx);
iterationContextLocal.remove();
}
}
private static 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
*
* @param ctx
*/
private void exposeVariables(FaceletContext ctx) {
VariableMapper vm = ctx.getVariableMapper();
if (vm == null) {
return;
}
ColumnsHandlerIterationContext itContext = getIterationContext();
if (itContext.getItemId() != null) {
if (value != null) {
ValueExpression srcVE = value.getValueExpression(ctx, Object.class);
ValueExpression ve = itContext.getVarExpression(ctx, srcVE);
vm.setVariable(itContext.getItemId(), ve);
}
}
// Set up index variable
if (itContext.getIndexId() != null) {
ValueExpression ve = new IteratedIndexExpression(itContext.getIndex());
vm.setVariable(itContext.getIndexId(), ve);
}
int componentsCount = itContext.getIndex() - itContext.getBegin();
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).
*
* @param ctx
*/
private void unExposeVariables(FaceletContext ctx) {
VariableMapper vm = ctx.getVariableMapper();
if (vm == null) {
return;
}
// "nested" variables are now simply removed
ColumnsHandlerIterationContext itContext = getIterationContext();
if (itContext.getItemId() != null) {
vm.setVariable(itContext.getItemId(), null);
}
if (itContext.getIndexId() != null) {
vm.setVariable(itContext.getIndexId(), null);
}
vm.setVariable(ITERATION_INDEX_VARIABLE, null);
}
}