This repository was archived by the owner on Jan 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathELContext.java
More file actions
482 lines (449 loc) · 17.6 KB
/
ELContext.java
File metadata and controls
482 lines (449 loc) · 17.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.el;
import java.util.Map;
import java.util.Stack;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Locale;
/**
* Context information for expression parsing and evaluation.
*
* <p>To parse or evaluate an {@link Expression}, an <code>ELContext</code>
* must be provided. The <code>ELContext</code> holds:
* <ul>
* <li>a reference to {@link FunctionMapper} that will be used
* to resolve EL Functions. This is used only in parsing.</li>
* <li>a reference to {@link VariableMapper} that will be used
* to resolve EL Variables. This is used only in parsing.</li>
* <li>a reference to the base {@link ELResolver} that will be consulted
* to resolve model objects and their properties</li>
* <li>a collection of all the relevant context objects for use by
* <code>ELResolver</code>s</li>
* <li>state information during the evaluation of an expression, such as
* whether a property has been resolved yet</li>
* <li>a reference to {@link ImportHandler} that will be consulted to
* resolve classes that have been imported</li>
* <li>a reference to the arguments for the active {@link LambdaExpression}s</li>
* <li>a reference to the list of registered evaluation listeners</li>
* </ul></p>
*
* <p>The collection of context objects is necessary because each
* <code>ELResolver</code> may need access to a different context object.
* For example, JSP and Faces resolvers need access to a
* {@link javax.servlet.jsp.JspContext} and a
* {@link javax.faces.context.FacesContext}, respectively.</p>
*
* <p>When used in a web container, the creation of
* <code>ELContext</code> objects is controlled through
* the underlying technology. For example, in JSP the
* <code>JspContext.getELContext()</code> factory method is used.
* Some technologies provide the ability to add an {@link ELContextListener}
* so that applications and frameworks can ensure their own context objects
* are attached to any newly created <code>ELContext</code>.</p>
*
* <p>When used in a stand-alone environment, {@link StandardELContext}
* provides a default <code>ELContext</code>, which is managed and modified
* by {@link ELManager}.
*
* <p>Because it stores state during expression evaluation, an
* <code>ELContext</code> object is not thread-safe. Care should be taken
* to never share an <code>ELContext</code> instance between two or more
* threads.</p>
*
* @see ELContextListener
* @see ELContextEvent
* @see ELResolver
* @see FunctionMapper
* @see VariableMapper
* @see ImportHandler
* @see LambdaExpression
* @see StandardELContext
* @see javax.servlet.jsp.JspContext
* @since EL 2.1 and EL 3.0
*/
public abstract class ELContext {
/**
* Called to indicate that a <code>ELResolver</code> has successfully
* resolved a given (base, property) pair.
* Use {@link #setPropertyResolved(Object, Object)} if
* resolved is true and to notify {@link EvaluationListener}s.
*
* <p>The {@link CompositeELResolver} checks this property to determine
* whether it should consider or skip other component resolvers.</p>
*
* @see CompositeELResolver
* @param resolved true if the property has been resolved, or false if
* not.
*/
public void setPropertyResolved(boolean resolved) {
this.resolved = resolved;
}
/**
* Called to indicate that a <code>ELResolver</code> has successfully
* resolved a given (base, property) pair and to notify the
* {@link EvaluationListener}s.
*
* <p>The {@link CompositeELResolver} checks this property to determine
* whether it should consider or skip other component resolvers.</p>
*
* @see CompositeELResolver
* @param base The base object
* @param property The property object
*
* @since EL 3.0
*/
public void setPropertyResolved(Object base, Object property) {
setPropertyResolved(true); // Don't set the variable here, for 2.2 users
// ELContext may be overridden or delegated.
notifyPropertyResolved(base, property);
}
/**
* Returns whether an {@link ELResolver} has successfully resolved a
* given (base, property) pair.
*
* <p>The {@link CompositeELResolver} checks this property to determine
* whether it should consider or skip other component resolvers.</p>
*
* @see CompositeELResolver
* @return true if the property has been resolved, or false if not.
*/
public boolean isPropertyResolved() {
return resolved;
}
/**
* Associates a context object with this <code>ELContext</code>.
*
* <p>The <code>ELContext</code> maintains a collection of context objects
* relevant to the evaluation of an expression. These context objects
* are used by <code>ELResolver</code>s. This method is used to
* add a context object to that collection.</p>
*
* <p>By convention, the <code>contextObject</code> will be of the
* type specified by the <code>key</code>. However, this is not
* required and the key is used strictly as a unique identifier.</p>
*
* @param key The key used by an @{link ELResolver} to identify this
* context object.
* @param contextObject The context object to add to the collection.
* @throws NullPointerException if key is null or contextObject is null.
*/
public void putContext(Class key, Object contextObject) {
if((key == null) || (contextObject == null)) {
throw new NullPointerException();
}
map.put(key, contextObject);
}
/**
* Returns the context object associated with the given key.
*
* <p>The <code>ELContext</code> maintains a collection of context objects
* relevant to the evaluation of an expression. These context objects
* are used by <code>ELResolver</code>s. This method is used to
* retrieve the context with the given key from the collection.</p>
*
* <p>By convention, the object returned will be of the type specified by
* the <code>key</code>. However, this is not required and the key is
* used strictly as a unique identifier.</p>
*
* @param key The unique identifier that was used to associate the
* context object with this <code>ELContext</code>.
* @return The context object associated with the given key, or null
* if no such context was found.
* @throws NullPointerException if key is null.
*/
public Object getContext(Class key) {
if(key == null) {
throw new NullPointerException();
}
return map.get(key);
}
/**
* Retrieves the <code>ELResolver</code> associated with this context.
*
* <p>The <code>ELContext</code> maintains a reference to the
* <code>ELResolver</code> that will be consulted to resolve variables
* and properties during an expression evaluation. This method
* retrieves the reference to the resolver.</p>
*
* <p>Once an <code>ELContext</code> is constructed, the reference to the
* <code>ELResolver</code> associated with the context cannot be changed.</p>
*
* @return The resolver to be consulted for variable and
* property resolution during expression evaluation.
*/
public abstract ELResolver getELResolver();
/**
* Retrieves the <code>ImportHandler</code> associated with this
* <code>ELContext</code>.
*
* @return The import handler to manage imports of classes and packages.
* @since EL 3.0
*/
public ImportHandler getImportHandler() {
if (importHandler == null) {
importHandler = new ImportHandler();
}
return importHandler;
}
/**
* Retrieves the <code>FunctionMapper</code> associated with this
* <code>ELContext</code>.
*
* @return The function mapper to be consulted for the resolution of
* EL functions.
*/
public abstract FunctionMapper getFunctionMapper();
/**
* Holds value of property locale.
*/
private Locale locale;
/**
* Get the <code>Locale</code> stored by a previous invocation to
* {@link #setLocale}. If this method returns non <code>null</code>,
* this <code>Locale</code> must be used for all localization needs
* in the implementation. The <code>Locale</code> must not be cached
* to allow for applications that change <code>Locale</code> dynamically.
*
* @return The <code>Locale</code> in which this instance is operating.
* Used primarily for message localization.
*/
public Locale getLocale() {
return this.locale;
}
/**
* Sets the <code>Locale</code> for this instance. This method may be
* called by the party creating the instance, such as JavaServer
* Faces or JSP, to enable the EL implementation to provide localized
* messages to the user. If no <code>Locale</code> is set, the implementation
* must use the locale returned by <code>Locale.getDefault( )</code>.
*/
public void setLocale(Locale locale) {
this.locale = locale;
}
/**
* Retrieves the <code>VariableMapper</code> associated with this
* <code>ELContext</code>.
*
* @return The variable mapper to be consulted for the resolution of
* EL variables.
*/
public abstract VariableMapper getVariableMapper();
/**
* Registers an evaluation listener to the ELContext.
*
* @param listener The listener to be added.
*
* @since EL 3.0
*/
public void addEvaluationListener(EvaluationListener listener) {
if (listeners == null) {
listeners = new ArrayList<EvaluationListener>();
}
listeners.add(listener);
}
/**
* Returns the list of registered evaluation listeners.
* @return The list of registered evaluation listeners.
*
* @since EL 3.0
*/
public List<EvaluationListener> getEvaluationListeners() {
return listeners;
}
/**
* Notifies the listeners before an EL expression is evaluated
* @param expr The EL expression string to be evaluated
*/
public void notifyBeforeEvaluation(String expr) {
if (getEvaluationListeners() == null)
return;
for (EvaluationListener listener: getEvaluationListeners()) {
listener.beforeEvaluation(this, expr);
}
}
/**
* Notifies the listeners after an EL expression is evaluated
* @param expr The EL expression string that has been evaluated
*/
public void notifyAfterEvaluation(String expr) {
if (getEvaluationListeners() == null)
return;
for (EvaluationListener listener: getEvaluationListeners()) {
listener.afterEvaluation(this, expr);
}
}
/**
* Notifies the listeners when the (base, property) pair is resolved
* @param base The base object
* @param property The property Object
*/
public void notifyPropertyResolved(Object base, Object property) {
if (getEvaluationListeners() == null)
return;
for (EvaluationListener listener: getEvaluationListeners()) {
listener.propertyResolved(this, base, property);
}
}
/**
* Inquires if the name is a LambdaArgument
* @param arg A possible Lambda formal parameter name
* @return true if arg is a LambdaArgument, false otherwise.
*/
public boolean isLambdaArgument(String arg) {
if (lambdaArgs == null) {
return false;
}
for (int i = lambdaArgs.size() - 1; i >= 0; i--) {
Map<String, Object> lmap = lambdaArgs.elementAt(i);
if (lmap.containsKey(arg)) {
return true;
}
}
return false;
}
/**
* Retrieves the Lambda argument associated with a formal parameter.
* If the Lambda expression is nested within other Lambda expressions, the
* arguments for the current Lambda expression is first searched, and if
* not found, the arguments for the immediate nesting Lambda expression
* then searched, and so on.
*
* @param arg The formal parameter for the Lambda argument
* @return The object associated with formal parameter. Null if
* no object has been associated with the parameter.
* @since EL 3.0
*/
public Object getLambdaArgument(String arg) {
if (lambdaArgs == null) {
return null;
}
for (int i = lambdaArgs.size() - 1; i >= 0; i--) {
Map<String, Object> lmap = lambdaArgs.elementAt(i);
Object v = lmap.get(arg);
if (v != null) {
return v;
}
}
return null;
}
/**
* Installs a Lambda argument map, in preparation for the evaluation
* of a Lambda expression. The arguments in the map will be in scope
* during the evaluation of the Lambda expression.
* @param args The Lambda arguments map
* @since EL 3.0
*/
public void enterLambdaScope(Map<String,Object> args) {
if (lambdaArgs == null) {
lambdaArgs = new Stack<Map<String,Object>>();
}
lambdaArgs.push(args);
}
/**
* Exits the Lambda expression evaluation. The Lambda argument map that
* was previously installed is removed.
* @since EL 3.0
*/
public void exitLambdaScope() {
if (lambdaArgs != null) {
lambdaArgs.pop();
}
}
/**
* Converts an object to a specific type. If a custom converter in the
* <code>ELResolver</code> handles this conversion, it is used. Otherwise
* the standard coercions is applied.
*
* <p>An <code>ELException</code> is thrown if an error occurs during
* the conversion.</p>
*
* @param obj The object to convert.
* @param targetType The target type for the conversion.
* @throws ELException thrown if errors occur.
*
* @since EL 3.0
*/
public Object convertToType(Object obj,
Class<?> targetType) {
boolean propertyResolvedSave = isPropertyResolved();
try {
setPropertyResolved(false);
ELResolver elResolver = getELResolver();
if (elResolver != null) {
Object res = elResolver.convertToType(this, obj, targetType);
if (isPropertyResolved()) {
return res;
}
}
} catch (ELException ex) {
throw ex;
} catch (Exception ex) {
throw new ELException(ex);
} finally {
setPropertyResolved(propertyResolvedSave);
}
return ELUtil.getExpressionFactory().coerceToType(obj, targetType);
}
private boolean resolved;
private HashMap<Class<?>, Object> map = new HashMap<Class<?>, Object>();
private transient List<EvaluationListener> listeners = null;
private Stack<Map<String,Object>> lambdaArgs;
private ImportHandler importHandler;
}