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