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 "quoted_expression" [debug]
* </pre>
* Where:
* <ul>
* <li> "quoted_expression" 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);
}
}
}