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; 042import org.nuxeo.ecm.platform.ui.web.util.FaceletDebugTracer; 043 044import com.sun.faces.facelets.tag.jsf.ComponentSupport; 045 046/** 047 * Tag handler for a {@link UIValueHolder} component, that exposes the value kept by the component at build time for 048 * children components. 049 * 050 * @since 5.5 051 */ 052public class ValueHolderTagHandler extends GenericHtmlComponentHandler { 053 054 protected final Log log = LogFactory.getLog(ValueHolderTagHandler.class); 055 056 protected final TagAttribute var; 057 058 /** 059 * @since 8.2 060 */ 061 protected final TagAttribute skip; 062 063 public ValueHolderTagHandler(ComponentConfig config) { 064 super(config); 065 var = getAttribute("var"); 066 skip = getAttribute("skip"); 067 } 068 069 @Override 070 public void apply(FaceletContext ctx, UIComponent parent) throws IOException { 071 boolean skipValue = false; 072 if (skip != null) { 073 skipValue = skip.getBoolean(ctx); 074 } 075 if (skipValue) { 076 super.applyNextHandler(ctx, parent); 077 } else { 078 super.apply(ctx, parent); 079 } 080 } 081 082 @Override 083 public void applyNextHandler(FaceletContext ctx, UIComponent c) throws IOException, FacesException, ELException { 084 long start = FaceletDebugTracer.start(); 085 String varName = null; 086 try { 087 boolean varSet = false; 088 if (var != null) { 089 varName = var.getValue(ctx); 090 } 091 092 VariableMapper orig = ctx.getVariableMapper(); 093 AliasVariableMapper alias = new AliasVariableMapper(); 094 // XXX: reuse the component id as the alias variable mapper id so that 095 // the value holder JSF component can reuse it at render time to expose 096 // the value it keeps 097 String aliasId = (String) c.getAttributes().get(ComponentSupport.MARK_CREATED); 098 alias.setId(aliasId); 099 100 if (!StringUtils.isBlank(varName)) { 101 varSet = true; 102 List<String> blockedPatterns = new ArrayList<String>(); 103 blockedPatterns.add(varName); 104 alias.setBlockedPatterns(blockedPatterns); 105 } 106 107 try { 108 if (varSet) { 109 Object valueToExpose = retrieveValueToExpose(ctx, c); 110 ExpressionFactory eFactory = ctx.getExpressionFactory(); 111 ValueExpression valueVe = eFactory.createValueExpression(valueToExpose, Object.class); 112 alias.setVariable(varName, valueVe); 113 VariableMapper vm = alias.getVariableMapperForBuild(orig); 114 ctx.setVariableMapper(vm); 115 AliasVariableMapper.exposeAliasesToRequest(ctx.getFacesContext(), alias); 116 } 117 super.applyNextHandler(ctx, c); 118 } finally { 119 if (varSet) { 120 AliasVariableMapper.removeAliasesExposedToRequest(ctx.getFacesContext(), aliasId); 121 ctx.setVariableMapper(orig); 122 } 123 } 124 } finally { 125 FaceletDebugTracer.trace(start, getTag(), varName); 126 } 127 } 128 129 /** 130 * Returns the value to expose at build time for this tag handler. 131 * <p> 132 * Value can be retrieved directly from component in most of cases, but should be retrieved from view-scoped managed 133 * bean when the restore phase is called (as component has not been restored yet, so its value is not available to 134 * be exposed in the tree view being built). 135 * 136 * @since 6.0 137 */ 138 protected Object retrieveValueToExpose(FaceletContext context, UIComponent comp) { 139 if (comp instanceof UIValueHolder) { 140 UIValueHolder c = (UIValueHolder) comp; 141 FacesContext faces = context.getFacesContext(); 142 if (PhaseId.RESTORE_VIEW.equals(faces.getCurrentPhaseId())) { 143 // lookup backing bean 144 NuxeoValueHolderBean bean = c.lookupBean(faces); 145 if (bean != null) { 146 String fid = c.getFaceletId(); 147 if (fid != null && bean.hasState(fid)) { 148 return bean.getState(fid); 149 } 150 } 151 } 152 return c.getValueToExpose(); 153 } else { 154 String className = null; 155 if (comp != null) { 156 className = comp.getClass().getName(); 157 } 158 log.error("Associated component with class '" + className 159 + "' is not a UIValueHolder instance => cannot retrieve value to expose."); 160 } 161 return null; 162 } 163 164}