/* * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * 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. * * Contributors: * Anahide Tchertchian */ package org.nuxeo.ecm.platform.ui.web.component.holder; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.el.ELException; import javax.el.ExpressionFactory; import javax.el.ValueExpression; import javax.el.VariableMapper; import javax.faces.FacesException; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.event.PhaseId; import javax.faces.view.facelets.ComponentConfig; import javax.faces.view.facelets.FaceletContext; import javax.faces.view.facelets.TagAttribute; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.platform.ui.web.binding.alias.AliasVariableMapper; import org.nuxeo.ecm.platform.ui.web.tag.handler.GenericHtmlComponentHandler; import com.sun.faces.facelets.tag.jsf.ComponentSupport; /** * Tag handler for a {@link UIValueHolder} component, that exposes the value * kept by the component at build time for children components. * * @since 5.5 */ public class ValueHolderTagHandler extends GenericHtmlComponentHandler { protected final Log log = LogFactory.getLog(ValueHolderTagHandler.class); protected final TagAttribute var; public ValueHolderTagHandler(ComponentConfig config) { super(config); var = getAttribute("var"); } @Override public void applyNextHandler(FaceletContext ctx, UIComponent c) throws IOException, FacesException, ELException { String varName = null; boolean varSet = false; if (var != null) { varName = var.getValue(ctx); } VariableMapper orig = ctx.getVariableMapper(); AliasVariableMapper alias = new AliasVariableMapper(); // XXX: reuse the component id as the alias variable mapper id so that // the value holder JSF component can reuse it at render time to expose // the value it keeps String aliasId = (String) c.getAttributes().get( ComponentSupport.MARK_CREATED); alias.setId(aliasId); if (!StringUtils.isBlank(varName)) { varSet = true; List<String> blockedPatterns = new ArrayList<String>(); blockedPatterns.add(varName); alias.setBlockedPatterns(blockedPatterns); } try { if (varSet) { Object valueToExpose = retrieveValueToExpose(ctx, c); ExpressionFactory eFactory = ctx.getExpressionFactory(); ValueExpression valueVe = eFactory.createValueExpression( valueToExpose, Object.class); alias.setVariable(varName, valueVe); VariableMapper vm = alias.getVariableMapperForBuild(orig); ctx.setVariableMapper(vm); AliasVariableMapper.exposeAliasesToRequest( ctx.getFacesContext(), alias); } super.applyNextHandler(ctx, c); } finally { if (varSet) { AliasVariableMapper.removeAliasesExposedToRequest( ctx.getFacesContext(), aliasId); ctx.setVariableMapper(orig); } } } /** * Returns the value to expose at build time for this tag handler. * <p> * Value can be retrieved directly from component in most of cases, but * should be retrieved from view-scoped managed bean when the restore phase * is called (as component has not been restored yet, so its value is not * available to be exposed in the tree view being built). * * @since 6.0 */ protected Object retrieveValueToExpose(FaceletContext context, UIComponent comp) { if (comp instanceof UIValueHolder) { UIValueHolder c = (UIValueHolder) comp; FacesContext faces = context.getFacesContext(); if (PhaseId.RESTORE_VIEW.equals(faces.getCurrentPhaseId())) { // lookup backing bean NuxeoValueHolderBean bean = ((UIValueHolder) c).lookupBean(faces); if (bean != null) { String fid = ((UIValueHolder) c).getFaceletId(); if (fid != null) { return bean.getState(fid); } } } return c.getValueToExpose(); } else { String className = null; if (comp != null) { className = comp.getClass().getName(); } log.error(String.format( "Associated component with class '%s' is not" + " a UIValueHolder instance => cannot " + "retrieve value to expose.", className)); } return null; } }