# FunctionSample.java

    /*
    ** Module   : FunctionSample.java
    ** Abstract : sample for user defined function execution in the Progress
    **            expression evaluator
    **
    ** Copyright (c) 2004-2023, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 GES 20041116 NEW   @18716 First version showing examples of:
    **                               - function w 1 String parm, int return
    **                               - function w null parms, int return
    **                               - static function w 1 String parm, int
    **                                 return
    **                               - int variable
    **                               - command line test driver
    ** 002 GES 20070319 CHG   @32499 Reworked code to match newer expression
    **                               processing implementation.
    ** 003 GBB 20230512              Logging methods replaced by CentralLogger/ConversionStatus.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.uast;

    import com.goldencode.p2j.convert.*;
    import com.goldencode.p2j.util.*;

    import java.util.logging.*;

    /**
     * Provides an example of how to implement user-defined functions and
     * variables while using the standard Progress expression evaluator on a
     * given Progress 4GL expression.
     * <p>
     * This sample shows that all necessary code to implement user-defined
     * functions can be implemented in a single class if desired. The
     * implementation can also be split into multiple files.
     * <p>
     * Steps in the process of implementing user-defined functions:
     * <ul>
     *    <li> Create a static or instance method that implements the function
     *         required. In particular, the parameters and return value must
     *         match one of the supported data types (which map from Java to
     *         Progress 4GL):
     *       <ul>
     *          <li> <code>String</code>
     *          <li> <code>int</code>
     *          <li> <code>double</code>
     *          <li> <code>boolean</code>
     *       </ul>
     *    <li> In the class that is going to call the
     *         <code>{@link ExpressionEvaluator#evaluateExpr}</code>
     *         method:
     *       <ol>
     *          <li> Instantiate a <code>ExpressionEvaluator</code>.
     *          <li> Instantiate a <code>CallbackResolver</code>.
     *          <li> If your method is not static, instantiate the class that
     *               contains the callback method.
     *          <li> Instantiate a <code>Keyword</code> object with the text
     *               that matches the Progress function name being implemented.
     *          <li> Ensure that the class that instantiates the
     *               <code>Keyword</code> objects also implements the
     *               <code>ProgressParserTokenTypes</code> Interface. This is
     *               required to provide access to the token types constant
     *               definitions.
     *          <li> Call <code>{@link CallbackResolver#addCallback}</code> to
     *               add the definition of this callback to the resolver.
     *          <li> Invoke <code>evaluateExpr</code> with the expression,
     *               the <code>CallbackResolver</code> and a boolean debug flag.
     *       </ol>
     *    <li> Voila!  At this point you can use the returned result.
     * </ul>
     * Some general notes:
     * <ol>
     *    <li> The method name does not have to match the Progress 4GL function
     *         name. This is because it is the <code>Keyword</code> object that
     *         defines the matching criteria by which the Progress function name
     *         is matched to a token type.  This token type is the type of the
     *         return data and the expression evaluator triggers all of its
     *         processing off of this.  Since the same <code>Keyword</code>
     *         object is the mechanism by which the <code>CallbackResolver</code>
     *         looks up the corresponding <code>Callback</code> which defines
     *         the name of the class and method, the two names are properly
     *         associated but do not need to be the same.
     *    <li> Variables can be implemented using a function returning the
     *         right data type and taking no parameters.  In addition, when you
     *         instantiate the <code>Keyword</code> object, you must set the
     *         token type to the correct value (e.g. <code>VAR_INT</code> instead
     *         of <code>FUNC_INT</code>.
     *    <li> The signature of the method that is found must match with the
     *         signature found in the Progress 4GL function call. The parameters
     *         are dynamically examined and converted to Java equivalents. Then
     *         the array of corresponding class objects (in the exact order in
     *         which the parameters were positioned in the Progress function
     *         call) is used in the J2SE reflection APIs to lookup the method.
     *         In the case of variables, it is the same except there are no
     *         parameters.
     *    <li> If you see a <code>NoSuchMethodException</code>, check the
     *         following:
     *       <ul>
     *          <li> The class name is fully qualified (includes the package)
     *               and each component is properly separated by '.' characters.
     *          <li> The class name is correct.
     *          <li> The method name is correct.
     *          <li> The type and order of parameters in the Progress 4GL
     *               expression exactly match those of the callback method.
     *          <li> The method MUST be public!
     *       </ul>
     * </ol>
     * <p>
     * This program provides a command line interface.  See {@link #main} for the
     * syntax.
     *
     * @author GES
     */
    public class FunctionSample
    implements ProgressParserTokenTypes
    {
       /** Logger. */
       private static final ConversionStatus LOG = ConversionStatus.get(FunctionSample.class);

       /**
        * Example private variable whose value will be returned as a user-defined
        * variable.
        */
       private int myVar = 100;

       /**
        * Example user-defined function taking a single String parameter and
        * returning an integer.
        *
        * @param    name
        *           String passed as a parameter in the Progress 4GL expression.
        * @return   The length of the string.
        */
       public int myDefinedFunction(String name)
       {
          return name.length();
       }

       /**
        * Example user-defined function taking a no parameters and returning an
        * integer.
        *
        * @return   Example integer return data.
        */
       public int myNullParmDefinedFunction()
       {
          return 0;
       }

       /**
        * Example user-defined static function taking a single String parameter
        * and returning an integer.
        *
        * @param    name
        *           String passed as a parameter in the Progress 4GL expression.
        * @return   The length of the string.
        */
       public static int myStaticDefinedFunction(String name)
       {
          return name.length();
       }

       /**
        * Example user-defined function that implements a variable by taking no
        * parameters and returning an integer.
        *
        * @return   The value of the variable.
        */
       public int myVariable()
       {
          return myVar;
       }

       /**
        * Provides a command line interface for an end user to drive and/or test
        * the FunctionSample class.
        * <p>
        * This method is also the primary example of how to setup and evaluate
        * a Progress 4GL expression with user-defined functions and variables.
        * <p>
        * Syntax:
        * <pre>
        *   java.exe FunctionSample &quot;quoted_expression&quot; [debug]
        * </pre>
        * Where:
        * <ul>
        *   <li> &quot;quoted_expression&quot; is a valid Progress 4GL
        *        expression that is surrounded by double quotes. Note: if strings
        *        must be specified as part of the expression, specify those
        *        strings using the single quote character.
        * </ul>
        *
        * @param   args
        *          List of command line arguments.
        */
       public static void main(String[] args)
       {
          boolean debug  = false;
          String  syntax = "Syntax: java.exe FunctionSample " +
                           "<quoted_expression> [debug]";

          if (args.length < 1)
          {
             LOG.log(Level.SEVERE, syntax);
             System.exit(-1);
          }

          if (args.length == 2)
          {
             debug = true;
          }

          try
          {
             CallbackResolver cr = new CallbackResolver();
             FunctionSample   fs = new FunctionSample();

             Keyword defined1 = new Keyword("defined",  0, FUNC_INT, false);
             Keyword defined2 = new Keyword("defined2", 0, FUNC_INT, false);
             Keyword defined3 = new Keyword("defined3", 0, FUNC_INT, false);
             Keyword myvar    = new Keyword("myVar",    0, VAR_INT,  false);

             cr.addCallback(defined1,
                            fs,
                            "com.goldencode.p2j.uast.FunctionSample",
                            "myDefinedFunction");
             cr.addCallback(defined2,
                            fs,
                            "com.goldencode.p2j.uast.FunctionSample",
                            "myNullParmDefinedFunction");
             cr.addCallback(defined3,
                            null,
                            "com.goldencode.p2j.uast.FunctionSample",
                            "myStaticDefinedFunction");
             cr.addCallback(myvar,
                            fs,
                            "com.goldencode.p2j.uast.FunctionSample",
                            "myVariable");

             BaseDataType result = ExpressionEvaluator.evaluateExpr(args[0],
                                                                    cr,
                                                                    debug);
             System.out.println("Result = " + result);
          }

          catch (Exception exc)
          {
             LOG.log(Level.SEVERE, "", exc);
          }
       }
    }