Skip to contentMethod: StandardELContext(ExpressionFactory)
1: /*
2: * Copyright (c) 2012, 2020 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: *
5: * This program and the accompanying materials are made available under the
6: * terms of the Eclipse Public License v. 2.0, which is available at
7: * http://www.eclipse.org/legal/epl-2.0.
8: *
9: * This Source Code may also be made available under the following Secondary
10: * Licenses when the conditions for such availability set forth in the
11: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
12: * version 2 with the GNU Classpath Exception, which is available at
13: * https://www.gnu.org/software/classpath/license.html.
14: *
15: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
16: */
17:
18: package jakarta.el;
19:
20: import java.lang.reflect.Method;
21: import java.util.HashMap;
22: import java.util.Map;
23:
24: /**
25: * A standard ELContext suitable for use in a stand alone environment. This class provides a default implementation of
26: * an ELResolver that contains a number of useful ELResolvers. It also provides local repositories for the
27: * FunctionMapper, VariableMapper, and BeanNameResolver.
28: *
29: * @since Jakarta Expression Language 3.0
30: */
31: public class StandardELContext extends ELContext {
32:
33: /*
34: * The ELResolver for this ELContext.
35: */
36: private ELResolver elResolver;
37:
38: /*
39: * The list of the custom ELResolvers added to the ELResolvers. An ELResolver is added to the list when addELResolver is
40: * called.
41: */
42: private CompositeELResolver customResolvers;
43:
44: /*
45: * The ELResolver implementing the query operators.
46: */
47: private ELResolver streamELResolver;
48:
49: /*
50: * The FunctionMapper for this ELContext.
51: */
52: private FunctionMapper functionMapper;
53:
54: /*
55: * The pre-configured init function map;
56: */
57: private Map<String, Method> initFunctionMap;
58:
59: /*
60: * The VariableMapper for this ELContext.
61: */
62: private VariableMapper variableMapper;
63:
64: /*
65: * If non-null, indicates the presence of a delegate ELContext. When a Standard is constructed from another ELContext,
66: * there is no easy way to get its private context map, therefore delegation is needed.
67: */
68: private ELContext delegate;
69:
70: /**
71: * A bean repository local to this context
72: */
73: private Map<String, Object> beans = new HashMap<>();
74:
75: /**
76: * Construct a default ELContext for a stand-alone environment.
77: *
78: * @param factory The ExpressionFactory
79: */
80: public StandardELContext(ExpressionFactory factory) {
81: streamELResolver = factory.getStreamELResolver();
82: initFunctionMap = factory.getInitFunctionMap();
83: }
84:
85: /**
86: * Construct a StandardELContext from another ELContext.
87: *
88: * @param context The ELContext that acts as a delegate in most cases
89: */
90: public StandardELContext(ELContext context) {
91: delegate = context;
92:
93: // Copy all attributes except map and resolved
94: CompositeELResolver compositeELResolver = new CompositeELResolver();
95: compositeELResolver.add(new BeanNameELResolver(new LocalBeanNameResolver()));
96: customResolvers = new CompositeELResolver();
97:
98: compositeELResolver.add(customResolvers);
99: compositeELResolver.add(context.getELResolver());
100: elResolver = compositeELResolver;
101:
102: functionMapper = context.getFunctionMapper();
103: variableMapper = context.getVariableMapper();
104: setLocale(context.getLocale());
105: }
106:
107: @Override
108: public void putContext(Class<?> key, Object contextObject) {
109: if (delegate != null) {
110: delegate.putContext(key, contextObject);
111: } else {
112: super.putContext(key, contextObject);
113: }
114: }
115:
116: @Override
117: public Object getContext(Class<?> key) {
118: if (delegate == null) {
119: return super.getContext(key);
120: }
121:
122: return delegate.getContext(key);
123: }
124:
125: /**
126: * Construct (if needed) and return a default ELResolver.
127: *
128: * <p>
129: * Retrieves the <code>ELResolver</code> associated with this context. This is a <code>CompositeELResover</code>
130: * consists of an ordered list of <code>ELResolver</code>s.
131: *
132: * <ol>
133: * <li>A {@link BeanNameELResolver} for beans defined locally</li>
134: * <li>Any custom <code>ELResolver</code>s</li>
135: * <li>An <code>ELResolver</code> supporting the collection operations</li>
136: * <li>A {@link StaticFieldELResolver} for resolving static fields</li>
137: * <li>A {@link MapELResolver} for resolving Map properties</li>
138: * <li>A {@link ResourceBundleELResolver} for resolving ResourceBundle properties</li>
139: * <li>A {@link ListELResolver} for resolving List properties</li>
140: * <li>An {@link ArrayELResolver} for resolving array properties</li>
141: * <li>A {@link BeanELResolver} for resolving bean properties</li>
142: * </ol>
143: *
144: * @return The ELResolver for this context.
145: */
146: @Override
147: public ELResolver getELResolver() {
148: if (elResolver == null) {
149: CompositeELResolver resolver = new CompositeELResolver();
150: resolver.add(new BeanNameELResolver(new LocalBeanNameResolver()));
151: customResolvers = new CompositeELResolver();
152: resolver.add(customResolvers);
153: if (streamELResolver != null) {
154: resolver.add(streamELResolver);
155: }
156: resolver.add(new StaticFieldELResolver());
157: resolver.add(new MapELResolver());
158: resolver.add(new ResourceBundleELResolver());
159: resolver.add(new ListELResolver());
160: resolver.add(new ArrayELResolver());
161: resolver.add(new BeanELResolver());
162: elResolver = resolver;
163: }
164:
165: return elResolver;
166: }
167:
168: /**
169: * Add a custom ELResolver to the context. The list of the custom ELResolvers will be accessed in the order they are
170: * added. A custom ELResolver added to the context cannot be removed.
171: *
172: * @param cELResolver The new ELResolver to be added to the context
173: */
174: public void addELResolver(ELResolver cELResolver) {
175: getELResolver(); // make sure elResolver is constructed
176: customResolvers.add(cELResolver);
177: }
178:
179: /**
180: * Get the local bean repository
181: *
182: * @return the bean repository
183: */
184: Map<String, Object> getBeans() {
185: return beans;
186: }
187:
188: /**
189: * Construct (if needed) and return a default FunctionMapper.
190: *
191: * @return The default FunctionMapper
192: */
193: @Override
194: public FunctionMapper getFunctionMapper() {
195: if (functionMapper == null) {
196: functionMapper = new DefaultFunctionMapper(initFunctionMap);
197: }
198:
199: return functionMapper;
200: }
201:
202: /**
203: * Construct (if needed) and return a default VariableMapper() {
204: *
205: * @return The default Variable
206: */
207: @Override
208: public VariableMapper getVariableMapper() {
209: if (variableMapper == null) {
210: variableMapper = new DefaultVariableMapper();
211: }
212:
213: return variableMapper;
214: }
215:
216: private static class DefaultFunctionMapper extends FunctionMapper {
217:
218: private Map<String, Method> functions;
219:
220: DefaultFunctionMapper(Map<String, Method> initMap) {
221: functions = (initMap == null) ? new HashMap<>() : new HashMap<>(initMap);
222: }
223:
224: @Override
225: public Method resolveFunction(String prefix, String localName) {
226: return functions.get(prefix + ":" + localName);
227: }
228:
229: @Override
230: public void mapFunction(String prefix, String localName, Method meth) {
231: functions.put(prefix + ":" + localName, meth);
232: }
233: }
234:
235: private static class DefaultVariableMapper extends VariableMapper {
236:
237: private Map<String, ValueExpression> variables;
238:
239: @Override
240: public ValueExpression resolveVariable(String variable) {
241: if (variables == null) {
242: return null;
243: }
244:
245: return variables.get(variable);
246: }
247:
248: @Override
249: public ValueExpression setVariable(String variable, ValueExpression expression) {
250: if (variables == null) {
251: variables = new HashMap<>();
252: }
253:
254: ValueExpression prev = null;
255: if (expression == null) {
256: prev = variables.remove(variable);
257: } else {
258: prev = variables.put(variable, expression);
259: }
260:
261: return prev;
262: }
263: }
264:
265: private class LocalBeanNameResolver extends BeanNameResolver {
266:
267: @Override
268: public boolean isNameResolved(String beanName) {
269: return beans.containsKey(beanName);
270: }
271:
272: @Override
273: public Object getBean(String beanName) {
274: return beans.get(beanName);
275: }
276:
277: @Override
278: public void setBeanValue(String beanName, Object value) {
279: beans.put(beanName, value);
280: }
281:
282: @Override
283: public boolean isReadOnly(String beanName) {
284: return false;
285: }
286:
287: @Override
288: public boolean canCreateBean(String beanName) {
289: return true;
290: }
291: }
292: }