001/* 002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Anahide Tchertchian 016 */ 017package org.nuxeo.ecm.platform.ui.web.component.holder; 018 019import java.io.IOException; 020import java.util.ArrayList; 021import java.util.List; 022 023import javax.el.ELException; 024import javax.el.ExpressionFactory; 025import javax.el.ValueExpression; 026import javax.el.VariableMapper; 027import javax.faces.FacesException; 028import javax.faces.component.UIComponent; 029import javax.faces.context.FacesContext; 030import javax.faces.event.PhaseId; 031import javax.faces.view.facelets.ComponentConfig; 032import javax.faces.view.facelets.FaceletContext; 033import javax.faces.view.facelets.TagAttribute; 034 035import org.apache.commons.lang.StringUtils; 036import org.apache.commons.logging.Log; 037import org.apache.commons.logging.LogFactory; 038import org.nuxeo.ecm.platform.ui.web.binding.alias.AliasVariableMapper; 039import org.nuxeo.ecm.platform.ui.web.tag.handler.GenericHtmlComponentHandler; 040 041import com.sun.faces.facelets.tag.jsf.ComponentSupport; 042 043/** 044 * Tag handler for a {@link UIValueHolder} component, that exposes the value kept by the component at build time for 045 * children components. 046 * 047 * @since 5.5 048 */ 049public class ValueHolderTagHandler extends GenericHtmlComponentHandler { 050 051 protected final Log log = LogFactory.getLog(ValueHolderTagHandler.class); 052 053 protected final TagAttribute var; 054 055 public ValueHolderTagHandler(ComponentConfig config) { 056 super(config); 057 var = getAttribute("var"); 058 } 059 060 @Override 061 public void applyNextHandler(FaceletContext ctx, UIComponent c) throws IOException, FacesException, ELException { 062 String varName = null; 063 boolean varSet = false; 064 if (var != null) { 065 varName = var.getValue(ctx); 066 } 067 068 VariableMapper orig = ctx.getVariableMapper(); 069 AliasVariableMapper alias = new AliasVariableMapper(); 070 // XXX: reuse the component id as the alias variable mapper id so that 071 // the value holder JSF component can reuse it at render time to expose 072 // the value it keeps 073 String aliasId = (String) c.getAttributes().get(ComponentSupport.MARK_CREATED); 074 alias.setId(aliasId); 075 076 if (!StringUtils.isBlank(varName)) { 077 varSet = true; 078 List<String> blockedPatterns = new ArrayList<String>(); 079 blockedPatterns.add(varName); 080 alias.setBlockedPatterns(blockedPatterns); 081 } 082 083 try { 084 if (varSet) { 085 Object valueToExpose = retrieveValueToExpose(ctx, c); 086 ExpressionFactory eFactory = ctx.getExpressionFactory(); 087 ValueExpression valueVe = eFactory.createValueExpression(valueToExpose, Object.class); 088 alias.setVariable(varName, valueVe); 089 VariableMapper vm = alias.getVariableMapperForBuild(orig); 090 ctx.setVariableMapper(vm); 091 AliasVariableMapper.exposeAliasesToRequest(ctx.getFacesContext(), alias); 092 } 093 super.applyNextHandler(ctx, c); 094 } finally { 095 if (varSet) { 096 AliasVariableMapper.removeAliasesExposedToRequest(ctx.getFacesContext(), aliasId); 097 ctx.setVariableMapper(orig); 098 } 099 } 100 } 101 102 /** 103 * Returns the value to expose at build time for this tag handler. 104 * <p> 105 * Value can be retrieved directly from component in most of cases, but should be retrieved from view-scoped managed 106 * bean when the restore phase is called (as component has not been restored yet, so its value is not available to 107 * be exposed in the tree view being built). 108 * 109 * @since 6.0 110 */ 111 protected Object retrieveValueToExpose(FaceletContext context, UIComponent comp) { 112 if (comp instanceof UIValueHolder) { 113 UIValueHolder c = (UIValueHolder) comp; 114 FacesContext faces = context.getFacesContext(); 115 if (PhaseId.RESTORE_VIEW.equals(faces.getCurrentPhaseId())) { 116 // lookup backing bean 117 NuxeoValueHolderBean bean = c.lookupBean(faces); 118 if (bean != null) { 119 String fid = c.getFaceletId(); 120 if (fid != null && bean.hasState(fid)) { 121 return bean.getState(fid); 122 } 123 } 124 } 125 return c.getValueToExpose(); 126 } else { 127 String className = null; 128 if (comp != null) { 129 className = comp.getClass().getName(); 130 } 131 log.error(String.format("Associated component with class '%s' is not" 132 + " a UIValueHolder instance => cannot " + "retrieve value to expose.", className)); 133 } 134 return null; 135 } 136 137}