001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 018 * 019 * $Id: LayoutRowTagHandler.java 30553 2008-02-24 15:51:31Z atchertchian $ 020 */ 021 022package org.nuxeo.ecm.platform.forms.layout.facelets; 023 024import java.io.IOException; 025import java.util.ArrayList; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import javax.el.ELException; 031import javax.el.ExpressionFactory; 032import javax.el.ValueExpression; 033import javax.el.VariableMapper; 034import javax.faces.FacesException; 035import javax.faces.component.UIComponent; 036import javax.faces.view.facelets.FaceletContext; 037import javax.faces.view.facelets.FaceletHandler; 038import javax.faces.view.facelets.TagAttribute; 039import javax.faces.view.facelets.TagConfig; 040import javax.faces.view.facelets.TagHandler; 041 042import org.apache.commons.logging.Log; 043import org.apache.commons.logging.LogFactory; 044import org.nuxeo.ecm.platform.forms.layout.api.Layout; 045import org.nuxeo.ecm.platform.forms.layout.api.LayoutRow; 046import org.nuxeo.ecm.platform.ui.web.binding.BlockingVariableMapper; 047import org.nuxeo.ecm.platform.ui.web.binding.MetaValueExpression; 048 049/** 050 * Layout row recursion tag handler. 051 * <p> 052 * Iterate over the layout rows and apply next handlers as many times as needed. 053 * <p> 054 * Only works when used inside a tag using the {@link LayoutTagHandler} template client. 055 * 056 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 057 */ 058public class LayoutRowTagHandler extends TagHandler { 059 060 private static final Log log = LogFactory.getLog(LayoutRowTagHandler.class); 061 062 protected final TagConfig config; 063 064 public LayoutRowTagHandler(TagConfig config) { 065 super(config); 066 this.config = config; 067 } 068 069 /** 070 * For each row in layout, exposes row variables and applies next handler. 071 * <p> 072 * Needs layout to be exposed in context, so works in conjunction with {@link LayoutTagHandler}. 073 * <p> 074 * Row variables exposed: {@link RenderVariables.rowVariables#layoutRow} and 075 * {@link RenderVariables.rowVariables#layoutRowIndex}, as well as 076 * {@link RenderVariables.columnVariables#layoutColumn} and 077 * {@link RenderVariables.columnVariables#layoutColumnIndex}, that act are aliases. 078 */ 079 public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, ELException { 080 FaceletHandlerHelper helper = new FaceletHandlerHelper(config); 081 082 if (FaceletHandlerHelper.isAliasOptimEnabled()) { 083 applyOptimized(ctx, parent, helper); 084 } else { 085 applyCompat(ctx, parent, helper); 086 } 087 } 088 089 protected void applyOptimized(FaceletContext ctx, UIComponent parent, FaceletHandlerHelper helper) 090 throws IOException, FacesException, ELException { 091 String rowCountVarName = RenderVariables.layoutVariables.layoutRowCount.name(); 092 TagAttribute rowCountAttr = helper.createAttribute(rowCountVarName, "#{" + rowCountVarName + "}"); 093 int rowCount = rowCountAttr.getInt(ctx); 094 095 if (rowCount == 0) { 096 return; 097 } 098 099 VariableMapper orig = ctx.getVariableMapper(); 100 try { 101 for (int i = 0; i < rowCount; i++) { 102 BlockingVariableMapper vm = new BlockingVariableMapper(orig); 103 ctx.setVariableMapper(vm); 104 // expose row variables 105 ExpressionFactory eFactory = ctx.getExpressionFactory(); 106 ValueExpression ve = eFactory.createValueExpression( 107 "#{" + RenderVariables.layoutVariables.layout.name() + ".rows[" + i + "]}", String.class); 108 ValueExpression rowVe = new MetaValueExpression(ve, ctx.getFunctionMapper(), vm, LayoutRow.class); 109 ValueExpression rowIndexVe = eFactory.createValueExpression(i, Integer.class); 110 String instanceName = getInstanceName(); 111 String indexName = getIndexName(); 112 vm.setVariable(instanceName, rowVe); 113 vm.addBlockedPattern(instanceName); 114 vm.setVariable(indexName, rowIndexVe); 115 vm.addBlockedPattern(indexName); 116 117 nextHandler.apply(ctx, parent); 118 } 119 } finally { 120 ctx.setVariableMapper(orig); 121 } 122 } 123 124 protected void applyCompat(FaceletContext ctx, UIComponent parent, FaceletHandlerHelper helper) 125 throws IOException, FacesException, ELException { 126 // resolve rows from layout in context 127 Layout layout = null; 128 String layoutVariableName = RenderVariables.layoutVariables.layout.name(); 129 TagAttribute layoutAttribute = helper.createAttribute(layoutVariableName, "#{" + layoutVariableName + "}"); 130 if (layoutAttribute != null) { 131 layout = (Layout) layoutAttribute.getObject(ctx, Layout.class); 132 } 133 if (layout == null) { 134 log.error("Could not resolve layout " + layoutAttribute); 135 return; 136 } 137 LayoutRow[] rows = layout.getRows(); 138 if (rows == null || rows.length == 0) { 139 return; 140 } 141 142 int rowCounter = 0; 143 for (LayoutRow row : rows) { 144 // expose row variables 145 Map<String, ValueExpression> variables = new HashMap<String, ValueExpression>(); 146 ValueExpression rowVe = ctx.getExpressionFactory().createValueExpression(row, LayoutRow.class); 147 variables.put(RenderVariables.rowVariables.layoutRow.name(), rowVe); 148 variables.put(RenderVariables.columnVariables.layoutColumn.name(), rowVe); 149 ValueExpression rowIndexVe = ctx.getExpressionFactory().createValueExpression(Integer.valueOf(rowCounter), 150 Integer.class); 151 variables.put(RenderVariables.rowVariables.layoutRowIndex.name(), rowIndexVe); 152 variables.put(RenderVariables.columnVariables.layoutColumnIndex.name(), rowIndexVe); 153 154 List<String> blockedPatterns = new ArrayList<String>(); 155 blockedPatterns.add(RenderVariables.rowVariables.layoutRow.name()); 156 blockedPatterns.add(RenderVariables.rowVariables.layoutRowIndex.name()); 157 blockedPatterns.add(RenderVariables.columnVariables.layoutColumn.name()); 158 blockedPatterns.add(RenderVariables.columnVariables.layoutColumnIndex.name()); 159 160 FaceletHandler handler = helper.getAliasFaceletHandler(row.getTagConfigId(), variables, blockedPatterns, 161 nextHandler); 162 handler.apply(ctx, parent); 163 rowCounter++; 164 } 165 } 166 167 protected String getInstanceName() { 168 return RenderVariables.rowVariables.layoutRow.name(); 169 } 170 171 protected String getIndexName() { 172 return RenderVariables.rowVariables.layoutRowIndex.name(); 173 } 174 175}