View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jexl3;
19  
20  import java.nio.charset.Charset;
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Map;
24  import java.util.function.IntFunction;
25  import java.util.function.Supplier;
26  
27  import org.apache.commons.jexl3.internal.Engine;
28  import org.apache.commons.jexl3.internal.SoftCache;
29  import org.apache.commons.jexl3.introspection.JexlPermissions;
30  import org.apache.commons.jexl3.introspection.JexlSandbox;
31  import org.apache.commons.jexl3.introspection.JexlUberspect;
32  import org.apache.commons.jexl3.parser.JexlScriptParser;
33  import org.apache.commons.logging.Log;
34  
35  /**
36   * Configures and builds a JexlEngine.
37   *
38   * <p>
39   *     The builder allow fine-tuning an engine instance behavior according to various control needs.
40   *     Check <em>{@link #JexlBuilder()}</em> for permission impacts starting with <em>JEXL 3.3</em>.
41   * </p><p>
42   *     Broad configurations elements are controlled through the features ({@link JexlFeatures}) that can restrict JEXL
43   *  syntax - for instance, only expressions with no-side effects - and permissions ({@link JexlPermissions}) that control
44   *  the visible set of objects - for instance, avoiding access to any object in java.rmi.* -.
45   *  </p><p>
46   *     Fine error control and runtime-overridable behaviors are implemented through options ({@link JexlOptions}). Most
47   * common flags accessible from the builder are reflected in its options ({@link #options()}).
48   * </p><p>
49   *     The {@code silent} flag tells the engine what to do with the error; when true, errors are logged as
50   * warning, when false, they throw {@link JexlException} exceptions.
51   * </p><p>
52   *     The {@code strict} flag tells the engine when and if null as operand is considered an error. The {@code safe}
53   * flog determines if safe-navigation is used. Safe-navigation allows an  evaluation shortcut and return null in expressions
54   * that attempts dereferencing null, typically a method call or accessing a property.
55   * </p><p>
56   *     The {@code lexical} and {@code lexicalShade} flags can be used to enforce a lexical scope for
57   * variables and parameters. The {@code lexicalShade} can be used to further ensure no global variable can be
58   * used with the same name as a local one even after it goes out of scope. The corresponding feature flags should be
59   * preferred since they will detect violations at parsing time. (see {@link JexlFeatures})
60   * </p><p>
61   *     The following rules apply on silent and strict flags:
62   * </p>
63   * <ul>
64   * <li>When "silent" &amp; "not-strict":
65   * <p> 0 &amp; null should be indicators of "default" values so that even in an case of error,
66   * something meaningful can still be inferred; may be convenient for configurations.
67   * </p>
68   * </li>
69   * <li>When "silent" &amp; "strict":
70   * <p>One should probably consider using null as an error case - ie, every object
71   * manipulated by JEXL should be valued; the ternary operator, especially the '?:' form
72   * can be used to workaround exceptional cases.
73   * Use case could be configuration with no implicit values or defaults.
74   * </p>
75   * </li>
76   * <li>When "not-silent" &amp; "not-strict":
77   * <p>The error control grain is roughly on par with JEXL 1.0</p>
78   * </li>
79   * <li>When "not-silent" &amp; "strict":
80   * <p>The finest error control grain is obtained; it is the closest to Java code -
81   * still augmented by "script" capabilities regarding automated conversions and type matching.
82   * </p>
83   * </li>
84   * </ul>
85   */
86  public class JexlBuilder {
87  
88      /**
89       * The set of default permissions used when creating a new builder.
90       * <p>Static but modifiable, so these default permissions can be changed to a purposeful set.</p>
91       * <p>In JEXL 3.7, these are {@link JexlPermissions#SECURE}.</p>
92       * <p>In JEXL 3.3, these were {@link JexlPermissions#RESTRICTED}.</p>
93       * <p>In JEXL 3.2, these were equivalent to {@link JexlPermissions#UNRESTRICTED}.</p>
94       */
95      private static JexlPermissions PERMISSIONS = JexlPermissions.SECURE;
96  
97      /**
98       * The full feature set that was the implicit default before JEXL 3.7.
99       * <p>This captures {@link JexlFeatures#createDefault()} - the feature set the engine used as its
100      * fallback throughout 3.x (since 3.3) before the 3.7 hardening. It enables {@code new(...)}, loops,
101      * side-effects, lambdas, method calls, structured literals, pragmas, etc. Use it (or
102      * {@link #setDefaultFeatures(JexlFeatures)}) to restore pre-3.7 behavior:</p>
103      * <pre>
104      * JexlEngine jexl = new JexlBuilder().features(JexlBuilder.FULL).create();
105      * </pre>
106      * <p>{@link JexlFeatures} instances are mutable; copy this one via {@code new JexlFeatures(JexlBuilder.FULL)}
107      * before customizing it rather than mutating the shared instance.</p>
108      *
109      * @since 3.7.0
110      */
111     public static final JexlFeatures FULL = JexlFeatures.createDefault();
112 
113     /**
114      * The set of default features used when creating a new builder.
115      * <p>Static but modifiable via {@link #setDefaultFeatures(JexlFeatures)}.</p>
116      * <p>In JEXL 3.7, the default hardens the feature set relative to {@link #FULL}: {@code new(...)},
117      * global side-effects, pragmas, and annotations are disabled, and lexical scoping (with shade) is
118      * enabled.  Loops remain available to scripts (expressions never allow them).  Scripts using a
119      * disabled construct will throw {@link JexlException.Feature} at parse time.</p>
120      *
121      * @see #secureFeatures()
122      */
123     private static JexlFeatures FEATURES = secureFeatures();
124 
125     /** The default maximum expression length to hit the expression cache. */
126     protected static final int CACHE_THRESHOLD = 64;
127 
128     /**
129      * Sets the default permissions.
130      *
131      * @param permissions The permissions
132      */
133     public static void setDefaultPermissions(final JexlPermissions permissions) {
134         PERMISSIONS = permissions == null ? JexlPermissions.SECURE : permissions;
135     }
136 
137     /**
138      * Sets the default features used when creating a new builder.
139      * <p>Passing {@code null} restores the 3.7 hardened default (new-instance, global side-effects,
140      * pragmas, and annotations disabled, lexical scoping enabled; see {@link #secureFeatures()}).</p>
141      *
142      * @param features The features, or {@code null} to restore the hardened default
143      * @since 3.7.0
144      */
145     public static void setDefaultFeatures(final JexlFeatures features) {
146         FEATURES = features == null ? secureFeatures() : features;
147     }
148 
149     /**
150      * Sets the default option flags used when creating a new engine.
151      * <p>Delegates to {@link JexlOptions#setDefaultFlags(String...)}; see that method for the
152      * flag-name syntax ({@code "+flag"}/{@code "-flag"}) and the available flag names
153      * ({@code cancellable}, {@code strict}, {@code silent}, {@code safe}, {@code lexical},
154      * {@code antish}, {@code lexicalShade}, ...).</p>
155      * <p>Example: restore safe/antish defaults before creating any engine:</p>
156      * <pre>JexlBuilder.setDefaultOptions("+safe", "+antish");</pre>
157      *
158      * @param flags The flags to set or clear
159      * @since 3.7.0
160      */
161     public static void setDefaultOptions(final String... flags) {
162         JexlOptions.setDefaultFlags(flags);
163     }
164 
165     /**
166      * Builds the JEXL 3.7 hardened default feature set.
167      * <p>Starting from {@link #FULL} (the pre-3.7 feature set), this disables {@code new(...)},
168      * global side-effects, pragmas, annotations, namespace instantiation, and enables lexical scoping and lexical shade.
169      * Loops are left enabled so scripts can iterate; expressions never allow loops since they are
170      * parsed as a single expression.</p>
171      *
172      * @return A fresh hardened feature set
173      * @since 3.7.0
174      */
175     private static JexlFeatures secureFeatures() {
176         return new JexlFeatures(FULL)
177             .newInstance(false)
178             .sideEffectGlobal(false)
179             .pragma(false)
180             .annotation(false)
181             .loops(true)
182             .lexical(true)
183             .lexicalShade(true)
184             .namespaceInstantiation(false);
185     }
186 
187     /** The JexlUberspect instance. */
188     private JexlUberspect uberspect;
189 
190     /** The {@link JexlUberspect} resolver strategy. */
191     private JexlUberspect.ResolverStrategy strategy;
192 
193     /** The set of permissions. */
194     private JexlPermissions permissions;
195 
196     /** The sandbox. */
197     private JexlSandbox sandbox;
198 
199     /** The Log to which all JexlEngine messages will be logged. */
200     private Log logger;
201 
202     /** Whether error messages will carry debugging information. */
203     private Boolean debug;
204 
205     /** Whether interrupt throws JexlException.Cancel. */
206     private Boolean cancellable;
207 
208     /** The options. */
209     private final JexlOptions options = new JexlOptions();
210 
211     /** Whether getVariables considers all potential equivalent syntactic forms. */
212     private int collectMode = 1;
213 
214     /** The {@link JexlArithmetic} instance. */
215     private JexlArithmetic arithmetic;
216 
217     /** The cache size. */
218     private int cache = -1;
219 
220     /** The cache class factory. */
221     private IntFunction<JexlCache<?,?>> cacheFactory = SoftCache::new;
222 
223    /** The parser class factory. */
224    private Supplier<JexlScriptParser> parserFactory;
225 
226     /** The stack overflow limit. */
227     private int stackOverflow = Integer.MAX_VALUE;
228 
229     /** The maximum expression length to hit the expression cache. */
230     private int cacheThreshold = CACHE_THRESHOLD;
231 
232     /** The charset. */
233     private Charset charset = Charset.defaultCharset();
234 
235     /** The class loader. */
236     private ClassLoader loader;
237 
238     /** The features. */
239     private JexlFeatures features;
240 
241     /**
242      * Default constructor.
243      * <p>
244      * As of JEXL 3.3, to reduce the security risks inherent to JEXL&quot;s purpose, the builder will use a set of
245      * restricted permissions as a default to create the {@link JexlEngine} instance. This will greatly reduce which classes
246      * and methods are visible to JEXL and usable in scripts using default implicit behaviors.
247      * </p><p>
248      * However, without mitigation, this change will likely break some scripts at runtime, especially those exposing
249      * your own class instances through arguments, contexts, or namespaces.
250      * The default set of allowed packages and denied classes is described by {@link JexlPermissions#SECURE}
251      * as of JEXL 3.7 (previously {@link JexlPermissions#RESTRICTED} since 3.3).
252      * </p><p>
253      * As of JEXL 3.7, the default features also disable {@code new(...)}, global side-effects, pragmas,
254      * and annotations, and enable lexical scoping; loops remain available to scripts (but never to
255      * expressions). Scripts using a disabled construct will throw {@link JexlException.Feature} at parse
256      * time unless a permissive feature set is configured.
257      * </p><p>
258      * The recommended mitigation if your usage of JEXL is impacted is to load a {@code jexl.yaml}
259      * configuration via {@link JexlConfigLoader} that restores the legacy permissions and features,
260      * or to explicitly configure them via {@link #permissions(JexlPermissions)} and
261      * {@link #features(JexlFeatures)}. Use {@link JexlPermissions#logging()} to discover which
262      * reflective elements the new algorithm denies.
263      * </p><p>
264      * Note that an explicit call to {@link #uberspect(JexlUberspect)} will supersede any permissions related behavior
265      * by using the {@link JexlUberspect} provided as argument used as-is in the created {@link JexlEngine}.
266      * </p>
267      *
268      * @since 3.3
269      */
270     public JexlBuilder() {
271         this.permissions = PERMISSIONS;
272         this.features = FEATURES == null ? null : new JexlFeatures(FEATURES);
273     }
274 
275     /**
276      * Is antish resolution enabled?
277      *
278      * @return whether antish resolution is enabled
279      */
280     public boolean antish() {
281         return options.isAntish();
282     }
283 
284     /**
285      * Sets whether the engine will resolve antish variable names.
286      *
287      * @param flag true means antish resolution is enabled, false disables it
288      * @return this builder
289      */
290     public JexlBuilder antish(final boolean flag) {
291         options.setAntish(flag);
292         return this;
293     }
294 
295     /**
296      * Gets the JexlArithmetic instance the engine will use.
297      *
298      * @return The arithmetic
299      */
300     public JexlArithmetic arithmetic() {
301         return this.arithmetic;
302     }
303 
304     /**
305      * Sets the JexlArithmetic instance the engine will use.
306      *
307      * @param a The arithmetic
308      * @return this builder
309      */
310     public JexlBuilder arithmetic(final JexlArithmetic a) {
311         this.arithmetic = a;
312         options.setStrictArithmetic(a.isStrict());
313         options.setMathContext(a.getMathContext());
314         options.setMathScale(a.getMathScale());
315         return this;
316     }
317 
318     /**
319      * Sets whether logical expressions (&quot;&quot; , ||) coerce their result to boolean.
320      *
321      * @param flag true or false
322      * @return this builder
323      */
324     public JexlBuilder booleanLogical(final boolean flag) {
325       options.setBooleanLogical(flag);
326       return this;
327     }
328 
329     /**
330      * Gets the expression cache size the engine will use.
331      *
332      * @return The cache size
333      */
334     public int cache() {
335       return cache;
336     }
337 
338     /**
339      * Sets the expression cache size the engine will use.
340      * <p>The cache will contain at most {@code size} expressions of at most {@code cacheThreshold} length.
341      * Note that all JEXL caches are held through SoftReferences and may be garbage-collected.</p>
342      *
343      * @param size if not strictly positive, no cache is used.
344      * @return this builder
345      */
346     public JexlBuilder cache(final int size) {
347         this.cache = size;
348         return this;
349     }
350 
351     /**
352      * Gets the expression-cache factory the engine will use.
353      *
354      * @return The cache factory
355      */
356     public IntFunction<JexlCache<?, ?>> cacheFactory() {
357       return this.cacheFactory;
358     }
359 
360     /**
361      * Sets the expression-cache factory the engine will use.
362      *
363      * @param factory The function to produce a cache.
364      * @return this builder
365      */
366     public JexlBuilder cacheFactory(final IntFunction<JexlCache<?, ?>> factory) {
367       this.cacheFactory = factory;
368       return this;
369     }
370 
371   /**
372    * Gets the Jexl script parser factory the engine will use.
373    *
374    * @return The cache factory
375    * @since 3.5.0
376    */
377   public Supplier<JexlScriptParser> parserFactory() {
378     return this.parserFactory;
379   }
380 
381   /**
382    * Sets the Jexl script parser factory the engine will use.
383    *
384    * @param factory The function to produce a cache.
385    * @return this builder
386    * @since 3.5.0
387    */
388     public JexlBuilder parserFactory(final Supplier<JexlScriptParser> factory) {
389       this.parserFactory = factory;
390       return this;
391     }
392 
393     /**
394      * Gets the maximum length for an expression to be cached.
395      *
396      * @return The cache threshold
397      */
398     public int cacheThreshold() {
399         return cacheThreshold;
400     }
401 
402     /**
403      * Sets the maximum length for an expression to be cached.
404      * <p>Expression whose length is greater than this expression cache length threshold will
405      * bypass the cache.</p>
406      * <p>It is expected that a "long" script will be parsed once and its reference kept
407      * around in user-space structures; the jexl expression cache has no added-value in this case.</p>
408      *
409      * @param length if not strictly positive, the value is silently replaced by the default value (64).
410      * @return this builder
411      */
412     public JexlBuilder cacheThreshold(final int length) {
413         this.cacheThreshold = length > 0? length : CACHE_THRESHOLD;
414         return this;
415     }
416 
417     /**
418      * Gets the cancellable information flag
419      *
420      * @return The cancellable information flag
421      * @since 3.1
422      */
423     public Boolean cancellable() {
424         return this.cancellable;
425     }
426 
427     /**
428      * Sets the engine behavior upon interruption: throw an JexlException.Cancel or terminates the current evaluation
429      * and return null.
430      *
431      * @param flag true implies the engine throws the exception, false makes the engine return null.
432      * @return this builder
433      * @since 3.1
434      */
435     public JexlBuilder cancellable(final boolean flag) {
436         this.cancellable = flag;
437         options.setCancellable(flag);
438         return this;
439     }
440 
441     /**
442      * Gets the charset
443      *
444      * @return The charset
445      */
446     public Charset charset() {
447         return charset;
448     }
449 
450     /**
451      * Sets the charset to use.
452      *
453      * @param arg The charset
454      * @return this builder
455      * @since 3.1
456      */
457     public JexlBuilder charset(final Charset arg) {
458         this.charset = arg;
459         return this;
460     }
461 
462     /**
463      * Does the variable collection follow strict syntactic rule?
464      *
465      * @return true if variable collection follows strict syntactic rule
466      * @since 3.2
467      */
468     public boolean collectAll() {
469         return this.collectMode != 0;
470     }
471 
472     /**
473      * Sets whether the engine variable collectors considers all potential forms of variable syntaxes.
474      *
475      * @param flag true means var collections considers constant array accesses equivalent to dotted references
476      * @return this builder
477      * @since 3.2
478      */
479     public JexlBuilder collectAll(final boolean flag) {
480         return collectMode(flag? 1 : 0);
481     }
482 
483     /**
484      * Gets the collection mode.
485      *
486      * @return 0 if variable collection follows strict syntactic rule
487      * @since 3.2
488      */
489     public int collectMode() {
490         return this.collectMode;
491     }
492 
493     /**
494      * Experimental collector mode setter.
495      *
496      * @param mode 0 or 1 as equivalents to false and true, other values are experimental
497      * @return this builder
498      * @since 3.2
499      */
500     public JexlBuilder collectMode(final int mode) {
501         this.collectMode = mode;
502         return this;
503     }
504 
505     /**
506      * Create a new engine
507      *
508      * @return A {@link JexlEngine} instance
509      */
510     public JexlEngine create() {
511         return new Engine(this);
512     }
513 
514     /**
515      * Gets the debug flag.
516      *
517      * @return The debugging information flag
518      */
519     public Boolean debug() {
520         return this.debug;
521     }
522 
523     /**
524      * Sets whether the engine will report debugging information when error occurs.
525      *
526      * @see JexlEngine#isDebug()
527      * @param flag true implies debug is on, false implies debug is off.
528      * @return this builder
529      */
530     public JexlBuilder debug(final boolean flag) {
531         this.debug = flag;
532         return this;
533     }
534 
535     /**
536      * Gets the features the engine will use as a base by default.
537      *
538      * @return The features
539      */
540     public JexlFeatures features() {
541         return this.features;
542     }
543 
544     /**
545      * Sets the features the engine will use as a base by default.
546      * <p>Note that the script flag will be ignored; the engine will be able to parse expressions and scripts.
547      * <p>Note also that these will apply to template expressions and scripts.
548      * <p>As a last remark, if lexical or lexicalShade are set as features, this
549      * method will also set the corresponding options.
550      *
551      * @param f The features
552      * @return this builder
553      */
554     public JexlBuilder features(final JexlFeatures f) {
555         this.features = f;
556         if (features != null) {
557             if (features.isLexical()) {
558                 options.setLexical(true);
559             }
560             if (features.isLexicalShade()) {
561                 options.setLexicalShade(true);
562             }
563         }
564         return this;
565     }
566 
567     /**
568      * Gets the optional set of imported packages.
569      *
570      * @return The set of imports, may be empty, not null
571      */
572     public Collection<String> imports() {
573         return options.getImports();
574     }
575 
576     /**
577      * Sets the optional set of imports.
578      *
579      * @param imports The imported packages
580      * @return this builder
581      */
582     public JexlBuilder imports(final Collection<String> imports) {
583         options.setImports(imports);
584         return this;
585     }
586 
587     /**
588      * Sets the optional set of imports.
589      *
590      * @param imports The imported packages
591      * @return this builder
592      */
593     public JexlBuilder imports(final String... imports) {
594         return imports(Arrays.asList(imports));
595     }
596 
597     /**
598      * Is lexical scope enabled?
599      *
600      * @see JexlOptions#isLexical()
601      * @return whether lexical scope is enabled
602      * @deprecated 3.5.0
603      */
604     @Deprecated
605     public boolean lexical() {
606         return options.isLexical();
607     }
608 
609     /**
610      * Sets whether the engine is in lexical mode.
611      *
612      * @param flag true means lexical function scope is in effect, false implies non-lexical scoping
613      * @return this builder
614      * @since 3.2
615      */
616     public JexlBuilder lexical(final boolean flag) {
617         options.setLexical(flag);
618         return this;
619     }
620 
621     /**
622      * Checks whether lexical shading is enabled.
623      *
624      * @see JexlOptions#isLexicalShade()
625      * @return whether lexical shading is enabled
626      * @deprecated 3.5.0
627      */
628     @Deprecated
629     public boolean lexicalShade() {
630         return options.isLexicalShade();
631     }
632 
633     /**
634      * Sets whether the engine is in lexical shading mode.
635      *
636      * @param flag true means lexical shading is in effect; false implies no lexical shading
637      * @return this builder
638      * @since 3.2
639      */
640     public JexlBuilder lexicalShade(final boolean flag) {
641         options.setLexicalShade(flag);
642         return this;
643     }
644 
645     /**
646      * Gets the classloader
647      *
648      * @return The class loader
649      */
650     public ClassLoader loader() {
651         return loader;
652     }
653 
654     /**
655      * Sets the charset to use.
656      *
657      * @param arg The charset
658      * @return this builder
659      * @deprecated since 3.1 use {@link #charset(Charset)} instead
660      */
661     @Deprecated
662     public JexlBuilder loader(final Charset arg) {
663         return charset(arg);
664     }
665 
666     /**
667      * Sets the class loader to use.
668      *
669      * @param l The class loader
670      * @return this builder
671      */
672     public JexlBuilder loader(final ClassLoader l) {
673         this.loader = l;
674         return this;
675     }
676 
677     /**
678      * Gets the logger
679      *
680      * @return The logger
681      */
682     public Log logger() {
683         return this.logger;
684     }
685 
686     /**
687      * Sets the o.a.c.Log instance to use.
688      *
689      * @param log The logger
690      * @return this builder
691      */
692     public JexlBuilder logger(final Log log) {
693         this.logger = log;
694         return this;
695     }
696 
697     /**
698      * Gets the map of namespaces.
699      *
700      * @return The map of namespaces.
701      */
702     public Map<String, Object> namespaces() {
703         return options.getNamespaces();
704     }
705 
706     /**
707      * Sets the default namespaces map the engine will use.
708      * <p>
709      * Each entry key is used as a prefix, each entry value used as a bean implementing
710      * methods; an expression like 'nsx:method(123)' will thus be solved by looking at
711      * a registered bean named 'nsx' that implements method 'method' in that map.
712      * If all methods are static, you may use the bean class instead of an instance as value.
713      * </p>
714      * <p>
715      * If the entry value is a class that has one constructor taking a JexlContext as argument, an instance
716      * of the namespace will be created at evaluation time. It might be a good idea to derive a JexlContext
717      * to carry the information used by the namespace to avoid variable space pollution and strongly type
718      * the constructor with this specialized JexlContext.
719      * </p>
720      * <p>
721      * The key or prefix allows to retrieve the bean that plays the role of the namespace.
722      * If the prefix is null, the namespace is the top-level namespace allowing to define
723      * top-level user-defined namespaces ( ie: myfunc(...) )
724      * </p>
725      * <p>Note that the JexlContext is also used to try to solve top-level namespaces. This allows ObjectContext
726      * derived instances to call methods on the wrapped object.</p>
727      *
728      * @param ns The map of namespaces
729      * @return this builder
730      */
731     public JexlBuilder namespaces(final Map<String, Object> ns) {
732         options.setNamespaces(ns);
733         return this;
734     }
735 
736     /**
737      * Gets the current set of options
738      *
739      * @return The current set of options
740      */
741     public JexlOptions options() {
742       return options;
743     }
744 
745     /**
746      * Gets the permissions
747      *
748      * @return The permissions
749      */
750     public JexlPermissions permissions() {
751         return this.permissions;
752     }
753 
754     /**
755      * Sets the JexlPermissions instance the engine will use.
756      *
757      * @param p The permissions
758      * @return this builder
759      */
760     public JexlBuilder permissions(final JexlPermissions p) {
761         this.permissions = p;
762         return this;
763     }
764 
765     /**
766      * Is it safe to dereference null?
767      *
768      * @return true if safe, false otherwise
769      */
770     public Boolean safe() {
771         return options.isSafe();
772     }
773 
774     /**
775      * Sets whether the engine considers dereferencing null in navigation expressions
776      * as null or triggers an error.
777      * <p>{@code x.y()} if x is null throws an exception when not safe,
778      * return null and warns if it is.</p>
779      * <p>It is recommended to use <em>safe(false)</em> as an explicit default.</p>
780      *
781      * @param flag true means safe navigation, false throws exception when dereferencing null
782      * @return this builder
783      */
784     public JexlBuilder safe(final boolean flag) {
785         options.setSafe(flag);
786         return this;
787     }
788 
789     /**
790      * Gets the sandbox
791      *
792      * @return The sandbox
793      */
794     public JexlSandbox sandbox() {
795         return this.sandbox;
796     }
797 
798     /**
799      * Sets the sandbox the engine will use.
800      *
801      * @param box The sandbox
802      * @return this builder
803      */
804     public JexlBuilder sandbox(final JexlSandbox box) {
805         this.sandbox = box;
806         return this;
807     }
808 
809     /**
810      * Is error handling silent?
811      *
812      * @return The silent error handling flag
813      */
814     public Boolean silent() {
815         return options.isSilent();
816     }
817 
818     /**
819      * Sets whether the engine will throw JexlException during evaluation when an error is triggered.
820      * <p>When <em>not</em> silent, the engine throws an exception when the evaluation triggers an exception or an
821      * error.</p>
822      * <p>It is recommended to use <em>silent(false)</em> as an explicit default.</p>
823      *
824      * @param flag true means no JexlException will occur, false allows them
825      * @return this builder
826      */
827     public JexlBuilder silent(final boolean flag) {
828         options.setSilent(flag);
829         return this;
830     }
831 
832     /**
833      * Gets the cache size
834      *
835      * @return The cache size
836      */
837     public int stackOverflow() {
838         return stackOverflow;
839     }
840 
841     /**
842      * Sets the number of script/expression evaluations that can be stacked.
843      *
844      * @param size if not strictly positive, limit is reached when Java StackOverflow is thrown.
845      * @return this builder
846      */
847     public JexlBuilder stackOverflow(final int size) {
848         this.stackOverflow = size;
849         return this;
850     }
851 
852     /**
853      * Gets the JexlUberspect strategy
854      *
855      * @return The JexlUberspect strategy */
856     public JexlUberspect.ResolverStrategy strategy() {
857         return this.strategy;
858     }
859 
860     /**
861      * Sets the JexlUberspect strategy the engine will use.
862      * <p>This is ignored if the uberspect has been set.
863      *
864      * @param rs The strategy
865      * @return this builder
866      */
867     public JexlBuilder strategy(final JexlUberspect.ResolverStrategy rs) {
868         this.strategy = rs;
869         return this;
870     }
871 
872     /**
873      * Is it strict mode?
874      *
875      * @return true if strict, false otherwise */
876     public Boolean strict() {
877         return options.isStrict();
878     }
879 
880     /**
881      * Sets whether the engine considers unknown variables, methods, functions, and constructors as errors or
882      * evaluates them as null.
883      * <p>When <em>not</em> strict, operators or functions using null operands return null on evaluation. When
884      * strict, those raise exceptions.</p>
885      * <p>It is recommended to use <em>strict(true)</em> as an explicit default.</p>
886      *
887      * @param flag true means strict error reporting, false allows them to be evaluated as null
888      * @return this builder
889      */
890     public JexlBuilder strict(final boolean flag) {
891         options.setStrict(flag);
892         return this;
893     }
894 
895     /**
896      * Is interpolation strict?
897      *
898      * @see JexlOptions#setStrictInterpolation(boolean)
899      * @param flag strict interpolation flag
900      * @return this builder
901      */
902     public JexlBuilder strictInterpolation(final boolean flag) {
903         options.setStrictInterpolation(flag);
904         return this;
905     }
906 
907     /**
908      * Gets the uberspect
909      *
910      * @return The uberspect */
911     public JexlUberspect uberspect() {
912         return this.uberspect;
913     }
914 
915     /**
916      * Sets the JexlUberspect instance the engine will use.
917      *
918      * @param u The uberspect
919      * @return this builder
920      */
921     public JexlBuilder uberspect(final JexlUberspect u) {
922         this.uberspect = u;
923         return this;
924     }
925 }