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: LayoutRowWidgetTagHandler.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.io.Serializable; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import javax.el.ELException; 032import javax.el.ExpressionFactory; 033import javax.el.ValueExpression; 034import javax.el.VariableMapper; 035import javax.faces.FacesException; 036import javax.faces.component.UIComponent; 037import javax.faces.view.facelets.FaceletContext; 038import javax.faces.view.facelets.FaceletException; 039import javax.faces.view.facelets.FaceletHandler; 040import javax.faces.view.facelets.TagAttribute; 041import javax.faces.view.facelets.TagConfig; 042import javax.faces.view.facelets.TagHandler; 043 044import org.apache.commons.logging.Log; 045import org.apache.commons.logging.LogFactory; 046import org.nuxeo.ecm.platform.forms.layout.api.LayoutRow; 047import org.nuxeo.ecm.platform.forms.layout.api.Widget; 048import org.nuxeo.ecm.platform.ui.web.binding.BlockingVariableMapper; 049 050/** 051 * Layout widget recursion tag handler. 052 * <p> 053 * Iterates over a layout row widgets and apply next handlers as many times as needed. 054 * <p> 055 * Only works when used inside a tag using the {@link LayoutRowTagHandler}. 056 * 057 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 058 */ 059public class LayoutRowWidgetTagHandler extends TagHandler { 060 061 private static final Log log = LogFactory.getLog(LayoutRowWidgetTagHandler.class); 062 063 protected final TagConfig config; 064 065 /** 066 * @since 7.2 067 */ 068 protected final TagAttribute recomputeIds; 069 070 public LayoutRowWidgetTagHandler(TagConfig config) { 071 super(config); 072 this.config = config; 073 recomputeIds = getAttribute("recomputeIds"); 074 } 075 076 /** 077 * For each widget in current row, exposes widget variables and applies next handler. 078 * <p> 079 * Needs row to be exposed in context, so works in conjunction with {@link LayoutRowTagHandler}. 080 * <p> 081 * Widget variables exposed: {@link RenderVariables.widgetVariables#widget} , same variable suffixed with "_n" where 082 * n is the widget level, and {@link RenderVariables.widgetVariables#widgetIndex}. 083 */ 084 public void apply(FaceletContext ctx, UIComponent parent) 085 throws IOException, FacesException, FaceletException, ELException { 086 if (FaceletHandlerHelper.isAliasOptimEnabled()) { 087 applyOptimized(ctx, parent); 088 } else { 089 applyCompat(ctx, parent); 090 } 091 } 092 093 protected void applyOptimized(FaceletContext ctx, UIComponent parent) 094 throws IOException, FacesException, FaceletException, ELException { 095 // resolve widgets from row in context 096 LayoutRow row = null; 097 String rowVariableName = getInstanceName(); 098 FaceletHandlerHelper helper = new FaceletHandlerHelper(config); 099 TagAttribute rowAttribute = helper.createAttribute(rowVariableName, "#{" + rowVariableName + "}"); 100 if (rowAttribute != null) { 101 row = (LayoutRow) rowAttribute.getObject(ctx, LayoutRow.class); 102 } 103 if (row == null) { 104 log.error("Could not resolve layout row " + rowAttribute); 105 return; 106 } 107 108 Widget[] widgets = row.getWidgets(); 109 if (widgets == null || widgets.length == 0) { 110 return; 111 } 112 113 boolean recomputeIdsBool = false; 114 if (recomputeIds != null) { 115 recomputeIdsBool = recomputeIds.getBoolean(ctx); 116 } 117 118 VariableMapper orig = ctx.getVariableMapper(); 119 try { 120 int widgetCounter = 0; 121 for (Widget widget : widgets) { 122 BlockingVariableMapper vm = new BlockingVariableMapper(orig); 123 ctx.setVariableMapper(vm); 124 125 // set unique id on widget before exposing it to the context, but assumes iteration could be done 126 // several times => do not generate id again if already set, unless specified by attribute 127 // "recomputeIds" 128 if (widget != null && (widget.getId() == null || recomputeIdsBool)) { 129 WidgetTagHandler.generateWidgetId(ctx, helper, widget, false); 130 } 131 132 WidgetTagHandler.exposeWidgetVariables(ctx, vm, widget, widgetCounter, true); 133 134 nextHandler.apply(ctx, parent); 135 widgetCounter++; 136 } 137 } finally { 138 ctx.setVariableMapper(orig); 139 } 140 } 141 142 protected String getInstanceName() { 143 return RenderVariables.rowVariables.layoutRow.name(); 144 } 145 146 protected void applyCompat(FaceletContext ctx, UIComponent parent) 147 throws IOException, FacesException, FaceletException, ELException { 148 // resolve widgets from row in context 149 LayoutRow row = null; 150 String rowVariableName = RenderVariables.rowVariables.layoutRow.name(); 151 FaceletHandlerHelper helper = new FaceletHandlerHelper(config); 152 TagAttribute rowAttribute = helper.createAttribute(rowVariableName, "#{" + rowVariableName + "}"); 153 if (rowAttribute != null) { 154 row = (LayoutRow) rowAttribute.getObject(ctx, LayoutRow.class); 155 } 156 if (row == null) { 157 log.error("Could not resolve layout row " + rowAttribute); 158 return; 159 } 160 161 Widget[] widgets = row.getWidgets(); 162 if (widgets == null || widgets.length == 0) { 163 return; 164 } 165 166 boolean recomputeIdsBool = false; 167 if (recomputeIds != null) { 168 recomputeIdsBool = recomputeIds.getBoolean(ctx); 169 } 170 171 int widgetCounter = 0; 172 for (Widget widget : widgets) { 173 // set unique id on widget before exposing it to the context, but assumes iteration could be done several 174 // times => do not generate id again if already set, unless specified by attribute "recomputeIds" 175 if (widget != null && (widget.getId() == null || recomputeIdsBool)) { 176 WidgetTagHandler.generateWidgetId(ctx, helper, widget, false); 177 } 178 179 // expose widget variables 180 Map<String, ValueExpression> variables = new HashMap<String, ValueExpression>(); 181 ExpressionFactory eFactory = ctx.getExpressionFactory(); 182 ValueExpression widgetVe = eFactory.createValueExpression(widget, Widget.class); 183 variables.put(RenderVariables.widgetVariables.widget.name(), widgetVe); 184 Integer level = null; 185 String tagConfigId = null; 186 if (widget != null) { 187 level = Integer.valueOf(widget.getLevel()); 188 tagConfigId = widget.getTagConfigId(); 189 } 190 variables.put(RenderVariables.widgetVariables.widget.name() + "_" + level, widgetVe); 191 ValueExpression widgetIndexVe = eFactory.createValueExpression(Integer.valueOf(widgetCounter), 192 Integer.class); 193 variables.put(RenderVariables.widgetVariables.widgetIndex.name(), widgetIndexVe); 194 variables.put(RenderVariables.widgetVariables.widgetIndex.name() + "_" + level, widgetIndexVe); 195 196 // XXX: expose widget controls too, need to figure out 197 // why controls cannot be references to widget.controls like 198 // properties are in TemplateWidgetTypeHandler 199 if (widget != null) { 200 for (Map.Entry<String, Serializable> ctrl : widget.getControls().entrySet()) { 201 String key = ctrl.getKey(); 202 String name = RenderVariables.widgetVariables.widgetControl.name() + "_" + key; 203 Serializable value = ctrl.getValue(); 204 variables.put(name, eFactory.createValueExpression(value, Object.class)); 205 } 206 } 207 208 List<String> blockedPatterns = new ArrayList<String>(); 209 blockedPatterns.add(RenderVariables.widgetVariables.widget.name() + "*"); 210 blockedPatterns.add(RenderVariables.widgetVariables.widgetIndex.name() + "*"); 211 blockedPatterns.add(RenderVariables.widgetVariables.widgetControl.name() + "_*"); 212 213 FaceletHandler handler = helper.getAliasFaceletHandler(tagConfigId, variables, blockedPatterns, 214 nextHandler); 215 216 // apply 217 handler.apply(ctx, parent); 218 widgetCounter++; 219 } 220 } 221 222}