<?xml version="1.0"?>
<!--
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You 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

        https://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.
-->

<document>
  <properties>
    <title>Apache Commons JEXL Examples</title>
  </properties>

  <body>
    <section name="Overview">
      <p>
        In this reference you will find the following topics to help with your use of JEXL.
        <ul>
          <li><a href="#Evaluating Expressions">Evaluating Expressions</a></li>
          <li><a href="#Custom Contexts">Custom Contexts</a></li>
          <li><a href="#Example Expressions">Example Expressions</a></li>
        </ul>
      </p>
      <p>
        You can find two sample programs in JEXL's source repository:
        <ul>
          <li><a href="https://gitbox.apache.org/repos/asf?p=commons-jexl.git;a=blob;f=src/test/java/org/apache/commons/jexl3/examples/ArrayTest.java">Using arrays</a></li>
          <li><a href="https://gitbox.apache.org/repos/asf?p=commons-jexl.git;a=blob;f=src/test/java/org/apache/commons/jexl3/examples/MethodPropertyTest.java">Accessing Properties and invoking methods</a></li>
        </ul>
      </p>
      <p>
        As well, <a href="https://gitbox.apache.org/repos/asf?p=commons-jexl.git;a=blob;f=src/test/java/org/apache/commons/jexl3/JexlTest.java">JEXL's Unit Tests</a>
        provide handy examples of expressions. The test code also contains a
        <a href="https://gitbox.apache.org/repos/asf?p=commons-jexl.git;a=blob;f=src/test/java/org/apache/commons/jexl3/Jexl.java">simple class</a>
        that evaluates its command line arguments as JEXL expressions when run.
      </p>
      <p>
          The <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/package-summary.html#intro">
          package javadoc</a> also contains useful information.
      </p>
    </section>
    <section name="Evaluating Expressions">
      <p>
        To evaluate expressions using JEXL, you need three things:
        <ul>
          <li>An <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlEngine.html">engine</a> to create expressions,</li>
          <li>A <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlContext.html">context</a> containing any variables, and</li>
          <li>An <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlExpression.html">expression</a></li>
        </ul>
      </p>
      <p>
        The common way of using a JEXL engine is to create it as a singleton and use this opportunity to tailor its
        behavior and cache through the jexlBuilder options.
        <source>
            private static final JexlEngine jexl = new JexlBuilder().cache(512).strict(true).silent(false).create();
        </source>
      </p>
      <p>
        The easiest way of obtaining a context is to use the
        <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/MapContext.html#MapContext()">new MapContext()</a>
        statement. This creates a context implemented using an underlying
        <a href="https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html">HashMap</a>
      </p>
      <p>
        <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/Expression.html">Expressions</a> are
        created using the <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlEngine.html#createExpression(java.lang.String)">JexlEngine.createExpression(String)</a>
        method.
      </p>
      <p>
        Once you have your expression, you can then use the
        <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/Expression.html#evaluate(org.apache.commons.jexl3.JexlContext)">evaluate</a>
        to execute it and obtain a result.
      </p>
      <p>
        Here's a typical scenario:
      </p>
      <source>
    // Assuming we have a JexlEngine instance initialized in our class named 'jexl':
    // Create an expression object for our calculation
    String calculateTax = taxManager.getTaxCalc(); //e.g. "((G1 + G2 + G3) * 0.1) + G4";
    Expression e = jexl.createExpression( calculateTax );

    // populate the context
    JexlContext context = new MapContext();
    context.set("G1", businessObject.getTotalSales());
    context.set("G2", taxManager.getTaxCredit(businessObject.getYear()));
    context.set("G3", businessObject.getIntercompanyPayments());
    context.set("G4", -taxManager.getAllowances());
    // ...

    // work it out
    Number result = (Number) e.evaluate(context);
      </source>
    </section>
    <section name="Custom Contexts">
      <p>
        Often you have the objects and values that are needed in the context available
        elsewhere. If those are already in a Map, instead of creating the default context and populating it
        manually in the code, you can wrap a MapContext around your own map using
        <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/MapContext.html#MapContext()">new MapContext(yourOwnMap)</a>
      </p>
      <p>
        In edge cases, it may be simpler to create a context implementation of your
        own.
        The <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlContext.html">JexlContext</a>
        interface is very simple with only three methods, to set, get and check the existence of variables.
      </p>
    </section>
    <section name="Example Expressions">
      <!--  invoking methods, property access, array access, empty, size etc... -->
      <subsection name="Arithmetic">
        <p>Most valid arithmetic expressions in Java are also valid in Jexl.</p>
        <source>
1 + 2
12.0 - 5.2
6 * 12 + 5 / 2.6
12 % 2
6 / 4
-12 + 77.2
x * 1.1 + y
        </source>
        <p>Arithmetic expressions can use variables. <code>null</code> can be treated as a zero for arithmetic;
        if you need stricter semantics and consider <code>null</code> as an erroneous operand for arithmetic and
        comparisons operations, you should initialize your JEXL engine using
        <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlEngine.html#setLenient(boolean)">JexlEngine.setLenient(false)</a>.
        </p>
      </subsection>
      <subsection name="Calling methods">
        <p>
          JEXL allows you to call any method on a Java object using the same syntax.
          If you have a string in the context under the name <code>aString</code>,
          you could call it's <code>length</code>
          method like this:
          <source>
aString.length()
aString.substring(6)
          </source>
        </p>
        <p>
          Often the values you want to pass to a method are other variables or expressions.
          If you have a number in the context, named <code>i</code>, you could use it
          in a method call:
          <source>aString.substring(i)</source>
        </p>
      </subsection>
      <subsection name="Accessing properties">
        <p>
          JEXL provides a shorthand syntax to access methods that
          follow the JavaBean naming convention for properties, i.e.
          setters and getters.
        </p>
        <p>
          If you have some object foo in the context and it has a
          method <code>getBar()</code>, you can call that method using
          the following syntax:
          <source>foo.bar</source>
        </p>
        <p>
          Since <code>java.lang.Object</code> has a <code>getClass()</code> method
          that returns a <code>java.lang.Class</code> object, and the
          class has a <code>getName()</code> method, the following is a shorthand
          for obtaining the class name of an object <code>foo</code> in the context:
          <source>foo.class.name</source>
        </p>
      </subsection>
      <subsection name="Arrays, Lists and Maps">
        <p>
          Array elements can be accessed using either square brackets or a dotted
          index notation, e.g. the following are equivalent
          <source>arr[0]
arr.0</source>
          The same holds true for lists.
        </p>
        <p>
          For a map, the syntax is very similar, except the 'index' is an object, e.g.
          the following are equivalent.
          <source>aMap['key']
aMap.get('key')</source>
          Please note that the index does not have to be a string, and
          that the string usage above is just one possible option.
        </p>
      </subsection>
    </section>
  </body>
</document>
