001/* 002 * (C) Copyright 2015 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-2.1.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.binding; 018 019import java.util.ArrayList; 020import java.util.LinkedHashMap; 021import java.util.List; 022import java.util.Map; 023 024import javax.el.ELException; 025import javax.el.ValueExpression; 026import javax.el.VariableMapper; 027 028import org.apache.commons.lang.StringUtils; 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.jboss.el.ValueExpressionLiteral; 032import org.nuxeo.ecm.platform.ui.web.binding.alias.AliasVariableMapper; 033 034/** 035 * Alternative to {@link AliasVariableMapper} optimized behavior. 036 * <p> 037 * Keeps variables in the current context, but without aliasing variables for efficiency. Compared to the standard 038 * variable mappers, adds blocking features, given patterns, to allow compartmenting variables contexts (inside layout 039 * widget trees for instance). 040 * 041 * @since 8.2 042 */ 043public class BlockingVariableMapper extends VariableMapper { 044 045 private static final Log log = LogFactory.getLog(BlockingVariableMapper.class); 046 047 protected final VariableMapper orig; 048 049 protected Map<String, ValueExpression> vars; 050 051 protected List<String> blockedPatterns; 052 053 public BlockingVariableMapper(VariableMapper orig) { 054 super(); 055 this.orig = orig; 056 } 057 058 @Override 059 public ValueExpression resolveVariable(String variable) { 060 ValueExpression ve = null; 061 try { 062 if (hasVariable(variable)) { 063 ve = (ValueExpression) vars.get(variable); 064 } else { 065 // resolve to a value expression resolving to null if variable 066 // is supposed to be blocked 067 if (variable != null && blockedPatterns != null) { 068 for (String blockedPattern : blockedPatterns) { 069 if (StringUtils.isBlank(blockedPattern)) { 070 continue; 071 } 072 boolean doBlock = false; 073 if (blockedPattern.endsWith("*")) { 074 String pattern = blockedPattern.substring(0, blockedPattern.length() - 1); 075 if (variable.startsWith(pattern)) { 076 doBlock = true; 077 } 078 } else if (blockedPattern.equals(variable)) { 079 doBlock = true; 080 } 081 if (doBlock) { 082 if (log.isDebugEnabled()) { 083 log.debug(String.format("Blocked expression var='%s'", variable)); 084 } 085 return getNullValueExpression(); 086 } 087 } 088 } 089 return orig.resolveVariable(variable); 090 } 091 return ve; 092 } catch (StackOverflowError e) { 093 throw new ELException("Could not Resolve Variable [Overflow]: " + variable, e); 094 } 095 } 096 097 @Override 098 public ValueExpression setVariable(String variable, ValueExpression expression) { 099 if (vars == null) { 100 vars = new LinkedHashMap<String, ValueExpression>(); 101 } 102 return vars.put(variable, expression); 103 } 104 105 public boolean hasVariable(String variable) { 106 return vars != null && vars.containsKey(variable); 107 } 108 109 protected ValueExpression getNullValueExpression() { 110 return new ValueExpressionLiteral(null, Object.class); 111 } 112 113 public Map<String, ValueExpression> getVariables() { 114 return vars; 115 } 116 117 public List<String> getBlockedPatterns() { 118 return blockedPatterns; 119 } 120 121 public void setBlockedPatterns(List<String> blockedPatterns) { 122 if (blockedPatterns != null) { 123 this.blockedPatterns = new ArrayList<String>(); 124 this.blockedPatterns.addAll(blockedPatterns); 125 } else { 126 this.blockedPatterns = null; 127 } 128 } 129 130 public void addBlockedPattern(String blockedPattern) { 131 if (StringUtils.isBlank(blockedPattern)) { 132 return; 133 } 134 if (this.blockedPatterns == null) { 135 this.blockedPatterns = new ArrayList<String>(); 136 } 137 this.blockedPatterns.add(blockedPattern); 138 } 139 140 @Override 141 public String toString() { 142 final StringBuilder buf = new StringBuilder(); 143 144 buf.append(getClass().getSimpleName()); 145 buf.append(" {"); 146 buf.append("vars="); 147 buf.append(vars); 148 buf.append('}'); 149 150 return buf.toString(); 151 } 152 153}