BlockManager.java
/*
** Module : BlockManager.java
** Abstract : common "scaffolding" for executing Progress-compatible code blocks
**
** Copyright (c) 2008-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------------Description-----------------------------------
** 001 GES 20080509 @38517 Created initial version. Implements the core
** "scaffolding" for executing 4GL-compatible
** code blocks. The API is designed to handle
** all possible block constructs and for the
** converted code to delegate the execution of
** those code blocks to this class. This greatly
** reduces the amount of code in the converted
** business logic.
** 002 GES 20080619 @38884 Now provides more detailed block types to the
** transaction manager. ON ENDKEY UNDO, RETRY is
** now signalled to the TM as well.
** 003 GES 20080625 @38958 Shifted the TM to the BlockType enum and
** moved the enum to be a separate class.
** 004 GES 20080701 @39058 FOR blocks/loops must honor user-defined
** ENDKEY behavior in preference to the default
** behavior for a query "off end".
** 005 GES 20080818 @39433 Added some UNDO stmt signatures. Fix to add
** the error prop to DO blocks/loops that are
** full transactions (it is implicit).
** 006 GES 20080822 @39519 Added missing function for GO-ON editing
** blocks, implicit ERROR property support for
** DO blocks/loops that are marked as FULL
** transaction types AND ILP support to convert
** NEXT to LEAVE.
** 007 GES 20080829 @39694 Added honorStop() support.
** 008 GES 20080924 @39934 Fix for QueryOffEndException processing.
** It must always cause a FOR loop or block
** to UNDO, LEAVE.
** 009 SIY 20081003 @40016 Added notification of listeners about
** conditions triggered in blocks to which they
** are bound.
** 010 GES 20081106 @40361 Editing blocks must handle an error generated
** by the END-ERROR key by re-throwing it (just
** as is done in the UPDATE stmt). This needs
** to be done for all forms of editing block,
** not just one with the UPDATE stmt.
** 011 SIY 20081111 @40412 Added UNKNOWN Condition type, changed
** visibility of exceptionToCondition, other
** minor cleanups.
** 012 GES 20081126 @40740 Fixes for interactions counter and END-ERROR
** processing in EDITING and DO blocks/loops.
** 013 GES 20090115 @41132 Fix for loophole in condition processing.
** If processCondition() is about to re-throw
** an exception, it must trigger abnormalEnd()
** processing first.
** 014 SVL 20090415 @41799 Fixed error handing for editing blocks.
** 015 GES 20090512 @42148 Added execution statistics support.
** 016 CA 20090727 @43396 When a query associated or nested with a FOR
** or FOR EACH block goes off end, its
** associated buffers must not process the
** undoables (the buffer must not reference any
** record after the UNDO, LEAVE).
** 017 GES 20090729 @43443 Added validation processing hooks at the end of
** every block or loop, just before normal exit or
** iteration.
** 018 CA 20090731 @43471 Fixed query off-end processing. When the query
** for a FOR or FOR EACH block finds no more records,
** the loop must be allowed to finish, by performing
** the implicit END-KEY action (UNDO, LEAVE), even
** if the user has defined an explicit END-KEY
** action. For END-KEY conditions generated by a FIND
** statement, the block must execute the default
** END-KEY action if no explicit one is defined.
** Else, it must execute the user-defined action.
** 019 CA 20090804 @43505 Fixed undo, leave when used inside a FOR block.
** Cleanup TM related static imports. Fixed PRESELECT
** query in DO/REPEAT blocks - the record buffers
** associated with the query must not reference any
** record until a FIND statement is executed on the
** buffer.
** 020 ECF 20090816 @43656 Fixed output parameter support for database
** fields. Modified topLevelBlock() and
** functionBlock() to call out to the current
** block's OutputParameterAssigner, if any, to copy
** output parameters' values back to the database
** fields with which they are associated.
** 021 GES 20090831 @43801 Don't raise ERROR in caller if the called code is a function.
** 022 CA 20130123 Pass the Block instance to pushScope, so it will be saved by the
** BlockDefinition. Added APIs to support functions returning rowid,
** recid and int64 values.
** 023 CA 20130129 Added "function returns longchar" support.
** 024 CA 20130209 Added support for functions returning extent. Refactored the
** function call APIs to use generics.
** 025 CA 20130315 Added returnNormal(WrappedResource) API, to be used when the HANDLE
** attribute is used by this statement (in this case, HANDLE returns a
** WrappedResource and not a real handle).
** 025 OM 20130329 Added returnNormal (long val) since decimal variant loses precision.
** Fixed return type in functionBlock() by applying "conversion"
** constructor if needed.
** 026 CA 20131116 Fixed pushing of the TARGET- and SOURCE-PROCEDURE for java-style
** function calls.
** 027 CA 20140218 Resolved PROGRAM-NAME in case of java-style function calls: push to
** a dedicated stack the closest function name, before invoking the
** function's body.
** 028 HC 20140708 Added support for error handling of the extent parameter wrapper
** classes (AbstractExtentParameter).
** 029 SVL 20140709 Handle InvalidParameterConditionException in topLevelBlock.
** 030 ECF 20140813 Added processValidateWorker to preserve and restore certain work area
** state which would otherwise be corrupted by database write triggers
** being fired during validation processing.
** 031 VIG 20140709 Added ConditionException processing for _MSG function to
** the processBody method.
** 032 GES 20141014 Added Block.fini() call support. It must be called every time the
** body() is actually executed (no matter whether on the first
** execution, an iteration, a retry or when the body is exiting
** normally or abnormally. In all cases there is a 1 to 1 association
** of block body execution to fini method execution. This matches the
** 4GL FINALLY block feature.
** 033 GES 20150204 Clear GO-PENDING when a NEXT statement is used in an EDITING block.
** 034 CA 20150222 An EDITING block is a no-op if no widgets are specified (i.e. all
** WHEN clauses are false).
** 036 OM 20150709 Added support for error conditions in OutputParameterAssigner.
** 037 CA 20150813 Improve performance of user-def function calls converted to java
** method calls: the legacy function name is passed at the function
** definition, to the function* emitted API. If this is set, this will
** avoid calling the expensive ProcedureManager.resolveClosestMethod.
** 038 ECF 20150815 Implemented more efficient reflection logic in functionBlock.
** 039 ECF 20160206 Pass exceptional cause of certain rollback operations to TM.
** 040 GES 20160518 Major rewrite to implement lambda expressions.
** 041 OM 20160906 Small optimization.
** 042 GES 20160830 Added support for Block.pre() to replace use of the default c'tor.
** 20160907 Modified how the containing business logic instance is obtained for
** an external procedure. When lambdas are used, this instance MUST be
** passed through as a parameter to the externalProc() call.
** 043 CA 20180521 Added stopAfter stubs for DO's STOP-AFTER option.
** CA 20180528 Added UNLESS-HIDDEN to the UPDATE/SET/PROMPT-FOR ... EDITING blocks.
** 044 CA 20181216 Added ON ... THROW support and BLOCK-LEVEL and ROUTINE-LEVEL stmts.
** Added stub for UNDO, THROW.
** Added stub for CATCH statement.
** 045 CA 20190122 internalProcedure calls emitted for constructor or destructor methods
** defined for a legacy 4GL class must specify the caller name and
** either the instance or .class, to allow Java direct class.
** CA 20190219 Added runtime for ROUTINE-LEVEL ON ERROR UNDO,THROW and
** BLOCK-LEVEL ON ERROR UNDO,THROW.
** Basic runtime for legacy error management.
** GES 20190323 Reduced context local lookups.
** CA 20190324 Improved the statistics to record the execution time.
** returnWorker now avoids building a Java array for all calls.
** GES 20190324 Implemented TransactionHelper instead of direct usage of the static
** TM API. This allows the elimination of context local usage in TM.
** CA 20190325 Implemented ProcedureHelper and ControlFlowOpsHelper instead of
** direct usage of the static API.
** 046 CA 20190628 Track if an AppError is from a RETURN ERROR statement.
** 047 HC 20190701 Fixed returnError to allow raising any legacy error type. Added
** marking of a returned object as 'pending-assign' to prevent deletion
** of the object before is is returned to the caller.
** 048 CA 20190710 Added API to get the return value from a function (if it applies).
** CA 20190720 Always load a legacy class, if a static method is accessed.
** 049 AIL 20190917 Added the ValidationUnwindException handling inside the blocks.
** 20191119 Replaced ValidationUnwindException with default on error throw
** CA 20191119 Track the executing legacy class, to be able to register any buffer
** to its source definition class.
** GES 20191122 Added processCatch().
** 050 CA 20200122 Javadoc fixes.
** CA 20200312 Fixes for UNDO, THROW and RETURN ERROR, in case when a OO-like
** error condition needs to be generated.
** CA 20200324 More fixes related to OO-like error processing via AppError.
** CA 20200330 More fixes related to OE-compatible error management, in constructor
** case and 'implicit' 4GL ERROR conditions.
** CA 20200407 ERROR conditions generated by the FWD runtime must be deferred, so
** that they can be emitted by the client-side, too.
** CA 20200427 Replaced isValid().booleanValue() calls with _isValid().
** CA 20200528 undoThrowTopLevel must mark the AppError as 'from return', to be able to use the
** return value message.
** 051 CA 20200713 Fixed 'RETURN ?' in a procedure - the RETURN-VALUE must be set to unknown.
** GES 20200731 Eliminated context-local lookups by using ErrorHelper.
** 052 CA 20200927 Use WorkArea.cfops.setReturnValue(String) instead of direct ControlFlowOps call.
** CA 20200927 Avoid context-local lookups by relying on the helper instance.
** CA 20210216 Arithmetic operations are always int64 - this requires special processing when
** passing such an expression as an argument, so the conversion-time type of the
** expression is preserved. If the assignment of the argument fails, the top-level
** must not be invoked.
** CA 20210310 Small performance improvement (avoid unnecessary setup if the block doesn't have
** a fini method).
** SVL 20210316 Fixed RETURN NO-APPLY for persistent triggers.
** CA 20210428 A memptr returned by a function call must be the real reference, as a SET-SIZE
** called on a OO property will change that property directly.
** CA 20210428 For function/OO calls passed as an argument to another call, evaluate them via a
** lambda expression so that the 'output parameter assigner' is not corrupted.
** HC 20210511 Fixed widget display validation on GO event in EDITING block and
** WAIT-FOR.
** CA 20210609 Reworked INPUT/INPUT-OUTPUT parameters to a new approach, where they are explicitly
** initialized at the method's execution, and not at the caller's arguments.
** (backed out CA/20210428).
** GES 20210809 Fixed FINALLY block to execute after commitables/finalizables are processed.
** OM 20211111 Added transaction support for FINALLY blocks.
** CA 20211112 Fixed RETURN-ERROR when this is done in the root procedure for a remote appserver
** call (the error condition must be propagated to the remote side).
** OM 20211201 Improved transaction support for finally blocks.
** OM 20211130 Allow function return value to be overriden.
** CA 20220120 Performance improvement for pushing a new calee scope, keep the already resolved
** internal entry legacy name.
** CA 20220120 When a legacy OO exception is consumed, release it so it can be deleted.
** CA 20220128 All non-empty messages in a thrown legacy error must be displayed, if the error
** is not processed by a CATCH block.
** CA 20220208 Only RETURN ERROR can raise legacy OO errors on the caller's side for appserver
** calls.
** CA 20220304 An ERROR condition being raised from within a block which can catch SysError must
** be morphed into a legacy SysError exception, and not raise an ERROR condition.
** VVT 20220305 NPE in hasLegacyError fixed when method is called from JUnit.
** AL2 20220314 Poly functions shouldn't explicitly convert the return value.
** Wrap return value in proxies to honor dynamic function behavior.
** CA 20220426 CATCH block can be nested, added a 'catchBlock' stub which will have the runtime
** support for a CATCH block's default block.
** CA 20220531 Fixed propagation of explicit legacy exceptions - they must propagate if the
** block has ON ERROR UNDO, THROW or if they are explicitly throw by the application.
** CA 20220606 Added lazy loading of legacy converted classes.
** TW 20220803 Error-status:error must be set for return error in method, while return error
** in old-style ABL function must remain the same. Refs: #6567.
** TW 20220804 Harden against NPE.
** TW 20220817 Error-status:error must be set for return error in static method.
** CA 20220930 Added a helper to expose the context-local 'markPendingDynCall' API.
** CA 20220901 Refactored scope notification support: ScopeableFactory was removed, and the
** registration is now specific to each type of scopeable. For each case, the block
** will be registered for scope support (for that particular scopeable) only when
** the scopeable is 'active' (i.e. unnamed streams or accumulators are used). This
** allows a lazy registration of scopeables, to avoid the unnecessary overhead of
** processing all the scopeables for each and every block.
** EVL 20221017 Fix from CA to protect from client silent abend for LegacyErrorException.
** TJD 20220504 Java 11 compatibility minor changes
** CA 20221123 If an 'object' instance is assigned in the FINALLY block and also referenced by
** the RETURN statement, then do not remove it from 'pendingAssign'.
** CA 20220613 Allow OO exceptions to propagate to the remote side, when exiting the root block
** on a appserver call.
** CA 20230116 Improvement from context-local state resolution.
** 053 GES 20230116 Avoid throw/catch for normal return in a function (performance optimization).
** Added variants of returnNormal/returnExtentNormal called storeReturnValue/
** storeExtentReturnValue to make the code read better (they are really the same
** code at this point in time).
** 054 CA 20230307 For p2j.oo code, for now let returnNormal throw a ReturnUnwindException, as this
** code is not refactored to use the GES/20230116 approach.
** 055 CA 20230313 A missed case for CA/20230307 - check static OO method calls, too, as the static
** classes have a different registry in ObjectOps.
** 056 GBB 20230322 Log legacy error before throwing.
** 057 RAA 20230525 Creating a new BaseDataType instance is now done using BaseDataTypeFactory.
** 058 OM 20230505 Avoided incorrect INDEX_OUT_OF_RANGE exception.
** 059 CA 20230609 If a structured exception reaches a block with an ON ERROR clause with an action
** something other than THROW, it will consume this legacy exception and treat it as
** an ERROR condition.
** CA 20230615 The UNDO, THROW executed from a CATCH block must target the parent block of the
** block where the CATCH was defined. Also, the CATCH block must execute just
** before the FINALLY block, in TM.popScope.
** Small optimization - avoid using obj.ref() and use instead obj.ref, if the 'obj'
** instance is known to be valid.
** 060 CA 202300707 A RETURN in a CATCH block associated with a top-level block will emit via
** 'storeReturnValue'; identify this call and treated as if it was from the top-level
** block.
** Also, clear any pending errors before the CATCH is executed.
** 061 CA 20230713 Fixed a regression in H059 and H060 - a RETURN from a CATCH block was leaking to
** previous block and terminating it.
** Other optimizations related to 'storeReturnValue' and basic processing of the
** CATCH and FINALLY termination blocks.
** 062 AL2 20230801 Refactored looping blocks to allow query parameter.
** 063 ME 20230919 Wrap return value from functionBlock if return type is BaseDataType (invoke, poly).
** 064 OM 20230921 Added static method trigger().
** 065 CA 20231009 Fixed the 'executing' type for direct Java calls.
** 066 CA 20230919 Fixed a bug for direct Java call, the 'executing' type was not computed correctly.
** 067 CA 20230802 Ensure the OutputParameterAssigner gets reset if a legacy OO exception is thrown
** in the FINALLY or CATCH block.
** 068 CA 20231026 An object instance being returned must be tracked on the caller block, as the
** returned value may or may not be assigned, and the callee may return a freshly
** created instance which will never gets discarded if is never assigned again.
** Do not pin the Block instance to BlockDefinition, as it is never read.
** 068 CA 20231129 Use method references where possible.
** CA 20231216 'checkFunctionReturn' needs to process only the top of stack, as this is where
** current return value can ever exist.
** CA 20231221 ObjectOps scopeable support is registered only when: a var is defined, a new
** instance is being created, or a function/method returns 'object'.
** 069 AL2 20230801 Refactored looping blocks to allow query parameter.
** 070 ES 20231203 Added a new parameter for forBlock to allow multiple query directions.
** ES 20231212 Removed casting to CompundQuery in forEachWorker and forWorker.
** ES 20231213 Adding a switch in forBlockWorker to select operation performed on the query parameter.
** 071 AL2 20240221 Process the legacy exceptions to trigger rollbacks of the block it passes through.
** 072 SVL 20240207 Preserve case sensitivity of the returned character value of a function.
** 073 AL2 20240308 Rollback on legacy error exceptions only when a (sub-)transaction is active.
** Don't let error condition exceptions enter abnormal handling with ON ... THROW.
** 074 AL2 20240229 Avoid roll-back on off-end query that was used for the for-each or for-block.
** 20240311 Restore the processOffEndListeners calls; they are used to reset the off-end.
** 075 AL2 20240310 Validate at the end of a loop iteration even if not inside a transaction.
** 076 CA 20240324 Use logical constants for TRUE, FALSE, UNKNOWN, within internal FWD runtime.
** 077 ES 20240404 Set iteration flag for the query defined in FOR EACH block.
** 078 SC 20240516 Added a check for dynamic call in functionBlock and created a proxy if the
** function return type is different from the returned value type
** 079 SB 20240523 Prevent rollback on legacy exception errors if there is a pending rollback.
** Refs #8728.
** 080 CA 20240522 Ensure 'abort' is called for OutputParameterAssigner in case of errors during
** pop scope processing (which includes catch/finally blocks).
** 081 DDF 20240523 Re-throw processed legacy error based on the reThrow flag of the error if possible.
** DDF 20240524 Revert re-throw change and avoid NPE when matching condition is null.
** 082 CA 20240529 Fixed SC/078 when there is direct java calls.
** 083 CA 20240609 Once a structured exception is re-thrown, mark it as explicit, so it can be
** re-thrown via top-level blocks.
** 084 ES 20240513 Added support for stop-after statement for Progress blocks.
** After each successful iteration of the block body the timer of the current block should
** be cleaned.
** Targeting the block for which stop-after timeout was raised.
** If a inner block of a targeted by a stop-after block has an ON STOP, RETRY, then the
** retry should be honored.
** 20240531 Added support to disable stop-after runtime with a parameter in directory.
** 20240604 Lazy initialization of the stopAfterTimer in WorkArea.
** 085 CA 20240708 A block needs to be aware if a RETURN ERROR or UNDO, THROW was used for exit,
** as this will make a FINALLY block to act as if it executes in silent mode. Also,
** a CATCH block will not be executed when RETURN ERROR or UNDO, THROW is used.
** 086 AS 20240730 Moved exitTopLevel to finally block in topLevelBlock
** 087 AS 20240911 Fixed error propagation for errors thrown in caller.
** 088 TJD 20240314 BufferManager should be pending scopeable for editing block, fix by CA
** TJD 20240409 Reset queryOffEnd listeners on beginning of foreach worker
** 089 ES 20240919 Prevent second rollback in case of an undoThrowTopLevel.
** 090 CA 20240625 Certain database-level ERROR conditions (like 132/buffer already exists with)
** must be processed as if BLOCK-LEVEL ON ERROR UNDO, THROW is set (in other words,
** it can get morphed into a strcutured exceptions).
** 091 AS 20241204 In LOG-MANAGER context, log the numbered errors thrown by undoThrow.
** 092 ES 20240115 In case the unnamed stream is redirected in the editiongBlock, call the
** subsequent GenericFrame method (set, update or promtFor).
** 093 RNC 20250204 If the FOR-EACH query raises an error, leave the block instead of retrying.
** 094 CA 20250131 Added support for ON QUIT, {LEAVE|NEXT|...} - this must not rollback, but commit.
** 095 SP 20250210 Added storeReturnValue(Stream) and returnNormal(Stream) variants.
** 096 GBB 20250218 ErrorManager.displayError() calls moved to a new method displayErrorMessage,
** where the legacy error is marked as displayed to avoid a second display.
** Duplicated code refactored.
** 097 ES 20250217 Added support for nested catch blocks.
** 098 ES 20250227 Added runtime support for undo, throw with Progress.Lang.Stop error. Added methods
** undoThrowStopTopLevel and undoThrowStop.
** ES 20250228 Added runtime supoort for UNDO, RETURN ERROR exe statement.
*/
/*
** 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.util;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.logging.Level;
import java.io.*;
import java.lang.reflect.*;
import com.goldencode.p2j.directory.*;
import com.goldencode.p2j.main.*;
import com.goldencode.p2j.net.Control;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.p2j.persist.*;
import com.goldencode.p2j.security.ContextLocal;
import com.goldencode.p2j.security.RestrictedUseException;
// the following are dependencies on the UI package which we would prefer to
// eliminate if the services can be cleanly abstracted without making the
// calling code worse from a readability perspective
import com.goldencode.p2j.ui.LogicalTerminal;
import com.goldencode.p2j.util.ProcedureManager.ProcedureHelper;
import com.goldencode.p2j.util.logging.CentralLogger;
import com.goldencode.p2j.ui.CommonFrame;
import com.goldencode.p2j.ui.FrameElement;
import com.goldencode.p2j.ui.GenericFrame;
import com.goldencode.p2j.ui.EventList;
import com.goldencode.p2j.security.SecurityManager;
import com.goldencode.util.*;
import static com.goldencode.p2j.util.TransactionManager.*;
/**
* Provides an external API that allows the Progress-compatible code block
* semantics to be provided with a minimum of code in the caller. This class
* encodes the "scaffolding" necessary to properly process code blocks with
* the right behavior. The external interface is designed to be statically
* imported to make access simple, short and easy to read. The API has been
* designed to minimize name conflicts. The scaffolding code uses the
* {@link TransactionManager} extensively to implement the proper behavior.
*/
public class BlockManager
{
/** Logger */
private static final CentralLogger LOG = CentralLogger.get(BlockManager.class.getName());
/** Stores context-local state variables. */
private static final ContextContainer work = new ContextContainer();
/** Encodes the possible levels of transaction support for each block. */
public static enum TransactionType { NONE, SUB, FULL };
/** Encodes the possible condition types. */
public static enum Condition { ERROR, ENDKEY, STOP, QUIT, QUIT_COMMIT, UNKNOWN };
/** Encodes the possible actions in response to given conditions. */
public static enum Action
{
LEAVE,
NEXT,
RETRY,
RETURN_NORMAL,
RETURN_CONSUME,
RETURN_ERROR,
THROW
}
/** The fixed label of all FINALLY: blocks. */
public static final String FINALLY_BLOCK_LABEL = "__finally__";
/** The fixed label of all CATCH: blocks. */
public static final String CATCH_BLOCK_LABEL = "__catch__";
/** Encodes the possible types of return statement. */
enum ReturnType { NORMAL, CONSUME, ERROR, STORE }
/** Encodes the possible responses to a flow control event. */
private static enum Disposition { BREAK, CONTINUE, THROW, NONE };
/** Directory entry to define an execution statistics output file. */
private static final String STATS_FILE = "block-execution-statistics";
/** Synthetic null value to use in a deque which doesn't accept null values. */
private static final Object NULL = new Object();
/** Output filename in which to write execution statistics. */
private static String statsFile = null;
/** Stores calls execution statistics. */
private static Map<String, AtomicInteger> stats = null;
/** Stores timing execution statistics. */
private static Map<String, AtomicLong> times = null;
static
{
Directory dir = DirectoryManager.getInstance();
statsFile = dir.getString(Directory.ID_RELATIVE, STATS_FILE, null);
if (statsFile != null)
{
stats = new ConcurrentHashMap<String, AtomicInteger>();
times = new ConcurrentHashMap<String, AtomicLong>();
StandardServer.register(new StatsHelper());
}
}
/**
* API for ROUTINE-LEVEL ON ERROR UNDO,THROW statement.
* <p>
* This will change the default ON ERROR from UNDO, RETRY to UNDO, THROW for all routines
* in this procedure or class (including its 'execute' method).
* <p>
* This includes:
* <ul>
* <li>external program</li>
* <li>internal procedures</li>
* <li>functions </li>
* <li>user-defined functions</li>
* <li>class methods</li>
* <li>class constructors (but not destructors) - including static</li>
* <li>class property getter/setter - including static</li>
* <li>schema trigger programs - including static</li>
* </ul>
* TODO: does this affect super-classes, in case of OO instances?
*
* @param condition
* ERROR.
* @param action
* THROW.
*/
public static void onRoutineLevel(Condition condition, Action action)
{
// TODO: the condition/action currently is not propagated or saved - ERROR, THROW is always assumed
work.get().pm.markRoutineLevelUndoThrow();
}
/**
* API for BLOCK-LEVEL ON ERROR UNDO,THROW statement.
* <p>
* This will change the default ON ERROR from UNDO, RETRY to UNDO, THROW for all routines
* in this procedure or class (including its 'execute' method).
* <p>
* This includes:
* <ul>
* <li>external program</li>
* <li>internal procedures</li>
* <li>functions </li>
* <li>user-defined functions</li>
* <li>class methods</li>
* <li>class constructors (but not destructors) - including static</li>
* <li>class property getter/setter - including static</li>
* <li>schema trigger programs - including static</li>
* <li>REPEAT, FOR, DO TRANSACTION blocks</li>
* </ul>
* TODO: does this affect super-classes, in case of OO instances?
*
* @param condition
* ERROR.
* @param action
* THROW.
*/
public static void onBlockLevel(Condition condition, Action action)
{
// TODO: the condition/action currently is not propagated or saved - ERROR, THROW is always
// assumed
work.get().pm.markBlockLevelUndoThrow();
}
/**
* Offers runtime support for stop-after statement for Progress blocks.
*
* @param val
* The number of seconds to wait before raising a QUIT.
*/
public static void stopAfter(NumberType val)
{
stopAfter(val.longValue());
}
/**
* Offers runtime support for stop-after statement for Progress blocks.
*
* @param val
* The number of seconds to wait before raising a QUIT.
*/
public static void stopAfter(long val)
{
WorkArea wa = work.get();
if (!wa.isStopAfterActive || val == 0)
{
return;
}
if (wa.stopAfterTimer == null)
{
try
{
Control control = SecurityManager.getCurrentContextControl();
String threadName = Thread.currentThread().getName();
wa.stopAfterTimer = new StopAfterTimer(threadName, control);
wa.errHelper.setStopAfterTimer(wa.stopAfterTimer);
wa.tm.registerStopAfterTimer(wa.stopAfterTimer);
}
catch (RestrictedUseException e)
{
LOG.log(Level.WARNING,
"Restricted use of Control.getCurrentContextControl()",
e);
return;
}
}
StopAfterTimer stopAfterTimer = wa.stopAfterTimer;
BlockDefinition block = wa.tm.getBlock();
if (stopAfterTimer.isBlockRegistered(block))
{
return;
}
StopAfterTimer.Task task = stopAfterTimer.addTimeOut(block, val);
wa.tm.registerFinalizable(task, false);
}
/**
* Execute the given external procedure block with a default transaction level of
* <code>TransactionType.SUB</code>.
* <p>
* This form may only be used with block instances that are anonymous inner classes since
* the containing business logic class can be calculated using reflection. Any usage with
* lambdas will fail!
*
* @param block
* The code to execute.
*/
public static void externalProcedure(Block block)
{
externalProcedure(null, null, TransactionType.SUB, block);
}
/**
* Execute the given external procedure block with the given transaction level.
* <p>
* This form may only be used with block instances that are anonymous inner classes since
* the containing business logic class can be calculated using reflection. Any usage with
* lambdas will fail!
*
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void externalProcedure(TransactionType lvl, Block block)
{
externalProcedure(null, null, lvl, block);
}
/**
* Execute the given external procedure block with a default transaction level of
* <code>TransactionType.SUB</code>.
* <p>
* This form is suitable for use with lambdas but in such a case the <code>referent</code>
* must be non-null.
*
* @param referent
* The instance of the containing business logic class from which this is being
* called. If this is non-null, then <code>block</code> can be an instance created
* using lambdas. If <code>null</code>, then <code>block</code> MUST BE an
* anonymous inner class of the containing business logic instance so that instance
* can be calculated via reflection.
* @param block
* The code to execute.
*/
public static void externalProcedure(Object referent, Block block)
{
externalProcedure(referent, TransactionType.SUB, block);
}
/**
* Execute the given external procedure block with the given transaction level.
* <p>
* This form is suitable for use with lambdas but in such a case the <code>referent</code>
* must be non-null.
*
* @param referent
* The instance of the containing business logic class from which this is being
* called. If this is non-null, then <code>block</code> can be an instance created
* using lambdas. If <code>null</code>, then <code>block</code> MUST BE an
* anonymous inner class of the containing business logic instance so that instance
* can be calculated via reflection.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void externalProcedure(Object referent, TransactionType lvl, Block block)
{
// TODO: move this in a more performance-wise place (i.e. after user login and Agent.listen)
// ensure certain context-local data has loaded
ProcedureManager.load();
topLevelBlock(null, referent, null, lvl, BlockType.EXTERNAL_PROC, block);
}
/**
* Execute the given external procedure block with a default transaction level of
* <code>TransactionType.SUB</code>.
* <p>
* This form is suitable for use with lambdas but in such a case the <code>referent</code>
* must be non-null.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The instance of the containing business logic class from which this is being
* called. If this is non-null, then <code>block</code> can be an instance created
* using lambdas. If <code>null</code>, then <code>block</code> MUST BE an
* anonymous inner class of the containing business logic instance so that instance
* can be calculated via reflection.
* @param block
* The code to execute.
*/
public static void externalProcedure(Class<?> def,
Object referent,
Block block)
{
externalProcedure(def, referent, TransactionType.SUB, block);
}
/**
* Execute the given external procedure block with the given transaction level.
* <p>
* This form is suitable for use with lambdas but in such a case the <code>referent</code>
* must be non-null.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The instance of the containing business logic class from which this is being
* called. If this is non-null, then <code>block</code> can be an instance created
* using lambdas. If <code>null</code>, then <code>block</code> MUST BE an
* anonymous inner class of the containing business logic instance so that instance
* can be calculated via reflection.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void externalProcedure(Class<?> def,
Object referent,
TransactionType lvl,
Block block)
{
// TODO: move this in a more performance-wise place (i.e. after user login and Agent.listen)
// ensure certain context-local data has loaded
ProcedureManager.load();
topLevelBlock(def, referent, null, lvl, BlockType.EXTERNAL_PROC, block);
}
/**
* Execute the given internal procedure block with a default transaction
* level of <code>TransactionType.SUB</code>.
*
* @param block
* The code to execute.
*/
public static void internalProcedure(Block block)
{
internalProcedure(TransactionType.SUB, block);
}
/**
* Execute the given internal procedure block with the given transaction
* level.
*
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void internalProcedure(TransactionType lvl, Block block)
{
topLevelBlock(null, null, null, lvl, BlockType.INTERNAL_PROC, block);
}
/**
* Execute the given internal procedure block with a default transaction
* level of <code>TransactionType.SUB</code>.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param block
* The code to execute.
*/
public static void internalProcedure(String legacyName, Block block)
{
internalProcedure(legacyName, TransactionType.SUB, block);
}
/**
* Execute the given internal procedure block with the given transaction
* level.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void internalProcedure(String legacyName, TransactionType lvl, Block block)
{
topLevelBlock(null, null, legacyName, lvl, BlockType.INTERNAL_PROC, block);
}
/**
* Execute the given internal procedure block with a default transaction
* level of <code>TransactionType.SUB</code>.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param block
* The code to execute.
*/
public static void internalProcedure(Object referent, String legacyName, Block block)
{
internalProcedure(referent, legacyName, TransactionType.SUB, block);
}
/**
* Execute the given internal procedure block with the given transaction
* level.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void internalProcedure(Object referent,
String legacyName,
TransactionType lvl,
Block block)
{
topLevelBlock(null, referent, legacyName, lvl, BlockType.INTERNAL_PROC, block);
}
/**
* Execute the given internal procedure block with a default transaction
* level of <code>TransactionType.SUB</code>.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param block
* The code to execute.
*/
public static void internalProcedure(Class<?> def,
Object referent,
String legacyName,
Block block)
{
internalProcedure(def, referent, legacyName, TransactionType.SUB, block);
}
/**
* Execute the given internal procedure block with the given transaction
* level.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*/
public static void internalProcedure(Class<?> def,
Object referent,
String legacyName,
TransactionType lvl,
Block block)
{
topLevelBlock(def, referent, legacyName, lvl, BlockType.INTERNAL_PROC, block);
}
/**
* Execute the given trigger block as a SUB-transaction.
*
* @param block
* The code to execute.
*/
public static void trigger(Block block)
{
// TODO: check if TransactionType.FULL is not the appropriate type
topLevelBlock(null, null, null, TransactionType.SUB, BlockType.DATABASETRIGGER, block);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>.
*
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(Class<T> cls, Block block)
{
return (T) function(cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level.
*
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(Class<T> cls,
TransactionType lvl,
Block block)
{
return ((T) functionBlock(null, null, null, lvl, block, cls, -1));
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns an extent value.
*
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<T> cls,
int extent,
Block block)
{
return (T[]) extentFunction(cls, extent, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level, which returns an extent
* value.
*
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<T> cls,
int extent,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(null, null, null, lvl, block, cls, extent);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns a dynamic extent value.
*
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<T> cls,
Block block)
{
return (T[]) extentFunction(cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level, which returns a
* dynamic extent value.
*
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<T> cls,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(null, null, null, lvl, block, cls, 0);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(String legacyName, Class<T> cls, Block block)
{
return (T) function(legacyName, cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(String legacyName,
Class<T> cls,
TransactionType lvl,
Block block)
{
return (T) functionBlock(null, null, legacyName, lvl, block, cls, -1);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(Object referent,
String legacyName,
Class<T> cls,
Block block)
{
return (T) function(referent, legacyName, cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(Object referent,
String legacyName,
Class<T> cls,
TransactionType lvl,
Block block)
{
return (T) functionBlock(null, referent, legacyName, lvl, block, cls, -1);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(Class<?> def,
Object referent,
String legacyName,
Class<T> cls,
Block block)
{
return (T) function(def, referent, legacyName, cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
public static <T extends BaseDataType> T function(Class<?> def,
Object referent,
String legacyName,
Class<T> cls,
TransactionType lvl,
Block block)
{
return (T) functionBlock(def, referent, legacyName, lvl, block, cls, -1);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns an extent value.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(String legacyName,
Class<T> cls,
int extent,
Block block)
{
return (T[]) extentFunction(legacyName, cls, extent, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level, which returns an extent
* value.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(String legacyName,
Class<T> cls,
int extent,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(null, null, legacyName, lvl, block, cls, extent);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns a dynamic extent value.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(String legacyName,
Class<T> cls,
Block block)
{
return (T[]) extentFunction(legacyName, cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level, which returns a
* dynamic extent value.
*
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(String legacyName,
Class<T> cls,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(null, null, legacyName, lvl, block, cls, 0);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns an extent value.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Object referent,
String legacyName,
Class<T> cls,
int extent,
Block block)
{
return (T[]) extentFunction(null, referent, legacyName, cls, extent, TransactionType.SUB, block);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns an extent value.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<?> def,
Object referent,
String legacyName,
Class<T> cls,
int extent,
Block block)
{
return (T[]) extentFunction(def, referent, legacyName, cls, extent, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level, which returns an extent
* value.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param extent
* The function's return extent value.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<?> def,
Object referent,
String legacyName,
Class<T> cls,
int extent,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(def, referent, legacyName, lvl, block, cls, extent);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns a dynamic extent value.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Object referent,
String legacyName,
Class<T> cls,
Block block)
{
return (T[]) extentFunction(referent, legacyName, cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with a default transaction level of
* <code>TransactionType.SUB</code>, which returns a dynamic extent value.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<?> def,
Object referent,
String legacyName,
Class<T> cls,
Block block)
{
return (T[]) extentFunction(def, referent, legacyName, cls, TransactionType.SUB, block);
}
/**
* Execute the given function block with the given transaction level, which returns a
* dynamic extent value.
*
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Object referent,
String legacyName,
Class<T> cls,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(null, referent, legacyName, lvl, block, cls, 0);
}
/**
* Execute the given function block with the given transaction level, which returns a
* dynamic extent value.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param cls
* The function's return type.
* @param lvl
* The transaction level for the given block.
* @param block
* The code to execute.
*
* @return The return value from the block (or its nested blocks).
*/
public static <T extends BaseDataType> T[] extentFunction(Class<?> def,
Object referent,
String legacyName,
Class<T> cls,
TransactionType lvl,
Block block)
{
return (T[]) functionBlock(def, referent, legacyName, lvl, block, cls, 0);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
*
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void doBlock(String label, Block block)
{
doBlockWorker(TransactionType.NONE, null, label, null, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void doBlock(String[] enclosing, String label, Block block)
{
doBlockWorker(TransactionType.NONE, enclosing, label, null, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void doBlock(TransactionType lvl, String label, Block block)
{
doBlockWorker(lvl, null, label, null, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no user-defined or default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void doBlock(TransactionType lvl,
String[] enclosing,
String label,
Block block)
{
doBlockWorker(lvl, enclosing, label, null, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doBlock(String label, OnPhrase[] on, Block block)
{
doBlockWorker(TransactionType.NONE, null, label, on, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doBlock(String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
doBlockWorker(TransactionType.NONE, enclosing, label, on, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no default properties. In this case, there are no enclosing
* non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doBlock(TransactionType lvl,
String label,
OnPhrase[] on,
Block block)
{
doBlockWorker(lvl, null, label, on, block);
}
/**
* Execute a simple DO block (not a loop) with the given configuration
* and no default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doBlock(TransactionType lvl,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
doBlockWorker(lvl, enclosing, label, on, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
*
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void doWhile(String label, LogicalOp expr, Block block)
{
doLoopWorker(TransactionType.NONE, null, label, null, expr, null, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void doWhile(String[] enclosing, String label, LogicalOp expr, Block block)
{
doLoopWorker(TransactionType.NONE, enclosing, label, null, expr, null, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void doWhile(TransactionType lvl, String label, LogicalOp expr, Block block)
{
doLoopWorker(lvl, null, label, null, expr, null, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no user-defined or default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void doWhile(TransactionType lvl,
String[] enclosing,
String label,
LogicalOp expr,
Block block)
{
doLoopWorker(lvl, enclosing, label, null, expr, null, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doWhile(String label, LogicalOp expr, OnPhrase[] on, Block block)
{
doLoopWorker(TransactionType.NONE, null, label, null, expr, on, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doWhile(String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(TransactionType.NONE, enclosing, label, null, expr, on, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no default properties. In this case, there are no enclosing
* non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doWhile(TransactionType lvl,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(lvl, null, label, null, expr, on, block);
}
/**
* Execute a DO WHILE expression loop with the given configuration
* and no default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doWhile(TransactionType lvl,
String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(lvl, enclosing, label, null, expr, on, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void doTo(String label, ToClause to, Block block)
{
doLoopWorker(TransactionType.NONE, null, label, to, null, null, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void doTo(String[] enclosing,
String label,
ToClause to,
Block block)
{
doLoopWorker(TransactionType.NONE, enclosing, label, to, null, null, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void doTo(TransactionType lvl,
String label,
ToClause to,
Block block)
{
doLoopWorker(lvl, null, label, to, null, null, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no user-defined or default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void doTo(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
Block block)
{
doLoopWorker(lvl, enclosing, label, to, null, null, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used and there are no enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doTo(String label,
ToClause to,
OnPhrase[] on,
Block block)
{
doLoopWorker(TransactionType.NONE, null, label, to, null, on, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no default properties. <code>TransactionType.NONE</code> will be
* used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doTo(String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
doLoopWorker(TransactionType.NONE, enclosing, label, to, null, on, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no default properties. In this case, there are no enclosing
* non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doTo(TransactionType lvl,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
doLoopWorker(lvl, null, label, to, null, on, block);
}
/**
* Execute a DO TO expression loop with the given configuration
* and no default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doTo(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
doLoopWorker(lvl, enclosing, label, to, null, on, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* <code>TransactionType.NONE</code> will be used and there are no
* enclosing non-managed blocks. In addition, there are no user-defined
* properties.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void doToWhile(String label, ToClause to, LogicalOp expr, Block block)
{
doLoopWorker(TransactionType.NONE, null, label, to, expr, null, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* <code>TransactionType.NONE</code> will be used and there are no
* user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void doToWhile(String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
doLoopWorker(TransactionType.NONE, enclosing, label, to, expr, null, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* There are no user-defined properties and no enclosing non-managed
* blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void doToWhile(TransactionType lvl,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
doLoopWorker(lvl, null, label, to, expr, null, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* There are no user-defined properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void doToWhile(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
doLoopWorker(lvl, enclosing, label, to, expr, null, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* <code>TransactionType.NONE</code> will be used and there are no
* enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doToWhile(String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(TransactionType.NONE, null, label, to, expr, on, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* <code>TransactionType.NONE</code> will be used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doToWhile(String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(TransactionType.NONE, enclosing, label, to, expr, on, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
* <p>
* There are no enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doToWhile(TransactionType lvl,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(lvl, null, label, to, expr, on, block);
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void doToWhile(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
doLoopWorker(lvl, enclosing, label, to, expr, on, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
*
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void repeat(String label, Block block)
{
repeatWorker(TransactionType.SUB, null, label, null, null, null, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void repeat(String[] enclosing, String label, Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, null, null, null, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. There are no user-defined properties and
* there are no enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void repeat(TransactionType lvl, String label, Block block)
{
repeatWorker(lvl, null, label, null, null, null, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. There are no user-defined properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void repeat(TransactionType lvl,
String[] enclosing,
String label,
Block block)
{
repeatWorker(lvl, enclosing, label, null, null, null, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be used
* and there are no enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeat(String label, OnPhrase[] on, Block block)
{
repeatWorker(TransactionType.SUB, null, label, null, null, on, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeat(String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, null, null, on, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeat(TransactionType lvl,
String label,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, null, label, null, null, on, block);
}
/**
* Execute a simple REPEAT (infinite loop) with the given configuration
* and default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeat(TransactionType lvl,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, enclosing, label, null, null, on, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
*
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void repeatWhile(String label, LogicalOp expr, Block block)
{
repeatWorker(TransactionType.SUB, null, label, null, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void repeatWhile(String[] enclosing, String label, LogicalOp expr, Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, null, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void repeatWhile(TransactionType lvl, String label, LogicalOp expr, Block block)
{
repeatWorker(lvl, null, label, null, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and no user-defined or default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void repeatWhile(TransactionType lvl,
String[] enclosing,
String label,
LogicalOp expr,
Block block)
{
repeatWorker(lvl, enclosing, label, null, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatWhile(String label, LogicalOp expr, OnPhrase[] on, Block block)
{
repeatWorker(TransactionType.SUB, null, label, null, expr, on, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatWhile(String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, null, expr, on, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatWhile(TransactionType lvl,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, null, label, null, expr, on, block);
}
/**
* Execute a REPEAT WHILE expression loop with the given configuration
* and default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatWhile(TransactionType lvl,
String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, enclosing, label, null, expr, on, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void repeatTo(String label, ToClause to, Block block)
{
repeatWorker(TransactionType.SUB, null, label, to, null, null, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void repeatTo(String[] enclosing,
String label,
ToClause to,
Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, to, null, null, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void repeatTo(TransactionType lvl,
String label,
ToClause to,
Block block)
{
repeatWorker(lvl, null, label, to, null, null, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and no user-defined or default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void repeatTo(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
Block block)
{
repeatWorker(lvl, enclosing, label, to, null, null, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatTo(String label,
ToClause to,
OnPhrase[] on,
Block block)
{
repeatWorker(TransactionType.SUB, null, label, to, null, on, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatTo(String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, to, null, on, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatTo(TransactionType lvl,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, null, label, to, null, on, block);
}
/**
* Execute a REPEAT TO expression loop with the given configuration
* and default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatTo(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, enclosing, label, to, null, on, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* enclosing non-managed blocks. In addition, there are no user-defined
* properties.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void repeatToWhile(String label, ToClause to, LogicalOp expr, Block block)
{
repeatWorker(TransactionType.SUB, null, label, to, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* user-defined properties.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void repeatToWhile(String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, to, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no user-defined properties and no enclosing non-managed
* blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void repeatToWhile(TransactionType lvl,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
repeatWorker(lvl, null, label, to, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no user-defined properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param block
* The code to execute.
*/
public static void repeatToWhile(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
repeatWorker(lvl, enclosing, label, to, expr, null, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* enclosing non-managed blocks.
*
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatToWhile(String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(TransactionType.SUB, null, label, to, expr, on, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatToWhile(String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(TransactionType.SUB, enclosing, label, to, expr, on, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no enclosing non-managed blocks.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatToWhile(TransactionType lvl,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, null, label, to, expr, on, block);
}
/**
* Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
* or REPEAT TO WHILE expression loop with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void repeatToWhile(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
repeatWorker(lvl, enclosing, label, to, expr, on, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forBlock(P2JQuery query, int direction, String label, Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, null, label, null, null, null, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forBlock(P2JQuery query,
int direction,
String[] enclosing,
String label,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, null, null, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. There are no user-defined properties and
* there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forBlock(TransactionType lvl,
P2JQuery query,
int direction,
String label,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, null, null, null, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. There are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forBlock(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, null, null, null, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be used
* and there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlock(P2JQuery query,
int direction,
String label,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, null, label, null, null, on, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlock(P2JQuery query,
int direction,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, null, on, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlock(TransactionType lvl,
P2JQuery query,
int direction,
String label,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, null, null, on, block);
}
/**
* Execute a FOR FIRST or FOR LAST block with the given configuration
* and default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlock(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, null, null, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockWhile(P2JQuery query,
int direction,
String label,
LogicalOp expr,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, null, label, null, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockWhile(P2JQuery query,
int direction,
String[] enclosing,
String label,
LogicalOp expr,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockWhile(TransactionType lvl,
P2JQuery query,
int direction,
String label,
LogicalOp expr,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, null, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and no user-defined or default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockWhile(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
LogicalOp expr,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, null, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockWhile(P2JQuery query,
int direction,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, null, label, null, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockWhile(P2JQuery query,
int direction,
String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockWhile(TransactionType lvl,
P2JQuery query,
int direction,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, null, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block with the given configuration
* and default properties.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockWhile(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, null, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param block
* The code to execute.
*/
public static void forBlockTo(P2JQuery query, int direction, String label, ToClause to, Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, null, label, to, null, null, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param block
* The code to execute.
*/
public static void forBlockTo(P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, null, null, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param block
* The code to execute.
*/
public static void forBlockTo(TransactionType lvl,
P2JQuery query,
int direction,
String label,
ToClause to,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, to, null, null, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and no user-defined or default properties.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param block
* The code to execute.
*/
public static void forBlockTo(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, to, null, null, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockTo(P2JQuery query,
int direction,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, (String[]) null, label, to, null, on, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockTo(P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, null, on, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockTo(TransactionType lvl,
P2JQuery query,
int direction,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, to, null, on, block);
}
/**
* Execute a FOR FIRST/LAST TO block with the given configuration
* and default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockTo(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, to, null, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* enclosing non-managed blocks. In addition, there are no user-defined
* properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(P2JQuery query,
int direction,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, null, label, to, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no user-defined properties and no enclosing non-managed
* blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(TransactionType lvl,
P2JQuery query,
int direction,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, to, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, to, expr, null, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(P2JQuery query,
int direction,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, (String[]) null, label, to, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(TransactionType lvl,
P2JQuery query,
int direction,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, null, label, to, expr, on, block);
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forBlockToWhile(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forBlockWorker(lvl, query, direction, enclosing, label, to, expr, on, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forBlock.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forEach(P2JQuery query, String label, Block block)
{
forEachWorker(TransactionType.SUB, query, null, label, null, null, null, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forEach(P2JQuery query, String[] enclosing, String label, Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, null, null, null, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. There are no user-defined properties and
* there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forEach(TransactionType lvl, P2JQuery query, String label, Block block)
{
forEachWorker(lvl, query, null, label, null, null, null, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. There are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void forEach(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
Block block)
{
forEachWorker(lvl, query, enclosing, label, null, null, null, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be used
* and there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEach(P2JQuery query, String label, OnPhrase[] on, Block block)
{
forEachWorker(TransactionType.SUB, query, null, label, null, null, on, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEach(P2JQuery query,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, null, null, on, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEach(TransactionType lvl,
P2JQuery query,
String label,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, null, label, null, null, on, block);
}
/**
* Execute a FOR EACH loop with the given configuration
* and default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEach(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, enclosing, label, null, null, on, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachWhile(P2JQuery query, String label, LogicalOp expr, Block block)
{
forEachWorker(TransactionType.SUB, query, null, label, null, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachWhile(P2JQuery query,
String[] enclosing,
String label,
LogicalOp expr,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, null, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachWhile(TransactionType lvl,
P2JQuery query,
String label,
LogicalOp expr,
Block block)
{
forEachWorker(lvl, query, null, label, null, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and no user-defined or default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachWhile(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
LogicalOp expr,
Block block)
{
forEachWorker(lvl, query, enclosing, label, null, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachWhile(P2JQuery query, String label, LogicalOp expr, OnPhrase[] on, Block block)
{
forEachWorker(TransactionType.SUB, query, null, label, null, expr, on, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachWhile(P2JQuery query,
String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, null, expr, on, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachWhile(TransactionType lvl,
P2JQuery query,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, null, label, null, expr, on, block);
}
/**
* Execute a FOR EACH WHILE block with the given configuration
* and default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param expr
* The WHILE clause that defines the loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachWhile(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, enclosing, label, null, expr, on, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks. In addition, there
* are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void forEachTo(P2JQuery query,
String label,
ToClause to,
Block block)
{
forEachWorker(TransactionType.SUB, query, null, label, to, null, null, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void forEachTo(P2JQuery query,
String[] enclosing,
String label,
ToClause to,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, to, null, null, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and no user-defined or default properties. In addition, there are no
* enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void forEachTo(TransactionType lvl,
P2JQuery query,
String label,
ToClause to,
Block block)
{
forEachWorker(lvl, query, null, label, to, null, null, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and no user-defined or default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param block
* The code to execute.
*/
public static void forEachTo(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
ToClause to,
Block block)
{
forEachWorker(lvl, query, enclosing, label, to, null, null, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used and there are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachTo(P2JQuery query,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forEachWorker(TransactionType.SUB, query, (String[]) null, label, to, null, on, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and default properties. <code>TransactionType.SUB</code> will be
* used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachTo(P2JQuery query,
String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, to, null, on, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and default properties. In this case, there are no enclosing
* non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachTo(TransactionType lvl,
P2JQuery query,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, null, label, to, null, on, block);
}
/**
* Execute a FOR EACH TO block with the given configuration
* and default properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachTo(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
ToClause to,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, enclosing, label, to, null, on, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* enclosing non-managed blocks. In addition, there are no user-defined
* properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachToWhile(P2JQuery query, String label, ToClause to, LogicalOp expr, Block block)
{
forEachWorker(TransactionType.SUB, query, null, label, to, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachToWhile(P2JQuery query,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, to, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no user-defined properties and no enclosing non-managed
* blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachToWhile(TransactionType lvl,
P2JQuery query,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forEachWorker(lvl, query, null, label, to, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no user-defined properties.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param block
* The code to execute.
*/
public static void forEachToWhile(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
Block block)
{
forEachWorker(lvl, query, enclosing, label, to, expr, null, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used and there are no
* enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachToWhile(P2JQuery query,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(TransactionType.SUB, query, (String[]) null, label, to, expr, on, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* <code>TransactionType.SUB</code> will be used.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachToWhile(P2JQuery query,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(TransactionType.SUB, query, enclosing, label, to, expr, on, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* There are no enclosing non-managed blocks.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachToWhile(TransactionType lvl,
P2JQuery query,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, null, label, to, expr, on, block);
}
/**
* Execute a FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* default properties. At least one of the to clause or while expression
* must be passed and it is valid to have both passed in which case both
* of the conditions are tested with a logical AND.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself. This
* means that the caller is responsible for all query processing. The
* record retrieval must be done on the first line of code in the block
* to duplicate the Progress behavior. Note that this is required to
* handle all error cases and 4GL conditions properly.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
public static void forEachToWhile(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
forEachWorker(lvl, query, enclosing, label, to, expr, on, block);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, null, null, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
String[] enclosing,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, null, enclosing, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, goOn, null, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, goOn, enclosing, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, null, null, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
String[] enclosing,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, null, enclosing, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, goOn, null, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, goOn, enclosing, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, null, null, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
String[] enclosing,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, null, enclosing, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, goOn, null, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditingUnlessHidden(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block)
{
FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
if (dataChanged == null || dataChanged.length == 0)
{
return;
}
editingBlock(frame, dataChanged, goOn, enclosing, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditing(CommonFrame frame,
FrameElement[] widgets,
String label,
Block block)
{
editingBlock(frame, widgets, null, null, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditing(CommonFrame frame,
FrameElement[] widgets,
String[] enclosing,
String label,
Block block)
{
editingBlock(frame, widgets, null, enclosing, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditing(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String label,
Block block)
{
editingBlock(frame, widgets, goOn, null, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void promptForEditing(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block)
{
editingBlock(frame, widgets, goOn, enclosing, label, block, CommonFrame.PROMPT_FOR);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditing(CommonFrame frame,
FrameElement[] widgets,
String label,
Block block)
{
editingBlock(frame, widgets, null, null, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditing(CommonFrame frame,
FrameElement[] widgets,
String[] enclosing,
String label,
Block block)
{
editingBlock(frame, widgets, null, enclosing, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditing(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String label,
Block block)
{
editingBlock(frame, widgets, goOn, null, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>SET</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void setEditing(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block)
{
editingBlock(frame, widgets, goOn, enclosing, label, block, CommonFrame.SET);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditing(CommonFrame frame,
FrameElement[] widgets,
String label,
Block block)
{
editingBlock(frame, widgets, null, null, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditing(CommonFrame frame,
FrameElement[] widgets,
String[] enclosing,
String label,
Block block)
{
editingBlock(frame, widgets, null, enclosing, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditing(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String label,
Block block)
{
editingBlock(frame, widgets, goOn, null, label, block, CommonFrame.UPDATE);
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
*/
public static void updateEditing(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block)
{
editingBlock(frame, widgets, goOn, enclosing, label, block, CommonFrame.UPDATE);
}
/**
* Break out of the nearest enclosing block.
*
* @throws LeaveUnwindException
*/
public static void leave()
throws LeaveUnwindException
{
leave("");
}
/**
* Break out of the block associated with the given label. This will
* unwind the stack until the proper block has been reached. At that
* point the block will be left using the Java "break" statement.
*
* @param label
* The name of the block to be left.
*
* @throws LeaveUnwindException
*/
public static void leave(String label)
throws LeaveUnwindException
{
leave(work.obtain(), label);
}
/**
* Detect if there is a pending leave for the block named by the given
* label. If so, this deferred leave flag will be cleared and
* <code>true</code> will be returned. The caller is responsible for
* ensuring that the leave request is fully granted as no further state
* will be available for subsequent processing.
*
* @param label
* The name of the block to be checked against the deferred
* leave block name.
*
* @return <code>true</code> if there is a pending deferred leave and
* the name of the block to be left is the same as the given
* label. If the pending deferred block name is the "" (empty
* string), that is the equivalent of matching "any block" and
* so the first call to this method after that is set will cause
* a <code>true</code> to be returned.
*/
public static boolean deferredLeave(String label)
{
return deferredLeaveWorker(null, label);
}
/**
* Continue (iterate) the nearest enclosing block.
*
* @throws NextUnwindException
*/
public static void next()
throws NextUnwindException
{
next("");
}
/**
* Continue (iterate) the block associated with the given label. This will
* unwind the stack until the proper block has been reached. At that
* point the block will be iterated using the Java "continue" statement.
*
* @param label
* The name of the block to be iterated.
*
* @throws NextUnwindException
*/
public static void next(String label)
throws NextUnwindException
{
next(work.obtain(), label);
}
/**
* Detect if there is a pending next for the block named by the given
* label. If so, this deferred next flag will be cleared and
* <code>true</code> will be returned. The caller is responsible for
* ensuring that the next request is fully granted as no further state
* will be available for subsequent processing.
*
* @param label
* The name of the block to be checked against the deferred
* next block name.
*
* @return <code>true</code> if there is a pending deferred next and
* the name of the block to be iterated is the same as the given
* label. If the pending deferred block name is the "" (empty
* string), that is the equivalent of matching "any block" and
* so the first call to this method after that is set will cause
* a <code>true</code> to be returned.
*/
public static boolean deferredNext(String label)
{
return deferredNextWorker(null, label);
}
/**
* Raise the STOP condition and cause control to be transferred to the
* nearest enclosing block that handles the associated condition.
*
* @throws StopConditionException
*/
public static void stop()
throws StopConditionException
{
String msg = "Explicit STOP.";
ErrorManager.handleStopException(msg);
}
/**
* Raise the QUIT condition and cause control to be transferred to the
* nearest enclosing block that handles the associated condition.
*
* @throws QuitConditionException
*/
public static void quit()
throws QuitConditionException
{
throw new QuitConditionException("Explicit QUIT.");
}
/**
* Return from the nearest enclosing top-level block. Sets the default
* <code>RETURN-VALUE</code> to "" (empty string) for internal/external
* procedures and triggers. Leaves <code>unknown value</code> as the
* default return from a user-defined function.
*
* @throws ReturnUnwindException
*/
public static void returnNormal()
throws ReturnUnwindException
{
returnWorker(null, null, ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(WrappedResource val)
throws ReturnUnwindException
{
returnNormal(new handle(val));
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(Stream val)
throws ReturnUnwindException
{
returnNormal(new handle(val));
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(BaseDataType val)
throws ReturnUnwindException
{
returnWorker(null, val, ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void returnExtentNormal(BaseDataType[] val)
throws ReturnUnwindException
{
returnWorker(null, val, ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(String val)
throws ReturnUnwindException
{
returnWorker(new character(val), ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(int val)
throws ReturnUnwindException
{
returnWorker(new integer(val), ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(long val)
throws ReturnUnwindException
{
returnWorker(new int64(val), ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(double val)
throws ReturnUnwindException
{
returnWorker(new decimal(val), ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void returnNormal(boolean val)
throws ReturnUnwindException
{
returnWorker(logical.of(val), ReturnType.NORMAL);
}
/**
* Return from the nearest enclosing top-level block. Sets the default
* <code>RETURN-VALUE</code> to "" (empty string) for internal/external
* procedures and triggers. Leaves <code>unknown value</code> as the
* default return from a user-defined function.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue()
throws ReturnUnwindException
{
returnWorker(null, null, ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(WrappedResource val)
throws ReturnUnwindException
{
returnWorker(null, new handle(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(Stream val)
throws ReturnUnwindException
{
returnWorker(null, new handle(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(BaseDataType val)
throws ReturnUnwindException
{
returnWorker(null, val, ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void storeExtentReturnValue(BaseDataType[] val)
throws ReturnUnwindException
{
returnWorker(null, val, ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. Sets the
* <code>RETURN-VALUE</code> to the given <code>character</code> value for
* internal/external procedures and triggers. Saves the given value as the
* return value for a user-defined function. If <code>val</code> is
* <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
* "" (empty string) for internal/external procedures and triggers. If
* <code>val</code> is <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(String val)
throws ReturnUnwindException
{
returnWorker(null, new character(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(int val)
throws ReturnUnwindException
{
returnWorker(null, new integer(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(long val)
throws ReturnUnwindException
{
returnWorker(null, new int64(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(double val)
throws ReturnUnwindException
{
returnWorker(null, new decimal(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. This should not be
* used for internal/external procedures and triggers, since the
* <code>RETURN-VALUE</code> can only be set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void storeReturnValue(boolean val)
throws ReturnUnwindException
{
returnWorker(null, logical.of(val), ReturnType.STORE);
}
/**
* Return from the nearest enclosing top-level block. Sets the default
* <code>RETURN-VALUE</code> to "" (empty string) for internal/external
* procedures and triggers. Leaves <code>unknown value</code> as the
* default return from a user-defined function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @throws ReturnUnwindException
*/
public static void returnConsume()
throws ReturnUnwindException
{
returnWorker(null, null, ReturnType.CONSUME);
}
/**
* Return from the nearest enclosing top-level block, consuming any pending
* event processing. Sets the <code>RETURN-VALUE</code> to the given value
* for internal/external procedures and triggers. Should not be called
* for a user-defined function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void returnConsume(character val)
throws ReturnUnwindException
{
returnWorker(val, ReturnType.CONSUME);
}
/**
* Return from the nearest enclosing top-level block, consuming any pending
* event processing. Sets the <code>RETURN-VALUE</code> to the given value
* for internal/external procedures and triggers. Sets the given value as
* the return value for a user-defined function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void returnConsume(String val)
throws ReturnUnwindException
{
returnWorker(new character(val), ReturnType.CONSUME);
}
/**
* Return from the nearest enclosing top-level block. Sets the default
* <code>RETURN-VALUE</code> to "" (empty string) for internal/external
* procedures and triggers. Leaves <code>unknown value</code> as the
* default return from a user-defined function.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void returnError()
throws ReturnUnwindException,
ErrorConditionException
{
returnWorker(null, null, ReturnType.ERROR);
}
/**
* Return from the nearest enclosing top-level block. If the given value
* is <code>null</code>, this sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* It leaves <code>unknown value</code> as the default return from a
* user-defined function. If the value is not <code>null</code>, then
* that value (if it is a <code>character</code> type) will be set as the
* <code>RETURN-VALUE</code> for internal/external procedures and triggers.
* If not <code>null</code>, the value will be returned as the function
* return value for user-defined functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void returnError(character val)
throws ReturnUnwindException,
ErrorConditionException
{
returnWorker(val, ReturnType.ERROR);
}
/**
* Return from the nearest enclosing top-level block. If the given value
* is <code>null</code>, this sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* It leaves <code>unknown value</code> as the default return from a
* user-defined function. If the value is not <code>null</code>, then
* that value will be set as the <code>RETURN-VALUE</code> for internal/
* external procedures and triggers. If not <code>null</code>, the value
* will be returned as the function return value for user-defined
* functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void returnError(String val)
throws ReturnUnwindException,
ErrorConditionException
{
returnWorker(new character(val), ReturnType.ERROR);
}
/**
* Return from the nearest enclosing top-level block by throwing the specified legacy error.
*
* @param error
* The error object.
*
* @throws LegacyErrorException
*/
public static void returnError(object<? extends LegacyError> error)
throws ReturnUnwindException,
ErrorConditionException
{
if (!error._isValid() || !LegacyError.class.isAssignableFrom(error.ref.getClass()))
{
ErrorManager.recordOrThrowError(14477,
"RETURN ERROR statement failed with an invalid error object",
false, false);
return;
}
WorkArea wa = work.get();
markReturnError(wa);
setReturnValue(wa, error.ref);
LegacyErrorException lex = new LegacyErrorException(error, true);
lex.setExplicit(true);
if (mustThrowLegacyError(wa, error.ref.getClass()))
{
throw lex;
}
else
{
wa.tm.triggerErrorInCaller(lex);
}
}
/**
* Execute the default block associated with a <code>CATCH</code> statement.
*
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void catchBlock(String label, Block block)
{
catchBlock(TransactionType.NONE, label, block);
}
/**
* Execute the default block associated with a <code>CATCH</code> statement.
*
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param block
* The code to execute.
*/
public static void catchBlock(TransactionType lvl, String label, Block block)
{
String[] enclosing = null;
block.pre();
BlockType blockType = BlockType.CATCH;
int ttype = convertTransType(lvl, blockType);
OnPhrase[] defOn = new OnPhrase[1];
defOn[0] = new OnPhrase(Condition.ERROR, Action.THROW, label);
WorkArea wa = work.obtain();
int props = decodeConditions(null, defOn);
wa.tm.pushScope(label, ttype, props, false, false, false, false, blockType);
try
{
// give the block a chance to initialize its state and don't
// repeat that during retry
block.init();
wa.tm.blockSetup();
blockLabel:
try
{
processBody(wa, block, null, defOn);
}
catch (LegacyErrorException lex)
{
processLegacyException(wa, lex);
}
catch (ConditionException ce)
{
wa.tm.notifyCondition(ce);
switch (processCondition(wa, null, defOn, ce, enclosing, "catchBlock"))
{
// note that this is not an iterating block so a leave or
// next targeted at this block must always act the same
case BREAK:
case CONTINUE:
break blockLabel;
default:
break;
}
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, "catchBlock") == Disposition.BREAK)
{
// the LEAVE targeted this block or an enclosing
// non-managed block
break blockLabel;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
if (testNext(wa, enclosing, "catchBlock") == Disposition.BREAK)
{
// the NEXT can't be targeted at this block BUT it can be
// targeted at an enclosing non-managed block
break blockLabel;
}
// the NEXT must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw nue;
}
catch (ReturnUnwindException rue)
{
// RETURN can't be targeted at a DO block so keep unwinding
throw rue;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
finally
{
wa.tm.popScope();
}
}
/**
* The CATCH statement. This API must be called from the Block's init method, and it will
* register a listener for the specified legacy error.
* <p>
* The catch order is the order of this API registration calls.
*
* @param type
* The CATCH's error type.
* @param catchBlock
* The code to be executed for this error.
*/
public static <T extends LegacyError> void catchError(Class<T> type,
Consumer<object<T>> catchBlock)
{
registerCatchBlock(type, catchBlock);
}
/**
* The CATCH statement. This API must be called from the Block's init method, and it will
* register a listener for the specified STOP condition.
* <p>
* The catch order is the order of this API registration calls.
*
* @param type
* The CATCH's stop error type.
* @param catchBlock
* The code to be executed for this error.
*/
public static <T extends Stop> void catchStop(Class<T> type,
Consumer<object<T>> catchBlock)
{
registerCatchBlock(type, catchBlock);
}
/**
* Execute the given catch block as if it was a simple DO block.
*
* @param body
* The catch block to execute.
*/
public static void processCatch(Body body)
{
doBlock("_catch_block_", new Block(body));
}
/**
* Trigger a rollback of the current block and then throw a legacy condition.
*
* @param error
* The legacy error to throw.
*/
public static void undoThrowTopLevel(object<? extends LegacyError> error)
{
if (!error._isValid())
{
String[] texts =
{
"You can only use a valid object reference in an UNDO, THROW or RETURN ERROR " +
"statement and it must be a class that implements Progress.Lang.Error",
"THROW statement failed"
};
int[] nums = {14117, 14456};
ErrorManager.recordOrThrowError(nums, texts, false, false);
return;
}
WorkArea wa = work.get();
BlockDefinition blk = wa.tm.getBlock();
if (blk.type == BlockType.CATCH)
{
// UNDO, THROW in a CATCH for a top-level block is emitted as 'undoThrowTopLevel'.
// but the behavior must be undoThrow.
undoThrow(error);
return;
}
wa.tm.rollbackTopLevel();
boolean fromReturn = setReturnValue(wa, error.ref);
LegacyErrorException lex = new LegacyErrorException(error, fromReturn);
lex.setExplicit(true);
// only RETURN ERROR is raised on the caller's side for an appserver call.
if (mustManageLegacyError(wa) && !(AppServerManager.isRemote() && !fromReturn))
{
wa.tm.triggerErrorInCaller(lex);
}
displayErrorMessages(wa.tm, lex.getErrorRef(), false, false);
throw lex;
}
/**
* Trigger a rollback of the current block and then throw a legacy STOP condition.
*
* @param stopError
* The legacy STOP error to throw.
*/
public static void undoThrowStopTopLevel(object<? extends Stop> stopError)
{
if (!stopError._isValid())
{
String[] texts =
{
"You can only use a valid object reference in an UNDO, THROW or RETURN" +
"statement and it must be a class that implements Progress.Lang.Stop",
"THROW statement failed"
};
int[] nums = {14117, 14456};
ErrorManager.recordOrThrowError(nums, texts, false, false);
return;
}
WorkArea wa = work.get();
BlockDefinition blk = wa.tm.getBlock();
if (blk.type == BlockType.CATCH)
{
// UNDO, THROW in a CATCH for a top-level block is emitted as 'undoThrowStopTopLevel'.
// but the behavior must be undoThrow.
undoThrowStop(stopError);
return;
}
wa.tm.rollbackTopLevel();
ErrorManager.handleStopException(stopError);
}
/**
* Trigger a rollback of the current block and then throw a legacy condition.
*
* @param error
* The legacy error to throw.
*/
public static void undoThrow(object<? extends LegacyError> error)
{
if (!error._isValid())
{
String[] texts =
{
"You can only use a valid object reference in an UNDO, THROW or RETURN ERROR " +
"statement and it must be a class that implements Progress.Lang.Error",
"THROW statement failed"
};
int[] nums = {14117, 14456};
ErrorManager.recordOrThrowError(nums, texts, false, false);
return;
}
WorkArea wa = work.obtain();
// TODO: any other processing?
setReturnValue(wa, error.ref);
if (!ErrorManager.hasLegacyError())
{
displayErrorMessages(wa.tm, error.ref, false, true);
}
LegacyErrorException lex = new LegacyErrorException(error);
lex.setExplicit(true);
throw lex;
}
/**
* Trigger a rollback of the current block and then throw a legacy STOP condition.
*
* @param stopError
* The legacy STOP error to throw.
*/
public static void undoThrowStop(object<? extends Stop> stopError)
{
if (!stopError._isValid())
{
String[] texts =
{
"You can only use a valid object reference in an UNDO, THROW" +
"statement and it must be a class that implements Progress.Lang.Stop",
"THROW statement failed"
};
int[] nums = {14117, 14456};
ErrorManager.recordOrThrowError(nums, texts, false, false);
return;
}
ErrorManager.handleStopException(stopError);
}
/**
* Trigger a rollback of the current block and then leave that block.
*
* @throws LeaveUnwindException
*/
public static void undoLeave()
throws LeaveUnwindException
{
undoLeave(null, "");
}
/**
* Trigger a rollback of the given block and then leave that block.
*
* @param label
* The name of the block that is the target of the undo and
* leave operations.
*
* @throws LeaveUnwindException
*/
public static void undoLeave(String label)
throws LeaveUnwindException
{
undoLeave(label, label);
}
/**
* Trigger a rollback of the given block and then leave that block or a
* more enclosing block.
* <p>
* If the current block is a variant of a FOR block, then the buffers
* associated with the block's query must not change the referenced
* record.
*
* @param undo
* The name of the block that is the target of the undo
* operation.
* @param leave
* The name of the block that is the target of the leave
* operation.
*
* @throws LeaveUnwindException
*/
public static void undoLeave(String undo, String leave)
throws LeaveUnwindException
{
WorkArea wa = work.obtain();
BlockType blk = wa.tm.getBlockType();
boolean forBlock = blk == BlockType.FOR_BLOCK ||
blk == BlockType.FOR_BLOCK_WHILE ||
blk == BlockType.FOR_BLOCK_TO ||
blk == BlockType.FOR_BLOCK_TO_WHILE ||
blk == BlockType.FOR_LOOP ||
blk == BlockType.FOR_LOOP_WHILE ||
blk == BlockType.FOR_LOOP_TO ||
blk == BlockType.FOR_LOOP_TO_WHILE;
try
{
if (forBlock)
{
wa.tm.processOffEndListeners(true);
}
wa.tm.rollback(undo);
leave(wa, leave);
}
finally
{
if (forBlock)
{
wa.tm.processOffEndListeners(false);
}
}
}
/**
* Trigger a rollback of the current block and then iterate that block.
* <p>
* Infinite loop protection may convert the NEXT action into a LEAVE
* depending on runtime state.
*
* @throws NextUnwindException
*/
public static void undoNext()
throws NextUnwindException
{
undoNext(null, "");
}
/**
* Trigger a rollback of the given block and then iterate that block.
* <p>
* Infinite loop protection may convert the NEXT action into a LEAVE
* depending on runtime state.
*
* @param label
* The name of the block that is the target of the undo and
* next operations.
*
* @throws NextUnwindException
*/
public static void undoNext(String label)
throws NextUnwindException
{
undoNext(label, label);
}
/**
* Trigger a rollback of the given block and then iterate that block or
* a more enclosing block.
* <p>
* Infinite loop protection may convert the NEXT action into a LEAVE
* depending on runtime state.
*
* @param undo
* The name of the block that is the target of the undo
* operation.
* @param next
* The name of the block that is the target of the next
* operation.
*
* @throws NextUnwindException
*/
public static void undoNext(String undo, String next)
throws NextUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(undo);
if (wa.tm.honorNext(next))
{
next(wa, next);
}
else
{
leave(wa, next);
}
}
/**
* Trigger a rollback of the current block and then retry that block.
*
* @throws RetryUnwindException
*/
public static void undoRetry()
throws RetryUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
wa.tm.forceRetry(null);
}
/**
* Trigger a rollback of the given block and then retry that block.
*
* @param label
* The name of the block that is the target of the undo and
* retry operations.
*
* @throws RetryUnwindException
*/
public static void undoRetry(String label)
throws RetryUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
wa.tm.forceRetry(label);
}
/**
* Trigger a rollback of the nearest enclosing top-level block and then
* retry that block.
*
* @throws RetryUnwindException
*/
public static void undoRetryTopLevel()
throws RetryUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
wa.tm.forceRetry(null);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code> to
* "" (empty string) for internal/external procedures and triggers. Leaves
* <code>unknown value</code> as the default return from a user-defined
* function.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal()
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, null, ReturnType.NORMAL);
}
/**
* Trigger a rollback and then return from the nearest enclosing top-level
* block. Sets the default <code>RETURN-VALUE</code> to "" (empty string)
* for internal/external procedures and triggers. Leaves
* <code>unknown value</code> as the default return from a user-defined
* function.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormalTopLevel()
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, null, ReturnType.NORMAL);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code> to
* "" (empty string) for internal/external procedures and triggers. Leaves
* <code>unknown value</code> as the default return from a user-defined
* function.
*
* @param label
* The name of the block that is the target of the undo
* operation.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(String label)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, null, ReturnType.NORMAL);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(BaseDataType val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, val, ReturnType.NORMAL);
}
/**
* Trigger a rollback of the nearest enclosing top-level block and then
* return from that block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormalTopLevel(BaseDataType val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, val, ReturnType.NORMAL);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(String label, BaseDataType val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, val, ReturnType.NORMAL);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(String label, String val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, new character(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the nearest enclosing top-level block and then
* return from that block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return or <code>null</code>. For procedures
* or triggers, this must be a <code>character</code> value.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormalTopLevel(String val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, new character(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. This should not be used for internal/external
* procedures and triggers, since the <code>RETURN-VALUE</code> can only be
* set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(int val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, new integer(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the nearest enclosing top-level block and then
* return from that block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormalTopLevel(int val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, new integer(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. This should not be used for internal/external
* procedures and triggers, since the <code>RETURN-VALUE</code> can only be
* set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(String label, int val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, new integer(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. This should not be used for internal/external
* procedures and triggers, since the <code>RETURN-VALUE</code> can only be
* set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(double val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, new decimal(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the nearest enclosing top-level block and then
* return from that block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormalTopLevel(double val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, new decimal(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. This should not be used for internal/external
* procedures and triggers, since the <code>RETURN-VALUE</code> can only be
* set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(String label, double val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, new decimal(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. This should not be used for internal/external
* procedures and triggers, since the <code>RETURN-VALUE</code> can only be
* set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(boolean val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, logical.of(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the nearest enclosing top-level block and then
* return from that block. Sets the <code>RETURN-VALUE</code> to the
* given <code>character</code> value for internal/external procedures and
* triggers. Saves the given value as the return value for a user-defined
* function. If <code>val</code> is <code>null</code>, then
* <code>RETURN-VALUE</code> will be set to the "" (empty string) for
* internal/external procedures and triggers. If <code>val</code> is
* <code>null</code> for a user-defined function,
* <code>unknown value</code> will be the default return.
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormalTopLevel(boolean val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, logical.of(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. This should not be used for internal/external
* procedures and triggers, since the <code>RETURN-VALUE</code> can only be
* set to a character expression.
* <p>
* For a user-defined function, this saves the given value as the function
* return value.
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return.
*
* @throws ReturnUnwindException
*/
public static void undoReturnNormal(String label, boolean val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, logical.of(val), ReturnType.NORMAL);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* Leaves <code>unknown value</code> as the default return from a
* user-defined function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsume()
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, null, ReturnType.CONSUME);
}
/**
* Trigger a rollback of and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* Leaves <code>unknown value</code> as the default return from a
* user-defined function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsumeTopLevel()
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, null, ReturnType.CONSUME);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block, consuming any pending event processing. Sets
* the <code>RETURN-VALUE</code> to the given value for internal/external
* procedures and triggers. Should not be called for a user-defined
* function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsume(character val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, val, ReturnType.CONSUME);
}
/**
* Trigger a rollback of and then return from the nearest
* enclosing top-level block, consuming any pending event processing. Sets
* the <code>RETURN-VALUE</code> to the given value for internal/external
* procedures and triggers. Should not be called for a user-defined
* function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsumeTopLevel(character val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, val, ReturnType.CONSUME);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* Leaves <code>unknown value</code> as the default return from a
* user-defined function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param label
* The name of the block that is the target of the undo
* operation.
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsume(String label)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, null, ReturnType.CONSUME);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block, consuming any pending event processing. Sets
* the <code>RETURN-VALUE</code> to the given value for internal/external
* procedures and triggers. Should not be called for a user-defined
* function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsume(String label, character val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, val, ReturnType.CONSUME);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block, consuming any pending event processing. Sets
* the <code>RETURN-VALUE</code> to the given value for internal/external
* procedures and triggers. Should not be called for a user-defined
* function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsume(String label, String val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, new character(val), ReturnType.CONSUME);
}
/**
* Trigger a rollback of and then return from the nearest
* enclosing top-level block, consuming any pending event processing. Sets
* the <code>RETURN-VALUE</code> to the given value for internal/external
* procedures and triggers. Should not be called for a user-defined
* function.
* <p>
* If executed for a trigger, force the event which caused the trigger
* execution to be consumed (no default processing of that event should
* occur).
*
* @param val
* The value to return or <code>null</code>.
*
* @throws ReturnUnwindException
*/
public static void undoReturnConsumeTopLevel(String val)
throws ReturnUnwindException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, new character(val), ReturnType.CONSUME);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* Leaves <code>unknown value</code> as the default return from a
* user-defined function.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnError()
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, null, ReturnType.ERROR);
}
/**
* Trigger a rollback of and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* Leaves <code>unknown value</code> as the default return from a
* user-defined function.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnErrorTopLevel()
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, null, ReturnType.ERROR);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
* to "" (empty string) for internal/external procedures and triggers.
* Leaves <code>unknown value</code> as the default return from a
* user-defined function.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param label
* The name of the block that is the target of the undo
* operation.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnError(String label)
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, null, ReturnType.ERROR);
}
/**
* Trigger a rollback of the current block and then return from the nearest
* enclosing top-level block. If the given value is <code>null</code>,
* this sets the default <code>RETURN-VALUE</code> to "" (empty string)
* for internal/external procedures and triggers. It leaves
* <code>unknown value</code> as the default return from a user-defined
* function. If the value is not <code>null</code>, then that value (if
* it is a <code>character</code> type) will be set as the
* <code>RETURN-VALUE</code> for internal/external procedures and triggers.
* If not <code>null</code>, the value will be returned as the function
* return value for user-defined functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnError(character val)
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollback();
returnWorker(wa, val, ReturnType.ERROR);
}
/**
* Trigger a rollback of and then return from the nearest
* enclosing top-level block. If the given value is <code>null</code>,
* this sets the default <code>RETURN-VALUE</code> to "" (empty string)
* for internal/external procedures and triggers. It leaves
* <code>unknown value</code> as the default return from a user-defined
* function. If the value is not <code>null</code>, then that value (if
* it is a <code>character</code> type) will be set as the
* <code>RETURN-VALUE</code> for internal/external procedures and triggers.
* If not <code>null</code>, the value will be returned as the function
* return value for user-defined functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnErrorTopLevel(character val)
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, val, ReturnType.ERROR);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. If the given value is <code>null</code>,
* this sets the default <code>RETURN-VALUE</code> to "" (empty string)
* for internal/external procedures and triggers. It leaves
* <code>unknown value</code> as the default return from a user-defined
* function. If the value is not <code>null</code>, then that value (if
* it is a <code>character</code> type) will be set as the
* <code>RETURN-VALUE</code> for internal/external procedures and triggers.
* If not <code>null</code>, the value will be returned as the function
* return value for user-defined functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnError(String label, character val)
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, val, ReturnType.ERROR);
}
/**
* Trigger a rollback of the given block and then return from the nearest
* enclosing top-level block. If the given value is <code>null</code>,
* this sets the default <code>RETURN-VALUE</code> to "" (empty string)
* for internal/external procedures and triggers. It leaves
* <code>unknown value</code> as the default return from a user-defined
* function. If the value is not <code>null</code>, then that value (if
* it is a <code>character</code> type) will be set as the
* <code>RETURN-VALUE</code> for internal/external procedures and triggers.
* If not <code>null</code>, the value will be returned as the function
* return value for user-defined functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param label
* The name of the block that is the target of the undo
* operation.
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnError(String label, String val)
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollback(label);
returnWorker(wa, new character(val), ReturnType.ERROR);
}
/**
* Trigger a rollback of and then return from the nearest
* enclosing top-level block. If the given value is <code>null</code>,
* this sets the default <code>RETURN-VALUE</code> to "" (empty string)
* for internal/external procedures and triggers. It leaves
* <code>unknown value</code> as the default return from a user-defined
* function. If the value is not <code>null</code>, then that value (if
* it is a <code>character</code> type) will be set as the
* <code>RETURN-VALUE</code> for internal/external procedures and triggers.
* If not <code>null</code>, the value will be returned as the function
* return value for user-defined functions.
* <p>
* If silent error mode is not enabled in the caller, an <code>ERROR</code>
* condition will be raised here and will unwind the stack (it will not
* be processed, but will instead it will be rethrown) until it reaches
* the caller's context at which time the error will be honored. If silent
* error mode is enabled, the error data will be stored in the
* <code>ERROR-STATUS</code> facility and a return will be executed to
* return processing to the caller without raising the error condition
* (without throwing an exception).
*
* @param val
* The value to return.
*
* @throws ReturnUnwindException
* @throws ErrorConditionException
*/
public static void undoReturnErrorTopLevel(String val)
throws ReturnUnwindException,
ErrorConditionException
{
WorkArea wa = work.obtain();
wa.tm.rollbackTopLevel();
returnWorker(wa, new character(val), ReturnType.ERROR);
}
/**
* Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is
* BLOCK-LEVEL UNDO, THROW.
*
* @return see above.
*/
static boolean mustManageLegacyError()
{
return mustManageLegacyError(work.obtain());
}
/**
* Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is
* BLOCK-LEVEL UNDO, THROW.
*
* @param wa
* The {@link WorkArea} instance.
* @param forceBlockLevelUndoThrow
* Flag indicating that, when nothing else matches, a BLOCK-LEVEL UNDO, THROW exists by default.
*
* @return see above.
*/
static boolean mustManageLegacyError(WorkArea wa, boolean forceBlockLevelUndoThrow)
{
return wa.pm._thisProcedure() != null &&
(forceBlockLevelUndoThrow ||
(wa.tm.isRootNestingLevel() && AppServerManager.isRemote() && wa.pm.isRoutineLevelUndoThrow()) ||
(wa.tm.isTopLevelBlock() && wa.pm.isRoutineLevelUndoThrow()) ||
wa.pm.isBlockLevelUndoThrow());
}
/**
* Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is
* BLOCK-LEVEL UNDO, THROW.
*
* @param forceBlockLevelUndoThrow
* Flag indicating that, when nothing else matches, a BLOCK-LEVEL UNDO, THROW exists by default.
*
* @return see above.
*/
static boolean mustManageLegacyError(boolean forceBlockLevelUndoThrow)
{
return mustManageLegacyError(work.obtain(), forceBlockLevelUndoThrow);
}
/**
* Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is
* BLOCK-LEVEL UNDO, THROW.
*
* @param wa
* The {@link WorkArea} instance.
*
* @return see above.
*/
static boolean mustManageLegacyError(WorkArea wa)
{
return wa.pm._thisProcedure() != null &&
((wa.tm.isRootNestingLevel() && AppServerManager.isRemote() && wa.pm.isRoutineLevelUndoThrow()) ||
(wa.tm.isTopLevelBlock() && wa.pm.isRoutineLevelUndoThrow()) ||
wa.pm.isBlockLevelUndoThrow());
}
/**
* Check whether the -catchStop startup parameter is set on 1.
*
* @param wa
* The {@link WorkArea} instance.
*
* @return see above.
*/
static boolean mustManageLegacyStop(WorkArea wa)
{
return wa.catchStopParameter != 0;
}
/**
* Check if we must throw a legacy compatible OO error. This will happen if either
* {@link #mustManageLegacyError()} or anywhere on the stack the specified error is handled
* by a CATCH block.
*
* @param errorClass
* The error class to be throw.
*
* @return See above.
*/
static boolean mustThrowLegacyError(Class<? extends LegacyError> errorClass)
{
return mustThrowLegacyError(work.obtain(), errorClass);
}
/**
* Check if we must throw a legacy compatible OO error. This will happen if either
* {@link #mustManageLegacyError()} or anywhere on the stack the specified error is handled
* by a CATCH block.
*
* @param errorClass
* The error class to be throw.
*
* @return See above.
*/
static boolean mustThrowLegacyError(WorkArea wa, Class<? extends LegacyError> errorClass)
{
return mustManageLegacyError(wa) || hasLegacyError(wa, errorClass, 1);
}
/**
* Check if any CATCH blocks defined at the specified enclosing block can manage this exception.
* <p>
* If none found, ignore this exception. 4GL doesn't seem to propagate the errors further than
* then current block.
*
* @param type
* The error type to process.
* @param levels
* Flag indicating which block to use (0 for current, 1 for parent, etc). Use -1 to search the
* entire stack.
*
* @return <code>true</code> if this exception can be processed by the current block.
*/
static boolean hasLegacyError(Class<? extends LegacyError> type, int levels)
{
return hasLegacyError(work.obtain(), type, levels);
}
/**
* Check if any CATCH blocks defined at the specified enclosing block can manage this stop exception.
* <p>
* If none found, ignore this exception. 4GL doesn't seem to propagate the errors further than
* then current block.
*
* @param type
* The error type to process.
* @param levels
* Flag indicating which block to use (0 for current, 1 for parent, etc). Use -1 to search the
* entire stack.
*
* @return <code>true</code> if this exception can be processed by the current block.
*/
static boolean hasLegacyStop(Class<? extends Stop> type)
{
return hasLegacyStop(work.obtain(), type);
}
/**
* Returns the type of return processing from the nearest top-level block.
* The returned value is the value passed to {@link #returnWorker(WorkArea, Object, ReturnType)}.
* <p>
* The value is valid from the time the converted code implementing the top-level
* block is exited until after {@link Scopeable#scopeFinished()} is called.
*
* @return Type of return processing value or <code>null</code> if the nearest
* top-level code is not finished by execution of
* {@link #returnWorker(WorkArea, Object, ReturnType)}.
*/
static ReturnType getReturnType()
{
return work.get().rtype;
}
/**
* Get the function's return value.
*
* @return The latest {@link WorkArea#funcRet} value.
*/
static Object getFunctionReturn()
{
Object ret = work.get().funcRet.peek();
return ret == null || ret == NULL ? null : ret;
}
/**
* Check the {@link WorkArea#funcRet} stack for the supplied condition.
*
* @param func
* The condition to check.
*
* @return <code>true</code> if the condition applies to any of object in the return stack.
*/
static boolean checkFunctionReturn(Function<Object, Boolean> func)
{
// only the top caller can have something to return 'in progress', everything else is still executing
Object ret = work.get().funcRet.peek();
if (ret == null)
{
return false;
}
if (ret.getClass().isArray())
{
int size = Array.getLength(ret);
for (int j = 0; j < size; j++)
{
Object aret = Array.get(ret, j);
if (func.apply(aret))
{
return true;
}
}
}
else
{
return func.apply(ret);
}
return false;
}
/**
* Get an instance of {@link ProcedureHelper}, which has the context-local instance saved,
* so API access can be done without a context-local query.
*
* @return See above.
*/
static BlockManagerHelper getHelper()
{
return new BlockManagerHelper(work.get());
}
/**
* Check if the <code>ErrorConditionException</code> was triggered in the caller and
* throw a <code>LegacyErrorException</code>
*
* @param exc
* The RuntimeException to propagate
*/
private static void checkLegacyError(RuntimeException exc)
{
if (exc instanceof ErrorConditionException && ((ErrorConditionException) exc).isTriggeredInCaller())
{
object<? extends SysError> legacyError = SysError.newInstance(
exc.getMessage(),
((ErrorConditionException) exc).getProgressErrorCode());
throw new LegacyErrorException(legacyError);
}
throw exc;
}
/**
* Execute the given top-level block with the given transaction level.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The instance of the containing business logic class from which this is being
* called. For external procedures, if this is non-null, then <code>block</code>
* can be an instance created using lambdas. If <code>null</code>, then
* <code>block</code> MUST BE an anonymous inner class of the containing business
* logic instance so that instance can be calculated via reflection. For internal
* procedures and triggers, this is expected to be <code>null</code>.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param lvl
* The transaction level for the given block.
* @param btype
* The type of block represented by the given code.
* @param block
* The code to execute.
*/
static void topLevelBlock(Class<?> def,
Object referent,
String legacyName,
TransactionType lvl,
BlockType btype,
Block block)
{
long start = 0;
if (statsFile != null)
{
start = System.currentTimeMillis();
}
if (def == null && referent != null && referent.getClass() == Class.class)
{
def = (Class<?>) referent;
}
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
int ttype = convertTransType(lvl, btype);
boolean etype = (btype == BlockType.EXTERNAL_PROC);
boolean ptype = (btype == BlockType.INTERNAL_PROC);
WorkArea wa = work.obtain();
// this checks if current block if current is either:
// - session database trigger, so with trigger block type
// - schema database trigger, so with external procedure block type
// and database trigger referent
boolean databaseTrigger = (etype &&
referent != null &&
referent instanceof com.goldencode.p2j.persist.trigger.DatabaseTrigger) ||
btype == BlockType.DATABASETRIGGER;
// external and internal procedures are allowed to be invoked outside of ControlFlowOps APIs
// only from hand-written java code, but the conversion code emits only ControlFlowOps APIs
// constructors are also invoked without ControlFlowOps APIs (emulated via internal proc).
boolean javaCall = (etype || ptype);
if (javaCall)
{
Boolean check = checkJavaCall(wa, def, referent, legacyName, block, false, etype, false);
if (check == null)
{
return;
}
javaCall = check;
}
OutputParameterAssigner opa = wa.tm.deregisterOutputParameterAssigner();
String calleeName = ""; // opa will need this back when performing exit checks
wa.tm.pushScope("methodScope",
ttype,
(PROP_ERROR | PROP_ENDKEY),
etype,
true,
false,
false,
databaseTrigger,
btype);
// add a scope to our list of function return values and block types
wa.topType.push(btype);
try
{
methodScope:
{
// give the block a chance to initialize its state and don't
// repeat that during retry
block.init();
wa.tm.blockSetup();
do
{
try
{
processBody(wa, block, null, null);
}
catch (LegacyErrorException lex)
{
processLegacyException(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStopException(wa, lex);
}
catch (ErrorConditionException err)
{
wa.tm.notifyCondition(err);
wa.tm.honorError(err);
wa.tm.rollback("methodScope");
wa.tm.triggerRetry("methodScope");
}
catch (StopConditionException err)
{
wa.tm.notifyCondition(err);
wa.tm.rollback("methodScope");
throw err;
}
catch (InvalidParameterConditionException ipe)
{
wa.tm.notifyCondition(Condition.ERROR);
wa.tm.rollback("methodScope");
throw new ErrorConditionException(ipe.getCause());
}
catch (EndConditionException end)
{
wa.tm.notifyCondition(end);
wa.tm.rollback("methodScope");
break methodScope;
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (StackUnwindException sue)
{
// we have unwound to the exit point, break out (it doesn't
// matter whether we need to exit because of a LEAVE, NEXT
// or a RETURN, they all have the same result on a top-level
// block
break methodScope;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
}
}
catch (RuntimeException exc)
{
// cleaning up the OPA inside this catch only works because "normal"
// control flow exceptions are caught and handled before they would
// cross the top-level block boundary
if (opa != null)
{
opa.abort();
}
checkLegacyError(exc);
}
finally
{
if (opa != null)
{
if (wa.rtype == BlockManager.ReturnType.ERROR)
{
opa.abort();
}
else
{
calleeName = wa.pm.getStackEntry(0);
}
}
try
{
wa.tm.popScope();
}
catch (RuntimeException exc)
{
if (opa != null)
{
opa.abort();
}
throw exc;
}
finally
{
// cleanup our top level block state
exitTopLevel(wa);
wa.rtype = null;
if (javaCall && (etype || ptype))
{
wa.pm.popCalleeInfo();
}
}
if (statsFile != null)
{
recordExecutionStats(btype, block, start);
}
}
// process assign-backs to database fields from output parameters, if any
if (opa != null &&
(btype == BlockType.EXTERNAL_PROC ||
btype == BlockType.INTERNAL_PROC))
{
opa.processAssignments(calleeName, !(etype || ptype));
}
}
/**
* Register the abend code to be executed when the next top-level block needs to be invoked, as the
* argument assignment failed.
*
* @param abend
* The code to execute instead of the top-level block.
*/
static void ignoreNextCall(Runnable abend)
{
WorkArea wa = work.get();
if (wa.ignoreNextCall == null)
{
wa.ignoreNextCall = abend;
}
}
/**
* If the error referenced is an {@link AppError}, then also set the
* {@link ControlFlowOps#setReturnValue RETURN-VALUE}.
*
* @param wa
* Context local work area. Must not be {@code null}.
* @param err
* The error being processed.
*
* @return <code>true</code> if this is referencing an {@link AppError} instance.
*/
private static boolean setReturnValue(WorkArea wa, LegacyError err)
{
boolean fromRetVal = false;
if (err instanceof AppError)
{
character retVal = ((AppError) err).getReturnValue();
fromRetVal = true;
if (retVal != null && !retVal.isUnknown() && !retVal.toStringMessage().isEmpty())
{
wa.cfops.setReturnValue(retVal);
}
}
return fromRetVal;
}
/**
* Break out of the block associated with the given label. This will
* unwind the stack until the proper block has been reached. At that
* point the block will be left using the Java "break" statement.
*
* @param wa
* Context local work area. Must not be {@code null}.
* @param label
* The name of the block to be left.
*
* @throws LeaveUnwindException
*/
private static void leave(WorkArea wa, String label)
throws LeaveUnwindException
{
if (label != null)
{
wa.deferredLeave = label;
}
throw wa.leaveExc;
}
/**
* Continue (iterate) the block associated with the given label. This will
* unwind the stack until the proper block has been reached. At that
* point the block will be iterated using the Java "continue" statement.
*
* @param wa
* Context local work area. Must not be {@code null}.
* @param label
* The name of the block to be iterated.
* @throws NextUnwindException
*/
private static void next(WorkArea wa, String label)
throws NextUnwindException
{
if (label != null)
{
wa.deferredNext = label;
}
throw wa.nextExc;
}
/**
* Check if we this call is a java-style call or is from {@link ControlFlowOps} APIs. If is
* not from {@link ControlFlowOps}, then resolve {@link ProcedureManager.ProcedureHelper#pushCalleeInfo push
* the callee info}.
*
* @param wa
* Context local work area. Must not be {@code null}.
* @param referent
* The instance of the containing business logic class from which this is being
* called. For external procedures, if this is non-null, then <code>block</code>
* can be an instance created using lambdas. If <code>null</code>, then
* <code>block</code> MUST BE an anonymous inner class of the containing business
* logic instance so that instance can be calculated via reflection. For internal
* procedures and functions, this is expected to be <code>null</code>.
* @param def
* The currently executing OE class or external program.
* @param legacyName
* The legacy name associated with the function/procedure being invoked via a
* java-style call. If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param block
* The {@link Block} insance beeing executed.
* @param function
* Flag indicating if we are calling a function.
* @param externalProgram
* Flag indicating if we are calling an external program.
* @param persistentProc
* Flag indicating if the called external program is persistent.
*
* @return {@code true} if we are in a java-style call, <code>null</code> if we need to abend.
*/
private static Boolean checkJavaCall(WorkArea wa,
Class<?> def,
Object referent,
String legacyName,
Block block,
boolean function,
boolean externalProgram,
boolean persistentProc)
{
if (referent != null && referent instanceof Class)
{
// there is at least a case where ObjectOps.load is emitted in the Block.init method,
// and not in the Java method. Anyway, we always emit the 'class referent', so we can
// load it here
wa.objHelper.load((Class) referent);
}
boolean javaCall = !wa.pendingDynCall;
wa.pendingDynCall = false;
if (wa.ignoreNextCall != null)
{
try
{
wa.ignoreNextCall.run();
}
finally
{
wa.ignoreNextCall = null;
}
return null;
}
if (javaCall)
{
String iename;
String pname;
Class<?> defref = def;
if (externalProgram)
{
// OO method call has a non-null referent
if (referent == null)
{
referent = ProcedureManager.findRootEnclosingInstance(block);
}
else if (referent instanceof Class)
{
defref = (Class<?>) referent;
referent = ObjectOps.getStaticInstance((Class<? extends _BaseObject_>) referent);
}
// safety first, this call won't work
if (referent == null)
{
ErrorManager.handleStopException("Invalid referent in external procedure call.");
}
iename = ProcedureManager.EXTERNAL_PROGRAM;
pname = SourceNameMapper.convertJavaProgSafe(referent.getClass().getName());
}
else
{
// OO method call has a non-null referent
if (referent == null)
{
referent = wa.pm._thisProcedure();
}
else if (referent instanceof Class)
{
defref = (Class<?>) referent;
referent = ObjectOps.getStaticInstance((Class<? extends _BaseObject_>) referent);
}
// we need to determine the legacy name of this call, so we can push it to the call
// stack. fortunately, unlike the external program names, the internal entry names are
// reported as they are defined, not called
if (legacyName == null)
{
iename = ProcedureManager.resolveClosestMethod(referent, function, externalProgram);
}
else
{
iename = legacyName;
}
pname = null;
}
if (defref == null)
{
if (referent.getClass() == Class.class)
{
defref = (Class<?>) referent;
}
else if (referent.getClass() == Object.class)
{
defref = ObjectOps.getStaticClass(referent);
}
else
{
defref = referent.getClass();
}
}
wa.pm.pushCalleeInfo(defref, false, referent, referent, iename, pname, function, persistentProc);
wa.pm.peekCalleeInfo().setLegacyName(iename);
}
return javaCall;
}
/**
* Implements the body of all blocks or loops that are not related to the
* <code>FOR</code> language statement. The main feature is to ensure that
* any normal exit from the body will notify any <code>Commitable</code>
* instances for validation purposes. A normal exit is a non-exception
* return from {@link Block#body}, or certain exception cases related to
* <code>LEAVE</code>, <code>NEXT</code>, <code>RETURN</code> or
* <code>QUIT</code> when they are not associated with an <code>UNDO</code>.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param block
* The block to execute.
* @param on
* List of user-defined ON phrases. May be {@code null}.
* @param defOn
* List of implicit ON phrases for this block. May be {@code null}.
*/
private static void processBody(WorkArea wa, Block block, OnPhrase[] on, OnPhrase[] defOn)
throws Throwable
{
Throwable reason = null;
try
{
// check the interrupted status and throw the stop condition if needed
wa.tm.honorStopCondition();
block.body();
// check the interrupted status and throw the stop condition if needed
wa.tm.honorStopCondition();
}
catch (DeferredLegacyErrorException dlex)
{
LegacyErrorException lex = ErrorManager.getDeferredLegacyError();
processLegacyError(wa, lex, on, defOn);
}
catch (LegacyErrorException lex)
{
processLegacyError(wa, lex, on, defOn);
}
catch (DeferredLegacyStopException dlex)
{
LegacyStopException lex = ErrorManager.getDeferredLegacyStop();
processLegacyStop(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStop(wa, lex);
}
catch (ConditionException e)
{
wa.tm.errHlp.addNumbersToConditionException(e);
reason = e;
}
catch (Throwable thr)
{
reason = thr;
}
finally
{
if (wa.tm.isTransaction() && (reason == null || isNormal(wa, reason, on)))
{
executeStateManaged(wa, wa.tm::processValidate);
}
// the body executed at least once, so the fini() method must be called too
if (block.hasFini())
{
// we cannot execute the FINALLY block here; it must be deferred to the end of iterate,
// retry or block exit
TransactionType lvl = block.finiMethod.getTransactionType();
Block finiAsBlock = new Block((Body) block::fini);
wa.tm.setupFinallyBlock(() -> doTerminationBlockWorker(wa,
lvl,
FINALLY_BLOCK_LABEL,
true,
finiAsBlock));
}
if (reason != null)
{
throw reason;
}
}
}
/**
* Implements the body of all <code>FOR</code> language statement blocks or
* loops. The main feature is to ensure that any normal exit from the body
* will notify any <code>Commitable</code> instances for validation
* purposes. A normal exit is a non-exception return from {@link Block#body},
* or certain exception cases related to <code>LEAVE</code>,
* <code>NEXT</code>, <code>RETURN</code> or <code>QUIT</code> when they are
* not associated with an <code>UNDO</code>.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param block
* The block to execute.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined ON phrases. May be {@code null}.
* @param defOn
* List of implicit ON phrases for this block. May be {@code null}.
*
* @return <code>true</code> if the code should break out of the block
* on return (because the loop/block control expressions or
* incrementer forced an exit).
*/
private static boolean processForBody(WorkArea wa,
Block block,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
OnPhrase[] defOn)
throws Throwable
{
Throwable reason = null;
boolean needsBreak = false;
boolean bodyRan = false;
try
{
wa.tm.honorStopCondition();
// retrieve the record (only used in cases where there is a TO and/or WHILE)
if (to != null || expr != null)
{
block.enter();
}
// evaluate any TO or WHILE condition and execute the block
// body if both are null or when all non-null expressions
// evaluate true; otherwise never execute the block body
if (needsIterate(to, expr))
{
bodyRan = true;
block.body();
wa.tm.honorStopCondition();
}
else
{
needsBreak = true;
}
}
catch (DeferredLegacyErrorException dlex)
{
LegacyErrorException lex = ErrorManager.getDeferredLegacyError();
processLegacyError(wa, lex, on, defOn);
}
catch (LegacyErrorException lex)
{
processLegacyError(wa, lex, on, defOn);
}
catch (DeferredLegacyStopException dlex)
{
LegacyStopException lex = ErrorManager.getDeferredLegacyStop();
processLegacyStop(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStop(wa, lex);
}
catch (Throwable thr)
{
// for now, we are still processing the query as the first statement in the body
// but this is known to cause some deviations in transaction state; one of the
// problems that we fixup here is that the body doesn't really execute in this
// case but without this code we would think that it had executed
if (thr instanceof QueryOffEndException)
{
bodyRan = false;
}
reason = thr;
}
finally
{
if (reason == null || isNormal(wa, reason, on))
{
executeStateManaged(wa, wa.tm::processValidate);
}
// if the body executed then the fini() method must be called too
if (bodyRan && block.hasFini())
{
// we cannot execute the FINALLY block here; it must be deferred to the end of iterate,
// retry or block exit
TransactionType lvl = block.finiMethod.getTransactionType();
Block finiAsBlock = new Block((Body) block::fini);
wa.tm.setupFinallyBlock(() -> doTerminationBlockWorker(wa,
lvl,
FINALLY_BLOCK_LABEL,
true,
finiAsBlock));
}
if (reason != null)
{
throw reason;
}
}
return needsBreak;
}
/**
* Detect if an exception represents a normal or abnormal condition.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param thr
* The exception to analyze.
* @param on
* List of user-defined on phrases.
*
* @return <code>true</code> if the exception is a normal control-flow
* condition.
*/
private static boolean isNormal(WorkArea wa, Throwable thr, OnPhrase[] on)
{
// no exception means normal
if (thr == null)
{
return true;
}
// LEAVE, NEXT and RETURN
if (thr instanceof StackUnwindException)
{
// check if an UNDO is NOT in effect
if (!wa.tm.hadRollback())
{
return true;
}
}
// QUIT
if (thr instanceof QuitConditionException)
{
// if there are no user-defined ON phrases, then a QUIT is always
// a commit instead of a rollback
if (on == null)
{
return true;
}
// look for a user-defined ON QUIT phrase
OnPhrase imple = matchCondition(on, null, Condition.QUIT);
// if none, then QUIT will be a commit not a rollback
if (imple == null)
{
return true;
}
}
return false;
}
/**
* Detect if there is a pending leave for the block named by the given
* label. If so, this deferred leave flag will be cleared and
* <code>true</code> will be returned. The caller is responsible for
* ensuring that the leave request is fully granted as no further state
* will be available for subsequent processing.
*
* @param wa
* Local context.
* @param label
* The name of the block to be checked against the deferred
* leave block name.
*
* @return <code>true</code> if there is a pending deferred leave and
* the name of the block to be left is the same as the given
* label. If the pending deferred block name is the "" (empty
* string), that is the equivalent of matching "any block" and
* so the first call to this method after that is set will cause
* a <code>true</code> to be returned.
*/
private static boolean deferredLeaveWorker(WorkArea wa, String label)
{
if (wa == null)
wa = work.obtain();
if (wa.deferredLeave != null && label != null)
{
if (label.equals(wa.deferredLeave) || wa.deferredLeave.length() == 0)
{
// clear state
wa.deferredLeave = null;
return true;
}
}
return false;
}
/**
* Detect if there is a pending next for the block named by the given
* label. If so, this deferred next flag will be cleared and
* <code>true</code> will be returned. The caller is responsible for
* ensuring that the next request is fully granted as no further state
* will be available for subsequent processing.
*
* @param wa
* Local context.
* @param label
* The name of the block to be checked against the deferred
* next block name.
*
* @return <code>true</code> if there is a pending deferred next and
* the name of the block to be iterated is the same as the given
* label. If the pending deferred block name is the "" (empty
* string), that is the equivalent of matching "any block" and
* so the first call to this method after that is set will cause
* a <code>true</code> to be returned.
*/
private static boolean deferredNextWorker(WorkArea wa, String label)
{
if (wa == null)
wa = work.obtain();
if (wa.deferredNext != null && label != null)
{
if (label.equals(wa.deferredNext) || wa.deferredNext.length() == 0)
{
// clear state
wa.deferredNext = null;
return true;
}
}
return false;
}
/**
* Return from the nearest enclosing top-level block. This will process
* differently based on the type of the top-level block (internal/external
* procedures, triggers or user-defined functions), the type of return
* processing that is requested (see {@link ReturnType}) and the presence
* or absence of a value to return.
* <p>
* The following behavior is provided:
* <p>
* <pre>
* Codes Meaning
* ------ -----------------------------------------------------
* C Invoke LogicalTerminal.consume()
* E Invoke TransactionManager.triggerErrorInCaller()
* V Invoke ControlFlowOps.setReturnValue(val)
* N Invoke ControlFlowOps.setReturnValue("")
* F Invoke setFuncReturn(val)
* U Invoke setFuncReturn(null) (set return value as unknown)
* I Invalid (compile error in Progress)
*
* Return Return Internal External Trigger Function
* Value Type Proc Proc
* -------- --------- -------- -------- ------- --------
* null NORMAL N N N U
* non-null NORMAL V V V F
* null CONSUME N N NC U
* non-null CONSUME V V VC F
* null ERROR NE NE I U
* non-null ERROR VE VE I U
* </pre>
* <p>
* In all cases, a {@link ReturnUnwindException} will be thrown and this
* will cause the stack to unwind to the nearest enclosing top-level
* block. That block will then handle the return in a block specific
* manner. For example, in a user-defined function, the given value or
* by default the <code>unknown value</code> will be returned to the
* caller. Procedures and triggers have void return values.
*
* @param val
* The value to return.
* @param rtype
* The type of return processing.
*/
private static void returnWorker(BaseDataType val, ReturnType rtype)
throws ReturnUnwindException
{
returnWorker(null, val, rtype);
}
/**
* Return from the nearest enclosing top-level block. This will process
* differently based on the type of the top-level block (internal/external
* procedures, triggers or user-defined functions), the type of return
* processing that is requested (see {@link ReturnType}) and the presence
* or absence of a value to return.
* <p>
* The following behavior is provided:
* <p>
* <pre>
* Codes Meaning
* ------ -----------------------------------------------------
* C Invoke LogicalTerminal.consume()
* E Invoke TransactionManager.triggerErrorInCaller()
* V Invoke ControlFlowOps.setReturnValue(val)
* N Invoke ControlFlowOps.setReturnValue("")
* F Invoke setFuncReturn(val)
* U Invoke setFuncReturn(null) (set return value as unknown)
* I Invalid (compile error in Progress)
*
* Return Return Internal External Trigger Function
* Value Type Proc Proc
* -------- --------- -------- -------- ------- --------
* null NORMAL N N N U
* non-null NORMAL V V V F
* null CONSUME N N NC U
* non-null CONSUME V V VC F
* null ERROR NE NE I U
* non-null ERROR VE VE I U
* </pre>
* <p>
* In all cases, a {@link ReturnUnwindException} will be thrown and this
* will cause the stack to unwind to the nearest enclosing top-level
* block. That block will then handle the return in a block specific
* manner. For example, in a user-defined function, the given value or
* by default the <code>unknown value</code> will be returned to the
* caller. Procedures and triggers have void return values.
*
* @param wa
* Context local data or {@code null} if not available in caller.
* @param val
* The value to return. If the function doesn't return an extent value, the element
* zero will be returned.
* @param rtype
* The type of return processing.
*/
private static void returnWorker(WorkArea wa, Object val, ReturnType rtype)
throws ReturnUnwindException
{
if (wa == null)
wa = work.obtain();
BlockType nearest = topLevelType(wa);
boolean skipThrowLegacyError = false;
// save the return processing type
boolean store = (rtype == ReturnType.STORE);
boolean retError = (rtype == ReturnType.ERROR);
if (retError)
{
markReturnError(wa);
}
if (store)
{
rtype = ReturnType.NORMAL;
}
wa.rtype = rtype;
if (nearest != null)
{
switch (nearest)
{
case DATABASETRIGGER:
case TRIGGER:
if (rtype == ReturnType.CONSUME)
{
LogicalTerminal.consumeEvent();
}
else if (retError)
{
String err = "RETURN ERROR is not allowed in a TRIGGER";
throw new IllegalArgumentException(err);
}
// fall through so that return-value is also set
case INTERNAL_PROC:
case EXTERNAL_PROC:
if (rtype == ReturnType.CONSUME && isPersistentTriggerTopLevel(wa))
{
LogicalTerminal.consumeEvent();
}
if (val == null)
{
wa.cfops.setReturnValue("");
}
else
{
// the return value should always be of type character
// but this code just makes it safer
if (val instanceof unknown)
{
wa.cfops.setReturnValue(new character());
}
else if (val instanceof character)
{
character retVal = (character) val;
wa.cfops.setReturnValue(retVal);
}
}
break;
case FUNCTION:
// In the error case, even if a value is passed, it will be
// forced to null; in the non-error cases if the value is null
// then the result will be setting the return to unknown value
// and if the value is not null, then that value will be set as
// the return value.
setFuncReturn(retError ? null : val, wa, nearest);
// Quirk: 'return error' in ABL method *does* set error-status:error
// to true, while an ABL function leaves error-status as is.
// Proof: xfer testcases rev 1274.
CalleeInfo calinfo = (retError ? wa.pm.peekCalleeInfo() : null);
// To avoid unnecessary peek calls, we only call isMethod() if needed further on.
if (calinfo == null || !calinfo.isMethod())
{
skipThrowLegacyError = true;
}
break;
default:
break;
}
}
// functions don't raise error in the calling scope, methods do.
if (retError && !skipThrowLegacyError)
{
if (mustThrowLegacyError(wa, AppError.class))
{
try
{
// reset before the 'newInstance' call
wa.rtype = null;
object<? extends AppError> err = AppError.newInstance(ControlFlowOps.getReturnValue());
err.ref.setFromReturn(true);
LegacyErrorException lex = new LegacyErrorException(err, true);
lex.setExplicit(true);
wa.tm.triggerErrorInCaller(lex);
throw lex;
}
finally
{
// set this again, as it gets changed by 'AppError.newInstance'
wa.rtype = rtype;
}
}
wa.tm.triggerErrorInCaller();
}
if (store)
{
// if 'storeReturnValue' is being called, then this is either the last RETURN in the block or is
// always followed by a Java 'return'.
return;
}
else if (rtype == ReturnType.NORMAL && wa.tm.getBlockType() == BlockType.FUNCTION)
{
// otherwise, check if this return can skip the exception throw
Object thisProc = wa.pm._thisProcedure();
String clsName = null;
if (thisProc instanceof _BaseObject_)
{
clsName = thisProc.getClass().getName();
}
else if (thisProc.getClass() == Object.class)
{
// this case handles static OO method calls - for this, FWD uses a surrogate java.lang.Object
// instance to be used as THIS-PROCEDURE; THIS-PROCEDURE is how FWD internally identifies the
// context of the current call (and for static calls there is no 'instance', thus the
// java.lang.Object surrogate).
Class<? extends _BaseObject_> cls = ObjectOps.getStaticClass(thisProc);
clsName = cls.getName();
}
// TODO: replace this test with cls.isAnnotation(LegacyResource.class) ?
if (clsName != null && clsName.startsWith("com.goldencode.p2j.oo"))
{
// WARNING: the p2o.oo code is not refactored to use 'storeReturnValue' or Java return statements
// instead, this code uses and expects for the returnNormal call to exit the block.
}
else
{
return;
}
}
throw wa.retExc;
}
/**
* Mark all blocks on the stack enclosed in this this top-level block (including it), as
* {@link BlockDefinition#wasReturnError}.
* <p>
* This is called only when a RETURN ERORR (from within a top-level block) is being called, and is meant to
* mark all blocks on the stack, up to the nearest top-level block, that the exist is being done via a
* RETURN ERROR.
* <p>
* Do not call this method from other code.
*
* @param wa
* The context-local instance.
*/
private static void markReturnError(WorkArea wa)
{
int i = 0;
BlockDefinition blk = wa.tm.getBlock(i);
while (blk != null && !blk.topLevel)
{
blk.wasReturnError = true;
i = i + 1;
blk = wa.tm.getBlock(i);
}
if (blk != null)
{
// this is the nearest top-level block
blk.wasReturnError = true;
}
}
/**
* Execute the given function block with the given transaction level.
*
* @param def
* The Java class associated with a legacy OE class, if this code is part of a legacy
* OE class; otherwise, <code>null</code>.
* @param referent
* The referent to which this method belongs.
* @param legacyName
* The legacy name associated with the function being invoked via a java-style call.
* If is <code>null</code>, it will be resolved by
* {@link ProcedureManager#resolveClosestMethod}.
* @param level
* The transaction level for the given block.
* @param block
* The code to execute.
* @param retType
* The type of the return value which is used in the case the
* <code>unknown value</code> must be returned.
* @param extent
* For functions not returning an extent value, this is -1. Else, this extent size,
* which is 0 for dynamic-extent and >0 for fixed extent.
*
* @return The return value from the block (or its nested blocks) which
* is the <code>unknown value</code> by default or on error.
*/
@SuppressWarnings("unchecked")
private static <T extends BaseDataType> Object functionBlock(Class<?> def,
Object referent,
String legacyName,
TransactionType level,
Block block,
Class<T> retType,
int extent)
{
WorkArea wa = work.obtain();
Boolean javaCall = checkJavaCall(wa, def, referent, legacyName, block, true, false, false);
if (javaCall == null)
{
// terminate the call
return BaseDataType.generateUnknown(retType);
}
if (object.class == retType || (retType.isArray() && object.class == retType.getComponentType()))
{
wa.objHelper.registerPendingScopeable();
}
long start = 0;
if (statsFile != null)
{
start = System.currentTimeMillis();
}
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
OutputParameterAssigner opa = wa.tm.deregisterOutputParameterAssigner();
String calleeName = ""; // opa will need this back when performing exit checks
boolean wasDynamicCall = false;
Object retVal = null;
int ttype = convertTransType(level, BlockType.FUNCTION);
wa.tm.pushScope("methodScope",
ttype,
(PROP_ERROR | PROP_ENDKEY),
false,
true,
false,
false,
BlockType.FUNCTION);
// add a scope to our list of function return values and block types
wa.funcRet.push(NULL);
wa.topType.push(BlockType.FUNCTION);
try
{
methodScope:
{
// give the block a chance to initialize its state and don't repeat that during retry
block.init();
wa.tm.blockSetup();
do
{
try
{
processBody(wa, block, null, null);
}
catch (LegacyErrorException lex)
{
processLegacyException(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStopException(wa, lex);
}
catch (ErrorConditionException err)
{
// we deliberately do not test honorError() here since
// functions in Progress do not implement the "trigger
// error in caller" behavior on a return error
wa.tm.notifyCondition(err);
wa.tm.rollback("methodScope", err);
wa.tm.triggerRetry("methodScope");
}
catch (StopConditionException err)
{
wa.tm.notifyCondition(err);
wa.tm.rollback("methodScope", err);
throw err;
}
catch (EndConditionException end)
{
wa.tm.notifyCondition(end);
wa.tm.rollback("methodScope", end);
break methodScope;
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (StackUnwindException sue)
{
// we have unwound to the exit point, break out (it doesn't
// matter whether we need to exit because of a LEAVE, NEXT or
// a RETURN, they all have the same result on a function block
break methodScope;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
}
}
catch (RuntimeException exc)
{
// cleaning up the OPA inside this catch only works because "normal"
// control flow exceptions are caught and handled before they would
// cross the top-level block boundary
if (opa != null)
{
opa.abort();
}
checkLegacyError(exc);
}
finally
{
if (opa != null)
{
if (wa.rtype == BlockManager.ReturnType.ERROR)
{
opa.abort();
}
else
{
calleeName = wa.pm.getStackEntry(0);
}
}
try
{
wa.tm.popScope();
}
catch (RuntimeException exc)
{
if (opa != null)
{
opa.abort();
}
throw exc;
}
finally
{
// cleanup return value stack and obtain the current value
retVal = wa.funcRet.pop();
if (retVal == NULL)
{
retVal = null;
}
// cleanup our top level block state
exitTopLevel(wa);
wa.rtype = null;
if (javaCall)
{
wasDynamicCall = wa.pm.peekCalleeInfo().isDynamicCall();
wa.pm.popCalleeInfo();
}
}
if (statsFile != null)
{
recordExecutionStats(BlockType.FUNCTION, block, start);
}
}
// process assign-backs to database fields from output parameters, if any
if (opa != null)
{
opa.processAssignments(calleeName, true);
}
// assume no-extent
int size = 1;
if (extent >= 0)
{
int retValLength = retVal == null
? extent
: retVal.getClass().isArray() ? Array.getLength(retVal) : 1;
if (extent > 0 && retVal != null && retValLength != extent)
{
// TODO: if fixed extent, it must be of the same size
}
size = retVal == null ? extent : retValLength;
T[] ret = (T[]) Array.newInstance(retType, size);
for (int i = 0; i < size; i++)
{
if (retVal == null)
{
ret[i] = (T) BaseDataType.generateUnknown(retType);
}
else
{
try
{
// In order to return the expected type, look for the "conversion" constructor
// of the type expected to return having as argument an object of the type
// we received in return statement. Then use it to create a new instance.
T t = null;
BaseDataType val = (BaseDataType) Array.get(retVal, i);
if (retType == memptr.class && val instanceof memptr)
{
t = (T) val;
}
else
{
t = (T) BaseDataTypeFactory.instantiate(retType);
t.assign((BaseDataType) val);
}
ret[i] = t;
}
catch (ConditionException ce)
{
// some 4GL validation/conversion error occurred
// propagate, will be handled elsewhere
throw ce;
}
catch (Exception ex)
{
Throwable ex2 = ex;
while (ex2 != null && !(ex2 instanceof ConditionException))
{
ex2 = ex2.getCause();
}
if (ex2 == null)
{
// wrap in a RunnableException and rethrow
throw new RuntimeException(ex);
}
else
{
// ex2 is instance of ConditionException because of a 4GL validation/conversion
// error has occurred: propagate, will be handled elsewhere
throw (ConditionException) ex2;
}
}
}
}
return ret;
}
else
{
if (retVal == null)
{
return BaseDataType.generateUnknown(retType);
}
else
{
try
{
BaseDataType ret;
if (memptr.class == retType && retVal instanceof memptr)
{
ret = (memptr) retVal;
}
else if ((retType == BaseDataType.class ||
BaseDataType.isProxy((BaseDataType) retVal) ||
((javaCall && wasDynamicCall) ||
(!javaCall && wa.pm.peekCalleeInfo().isDynamicCall()))) &&
((BaseDataType) retVal).val().getType().getCls() != retType)
{
// any dynamic function should provide a proxy for the return value instead:
// - in 4GL, returning a value which comes from a dynamic-function invocation
// can bypass the return data type
// - in Java, we should ensure that the returned value ALWAYS matches the defined return
// data type; that is why we encapsulate this value using a proxy
ret = BaseDataType.createProxy(((BaseDataType) retVal).val(),
(Class<? extends BaseDataType>) retType);
}
else
{
retVal = ((BaseDataType) retVal).val();
if (integer.class == retType && retVal instanceof int64)
{
ret = new integer()
{
@Override
boolean isAssignDirect()
{
return true;
}
};
}
else if (retType == object.class && ((object) retVal)._isValid())
{
// create a ObjectVar and register it with the current block - the return reference can
// end up only 'on the stack' as a return value, if the reference will never be assigned;
// more, ObjectOps.instanceReturned will prohibit the reference to be deleted (as it
// waits to 'maybe be assigned to something').
wa.objHelper.registerScopeable();
ret = new ObjectVar<>(((object) retVal).type());
wa.objHelper.registerObject((ObjectVar) ret);
}
else
{
ret = BaseDataTypeFactory.instantiate(retType);
}
ret.assign((BaseDataType) retVal);
// preserve case sensitivity of the returned value
if (retVal instanceof Text)
{
((Text) ret).setCaseSensitive(((Text) retVal).isCaseSensitive());
}
}
return ret;
}
catch (ConditionException ce)
{
// some 4GL validation/conversion error occurred
// propagate, will be handled elsewhere
throw ce;
}
catch (Exception ex)
{
Throwable ex2 = ex;
while (ex2 != null && !(ex2 instanceof ConditionException))
{
ex2 = ex2.getCause();
}
if (ex2 == null)
{
// wrap in a RunnableException and rethrow
throw new RuntimeException(ex);
}
else
{
// ex2 is instance of ConditionException because of a 4GL validation/conversion
// error has occurred: propagate, will be handled elsewhere
throw (ConditionException) ex2;
}
}
}
}
}
/**
* Execute the given editing block for the given frame and widget list
* with <code>UPDATE</code> semanics. All looping, sub-transaction
* properties and block properties will be honored. The exit from the
* editing block will be based on the given <code>GO-ON</code> event list.
*
* @param frame
* The frame for which the editing block is associated.
* @param widgets
* The widgets in the given frame that are to be enabled for
* editing.
* @param goOn
* The exit conditions for this loop or <code>null</code> if
* there are no explicit exit conditions.
* @param enclosing
* The list of enclosing blocks of which this class is unaware.
* Any LEAVE or NEXT that references one of those enclosing
* blocks must not unwind the stack further using an exception,
* but rather it must return and let the caller check to see if
* a deferred LEAVE or NEXT must be honored.
* @param label
* The label of the block for use in control flow statements
* such as <code>LEAVE</code> or <code>NEXT</code>.
* @param block
* The code for the editing block body.
* @param etype
* Editing block semantics (<code>CommonFrame.PROMPT-FOR</code>,
* <code>CommonFrame.SET</code> or
* <code>CommonFrame.UPDATE</code>).
*/
private static void editingBlock(CommonFrame frame,
FrameElement[] widgets,
EventList goOn,
String[] enclosing,
String label,
Block block,
int etype)
{
boolean noWidgets = true;
for (FrameElement el : widgets)
{
if (el != null)
{
noWidgets = false;
break;
}
}
if (noWidgets)
{
// the editing loop is a no-op if no widget was specified (as i.e. all WHEN clauses were
// false)
return;
}
if (UnnamedStreams.input() != null)
{
switch (etype)
{
case CommonFrame.PROMPT_FOR:
{
frame.promptFor(widgets, goOn);
break;
}
case CommonFrame.SET:
{
frame.set(widgets, goOn);
break;
}
case CommonFrame.UPDATE:
{
frame.update(widgets, goOn);
break;
}
}
return;
}
BufferManager.registerPendingScopeable(null);
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
WorkArea wa = work.obtain();
wa.tm.pushScope(label,
convertTransType(TransactionType.SUB, BlockType.EDITING),
PROP_ERROR,
false,
false,
true,
true,
BlockType.EDITING);
try
{
// give the block a chance to initialize its state and don't
// repeat that during retry
block.init();
// prepare the frame and the client for the editing block, this
// must only occur once (outside of the loop body and not being
// re-executed on retry)
if (goOn == null)
{
frame.startEditingMode(widgets, etype);
}
else
{
frame.startEditingMode(widgets, etype, goOn);
}
boolean hadNext = false;
editing:
do
{
wa.tm.blockSetup();
do
{
// reset at the beginning of each iteration
hadNext = false;
try
{
processBody(wa, block, null, null);
}
catch (ErrorConditionException err)
{
wa.tm.notifyCondition(err);
// EDITING blocks propagate ERROR conditions to the
// containing block, in 2 cases:
// 1. PROMPT-FOR or SET semantics
// 2. No matter the type of editing block (even if it is
// an UPDATE), if the condition was raised as a result
// of the END-ERROR key AND the editing block's "local"
// interaction number < 2
if (etype != CommonFrame.UPDATE ||
(err.isEndError() && (wa.tm.getInteractions() < 2)))
{
throw err;
}
// If the EDITING semantic is for an UPDATE type block AND
// the ERROR condition was NOT raised as a result of an
// END-ERROR key press if "local" interaction number < 2,
// then AND ONLY THEN we will act as if there was an UNDO,
// RETRY of the EDITING block.
wa.tm.honorError(err);
wa.tm.rollback(label, err);
wa.tm.triggerRetry(null);
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, label) == Disposition.BREAK)
{
boolean res = LogicalTerminal.getClient().validateDisplayValue();
if (!res)
{
continue editing;
}
// the LEAVE targeted this block or an enclosing non-managed block
break editing;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other
// enclosing managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
switch (testNext(wa, enclosing, label))
{
case BREAK:
// a NEXT targeted at a directly enclosing block that is not managed
break editing;
case CONTINUE:
// a NEXT targeted at this block
hadNext = true;
continue editing;
default:
// the NEXT must be referencing an enclosing block
// which IS known to the block manager OR to one of
// the other enclosing managed blocks, so keep
// unwinding the stack
throw nue;
}
}
catch (ReturnUnwindException ret)
{
// this isn't a top level block, keep unwinding without
// treating this as an abend
throw ret;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
if (wa.tm.isBreakPending())
{
break editing;
}
}
while (frame.continueEditing(widgets, hadNext));
}
finally
{
wa.tm.popScope();
}
}
/**
* Execute a simple DO block (not a loop) with the given configuration and no default properties.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current block.
* @param label
* The block name of the current block.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
private static void doBlockWorker(TransactionType lvl,
String[] enclosing,
String label,
OnPhrase[] on,
Block block)
{
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
BlockType blockType = BlockType.DO;
int ttype = convertTransType(lvl, blockType);
OnPhrase[] defOn = null;
if (lvl == TransactionType.FULL)
{
defOn = new OnPhrase[1];
defOn[0] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
}
int props = decodeConditions(defOn, on);
WorkArea wa = work.obtain();
wa.tm.pushScope(label, ttype, props, false, false, false, false, blockType);
try
{
try
{
// each constructed query during block initialization will be
// collected
wa.tm.startOffEndRegistration();
// give the block a chance to initialize its state and don't
// repeat that during retry
block.init();
}
finally
{
wa.tm.stopOffEndRegistration();
// after all queries were created and registered, they must be
// reset so the buffers reference no record.
Set<QueryOffEndListener> listeners = wa.tm.getOffEndListeners(true);
for (QueryOffEndListener qoel : listeners)
{
qoel.reset();
}
}
wa.tm.blockSetup();
blockLabel:
do
{
try
{
processBody(wa, block, on, defOn);
}
catch (LegacyErrorException lex)
{
processLegacyException(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStopException(wa, lex);
}
catch (ConditionException ce)
{
wa.tm.notifyCondition(ce);
switch (processCondition(wa, on, defOn, ce, enclosing, label))
{
// note that this is not an iterating block so a leave or
// next targeted at this block must always act the same
case BREAK:
case CONTINUE:
break blockLabel;
default:
break;
}
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, label) == Disposition.BREAK)
{
// the LEAVE targeted this block or an enclosing
// non-managed block
break blockLabel;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
if (testNext(wa, enclosing, label) == Disposition.BREAK)
{
// the NEXT can't be targeted at this block BUT it can be
// targeted at an enclosing non-managed block
break blockLabel;
}
// the NEXT must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw nue;
}
catch (ReturnUnwindException rue)
{
// RETURN can't be targeted at a DO block so keep unwinding
throw rue;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
}
finally
{
wa.tm.popScope();
}
}
/**
* Execute a a termination block like CATCH and FINALLY, emulating {@link #doBlockWorker}.
*
* @param wa
* The {@link WorkArea} instance.
* @param lvl
* The transaction level to be honored.
* @param label
* The block name of the current block.
* @param finBlock
* Flag identifying a FINALLY block when <code>true</code> and a CATCH block otherwise.
* @param block
* The code to execute.
*/
private static void doTerminationBlockWorker(WorkArea wa,
TransactionType lvl,
String label,
boolean finBlock,
Block block)
{
String[] enclosing = null;
OnPhrase[] on = null;
// give the block a chance to handle any initialization which must happen BEFORE the TM scope is pushed;
// doesn't repeat on retry
block.pre();
BlockType blockType = finBlock ? BlockType.FINALLY : BlockType.DO;
int ttype = convertTransType(lvl, blockType);
OnPhrase[] defOn = null;
if (lvl == TransactionType.FULL)
{
defOn = new OnPhrase[1];
defOn[0] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
}
int props = decodeConditions(defOn, on);
if (wa == null)
{
wa = work.obtain();
}
wa.tm.pushScope(label, ttype, props, false, false, false, false, blockType);
try
{
block.init();
wa.tm.blockSetup();
// a CATCH or FINALLY block can't be retried
blockLabel:
{
try
{
processBody(wa, block, on, defOn);
}
catch (LegacyErrorException lex)
{
processLegacyException(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStopException(wa, lex);
}
catch (ConditionException ce)
{
wa.tm.notifyCondition(ce);
switch (processCondition(wa, on, defOn, ce, enclosing, label))
{
// note that this is not an iterating block so a leave or
// next targeted at this block must always act the same
case BREAK:
case CONTINUE:
break blockLabel;
default:
break;
}
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, label) == Disposition.BREAK)
{
// the LEAVE targeted this block or an enclosing
// non-managed block
break blockLabel;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
if (testNext(wa, enclosing, label) == Disposition.BREAK)
{
// the NEXT can't be targeted at this block BUT it can be
// targeted at an enclosing non-managed block
break blockLabel;
}
// the NEXT must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw nue;
}
catch (ReturnUnwindException rue)
{
// RETURN can't be targeted at a DO block so keep unwinding
throw rue;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
}
finally
{
wa.tm.popScope();
}
}
/**
* Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
* TO WHILE expression loop with the given configuration and no default
* properties. At least one of the to clause or while expression must be
* passed and it is valid to have both passed in which case both of the
* conditions are tested with a logical AND.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
private static void doLoopWorker(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
BlockType btype = null;
boolean next = false;
if (to == null)
{
if (expr == null)
{
throw new IllegalStateException("DO loop MUST have a TO or WHILE clause.");
}
else
{
btype = BlockType.DO_WHILE;
}
}
else
{
btype = (expr == null) ? BlockType.DO_TO : BlockType.DO_TO_WHILE;
next = true;
}
OnPhrase[] defOn = null;
if (lvl == TransactionType.FULL)
{
defOn = new OnPhrase[1];
defOn[0] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
}
// process the loop
coreLoop(btype, next, lvl, enclosing, label, to, expr, on, defOn, block);
}
/**
* Execute a REPEAT, REPEAT WHILE expression, REPEAT TO var = val1 to val2
* by val3 or REPEAT TO WHILE expression loop with the given configuration
* and with default properties. If neither the to clause or while
* expression is specified, this is an infinite loop. If both are specified
* then both of the conditions are tested with a logical AND. By default,
* the ON ENDKEY UNDO, LEAVE and ON ERROR UNDO, RETRY properties are
* supported.
*
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
private static void repeatWorker(TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
BlockType btype = null;
boolean next = false;
if (to == null)
{
btype = (expr == null) ? BlockType.REPEAT : BlockType.REPEAT_WHILE;
}
else
{
btype = (expr == null) ? BlockType.REPEAT_TO : BlockType.REPEAT_TO_WHILE;
next = true;
}
OnPhrase[] defOn = new OnPhrase[2];
defOn[0] = new OnPhrase(Condition.ENDKEY, Action.LEAVE, label);
defOn[1] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
// process the loop
coreLoop(btype, next, lvl, enclosing, label, to, expr, on, defOn, block);
}
/**
* Execute a DO or REPEAT loop with all possible loop constructs, the
* given configuration and with default properties.
*
* @param btype
* Current block type.
* @param next
* <code>true</code> if on infinite loop protection a retry
* should be converted to a NEXT, <code>false</code> to convert
* to a LEAVE.
* @param lvl
* The transaction level to be honored.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
* @param on
* List of user-defined on phrases.
* @param defOn
* List of default properties for the block. Use
* <code>null</code> to indicate no default properties for the
* block.
* @param block
* The code to execute.
*/
private static void coreLoop(BlockType btype,
boolean next,
TransactionType lvl,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
OnPhrase[] defOn,
Block block)
{
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
int ttype = convertTransType(lvl, btype);
int props = decodeConditions(defOn, on);
WorkArea wa = work.obtain();
wa.tm.pushScope(label, ttype, props, false, false, true, next, btype);
try
{
try
{
// each constructed query during block initialization will be
// collected
wa.tm.startOffEndRegistration();
// give the block a chance to initialize its state and don't
// repeat that during iteration or retry
block.init();
}
finally
{
wa.tm.stopOffEndRegistration();
// after all queries were created and registered, they must be
// reset so the buffers reference no record.
Set<QueryOffEndListener> listeners = wa.tm.getOffEndListeners(true);
if (!listeners.isEmpty())
{
for (QueryOffEndListener qoel : listeners)
{
qoel.reset();
}
}
}
loop:
while (needsIterate(to, expr))
{
wa.tm.blockSetup();
do
{
try
{
processBody(wa, block, on, defOn);
}
catch (LegacyErrorException lex)
{
processLegacyException(wa, lex);
}
catch (LegacyStopException lex)
{
processLegacyStopException(wa, lex);
}
catch (ConditionException ce)
{
wa.tm.notifyCondition(ce);
switch (processCondition(wa, on, defOn, ce, enclosing, label))
{
case BREAK:
break loop;
case CONTINUE:
continue loop;
default:
break;
}
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, label) == Disposition.BREAK)
{
// the LEAVE targeted this block or an enclosing
// non-managed block
break loop;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other
// enclosing managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
switch (testNext(wa, enclosing, label))
{
case BREAK:
// the NEXT is targeted at an enclosing non-managed block
break loop;
case CONTINUE:
// the NEXT is targeted at the current loop
continue loop;
default:
break;
}
// the NEXT must be referencing an enclosing block which IS
// known to the block manager OR to one of the other
// enclosing managed blocks, so keep unwinding the stack
throw nue;
}
catch (ReturnUnwindException rue)
{
// RETURN can't be targeted at a DO loop so keep unwinding
throw rue;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
if (wa.tm.isBreakPending())
{
break loop;
}
}
}
finally
{
wa.tm.popScope();
}
}
/**
* Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
* or FOR FIRST/LAST TO WHILE block with the given configuration and
* with default properties. Any TO or WHILE clause is treated as an
* additional condition that must be met before the block body is executed.
* Note that the presence of a TO or WHILE does not make this a loop. If
* neither the TO clause or WHILE expression is specified, this is a
* simple block. If both are specified then both of the conditions are
* tested with a logical AND. By default, the ON ENDKEY UNDO, LEAVE and ON
* ERROR UNDO, RETRY properties are supported.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself or if there
* is a TO or WHILE clause then the query processing should be located in
* the {@link Block#enter} method. This means that the caller is
* responsible for all query processing. The record retrieval must be done
* on the first line of code in the block or in the <code>enter</code>
* method to duplicate the Progress behavior. Note that this is required
* to handle all error cases and 4GL conditions properly.
* <p>
* The evaluation of the TO or WHILE block termination conditions is done
* AFTER the record retrieval. This causes any found record to remain
* available if the block is never entered because of the TO or WHILE
* conditions.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forBlock.
* @param direction
* direction in which query will be iterating.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines the block condition. The block
* control variable is initialized before entering the block.
* Before the block body is entered, the control variable is
* compared to the termination value (which is dynamically
* resolved at that moment). if the termination condition is
* met, the block is never entered.
* @param expr
* The WHILE clause that defines a block condition. This
* expression is evaluated before the block body is about to
* be entered. The block body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
private static void forBlockWorker(TransactionType lvl,
P2JQuery query,
int direction,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
query.setLenientOffEnd(true);
BlockType btype = null;
if (to == null)
{
btype = (expr == null) ? BlockType.FOR_BLOCK : BlockType.FOR_BLOCK_WHILE;
}
else
{
btype = (expr == null) ? BlockType.FOR_BLOCK_TO : BlockType.FOR_BLOCK_TO_WHILE;
}
OnPhrase[] defOn = new OnPhrase[2];
defOn[0] = new OnPhrase(Condition.ENDKEY, Action.LEAVE, label);
defOn[1] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
int ttype = convertTransType(lvl, btype);
int props = decodeConditions(defOn, on);
WorkArea wa = work.obtain();
wa.tm.pushScope(label, ttype, props, false, false, false, false, btype);
try
{
try
{
// each constructed query during block initialization will be
// collected
wa.tm.startOffEndRegistration();
// give the block a chance to initialize its state and don't
// repeat that during retry
block.init();
}
finally
{
// after block initialization is finished, the off end listeners
// for all the buffers in the collected queries are saved
wa.tm.stopOffEndRegistration();
}
wa.tm.blockSetup();
blockLabel:
do
{
try
{
boolean querySucceful = false;
switch (direction)
{
case QueryConstants.FIRST: {
querySucceful = query.first();
break;
}
case QueryConstants.LAST: {
querySucceful = query.last();
break;
}
case QueryConstants.UNIQUE: {
querySucceful = query.unique();
break;
}
case QueryConstants.ITERATE: {
querySucceful = query.next();
break;
}
}
if (!querySucceful)
{
wa.tm.notifyCondition(Condition.ENDKEY);
try
{
wa.tm.processOffEndListeners(true);
// avoid roll-back; the query initialization might have done some database work
// like honoring the RecordNursery. If the query didn't find any record, using a rollback
// will eliminate the work done in the init block (i.e. a side-effect aggressive flush).
break blockLabel;
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
if (processForBody(wa, block, to, expr, on, defOn))
{
break blockLabel;
}
}
catch (ConditionException ce)
{
wa.tm.notifyCondition(ce);
// when there are no more records in the query, we ALWAYS
// UNDO, LEAVE (which is the same as the default ENDKEY
// processing) the current block even if the user has defined
// an explicit behavior for ENDKEY
if (ce instanceof QueryOffEndException)
{
QueryOffEndException qoee = (QueryOffEndException) ce;
QueryOffEndListener[] listeners = qoee.getListeners();
// flag indicating if the off-end listeners are the one
// registered during block initialization
boolean allOffEndListeners = true;
for (int i = 0; i < listeners.length; i++)
{
allOffEndListeners = allOffEndListeners &&
wa.tm.isOffEndListener(listeners[i]);
}
if (allOffEndListeners)
{
try
{
// if the buffers are the ones used by the FOR block,
// process them and trigger an UNDO, LEAVE
wa.tm.processOffEndListeners(true);
wa.tm.rollback(label, ce);
break blockLabel;
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
}
try
{
// if the exception was triggered by something else, then
// the off-end interested buffers must remain on the
// currently referenced record
wa.tm.processOffEndListeners(true);
// normal condition processing
switch (processCondition(wa, on, defOn, ce, enclosing, label))
{
// note that this is not an iterating block so a leave or
// next targeted at this block must always act the same
case BREAK:
case CONTINUE:
break blockLabel;
default:
break;
}
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, label) == Disposition.BREAK)
{
// the LEAVE targeted this block or an enclosing
// non-managed block
break blockLabel;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
if (testNext(wa, enclosing, label) == Disposition.BREAK)
{
// the NEXT can't be targeted at this block BUT it can be
// targeted at an enclosing non-managed block
break blockLabel;
}
// the NEXT must be referencing an enclosing block which IS
// known to the block manager OR to one of the other enclosing
// managed blocks, so keep unwinding the stack
throw nue;
}
catch (ReturnUnwindException rue)
{
// RETURN can't be targeted at a DO block so keep unwinding
throw rue;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
}
finally
{
wa.tm.popScope();
}
}
/**
* Execute a FOR EACH, FOR EACH WHILE block, FOR EACH TO block
* or FOR EACH TO WHILE block with the given configuration and
* with default properties. Any TO or WHILE clause is treated as an
* additional condition that must be met before the loop body is executed.
* If both are specified then both of the conditions are tested with a
* logical AND. By default, the ON ENDKEY UNDO, LEAVE and ON ERROR UNDO,
* RETRY properties are supported.
* <p>
* The record retrieval that is associated with FOR blocks or loops must
* be implemented directly inside the code of the block itself or if there
* is a TO or WHILE clause then the query processing should be located in
* the {@link Block#enter} method. This means that the caller is
* responsible for all query processing. The record retrieval must be done
* on the first line of code in the block or in the <code>enter</code>
* method to duplicate the Progress behavior. Note that this is required
* to handle all error cases and 4GL conditions properly.
* <p>
* The evaluation of the TO or WHILE block termination conditions is done
* AFTER the record retrieval. This causes any found record to remain
* available if the loop is never entered (or re-entered) because of the
* TO or WHILE conditions.
*
* @param lvl
* The transaction level to be honored.
* @param query
* query that will iterate forEachBlock.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>.
* @param on
* List of user-defined on phrases.
* @param block
* The code to execute.
*/
private static void forEachWorker(TransactionType lvl,
P2JQuery query,
String[] enclosing,
String label,
ToClause to,
LogicalOp expr,
OnPhrase[] on,
Block block)
{
// give the block a chance to handle any initialization which must happen BEFORE the TM
// scope is pushed; doesn't repeat on retry
block.pre();
query.setLenientOffEnd(true);
query.setIterating(true);
BlockType btype = null;
if (to == null)
{
btype = (expr == null) ? BlockType.FOR_LOOP : BlockType.FOR_LOOP_WHILE;
}
else
{
btype = (expr == null) ? BlockType.FOR_LOOP_TO : BlockType.FOR_LOOP_TO_WHILE;
}
OnPhrase[] defOn = new OnPhrase[2];
defOn[0] = new OnPhrase(Condition.ENDKEY, Action.LEAVE, label);
defOn[1] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
int ttype = convertTransType(lvl, btype);
int props = decodeConditions(defOn, on);
WorkArea wa = work.obtain();
wa.tm.pushScope(label, ttype, props, false, false, true, true, btype);
try
{
try
{
// each constructed query during block initialization will be
// collected
wa.tm.startOffEndRegistration();
// give the block a chance to initialize its state and don't
// repeat that during retry
block.init();
}
finally
{
// after block initialization is finished, the off end listeners
// for all the buffers in the collected queries are saved
wa.tm.stopOffEndRegistration();
// after all queries were created and registered, they must be
// reset so the buffers reference no record.
if (!query.isPresort())
{
Set<QueryOffEndListener> listeners = wa.tm.getOffEndListeners(false);
for (QueryOffEndListener qoel : listeners)
{
qoel.reset();
}
}
}
boolean topQuerySuccessful;
loop:
while (true)
{
wa.tm.blockSetup();
topQuerySuccessful = false;
do
{
try
{
if (!query.next())
{
wa.tm.notifyCondition(Condition.ENDKEY);
try
{
wa.tm.processOffEndListeners(true);
// avoid roll-back; the query initialization might have done some database work
// like honoring the RecordNursery. If the query didn't find any record, using a rollback
// will eliminate the work done in the init block (i.e. a side-effect aggressive flush).
break loop;
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
topQuerySuccessful = true;
if (processForBody(wa, block, to, expr, on, defOn))
{
break loop;
}
}
catch (ConditionException ce)
{
if (ce.shouldExitBlock() && !topQuerySuccessful)
{
// an error was produced when executing the FOR-EACH query
// leave the block instead of retrying
try
{
wa.tm.processOffEndListeners(true);
break loop;
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
wa.tm.notifyCondition(ce);
if (ce instanceof QueryOffEndException)
{
QueryOffEndException qoee = (QueryOffEndException) ce;
QueryOffEndListener[] listeners = qoee.getListeners();
// flag indicating if the off-end listeners are the one
// registered during block initialization
boolean allOffEndListeners = true;
for (int i = 0; i < listeners.length; i++)
{
allOffEndListeners = allOffEndListeners &&
wa.tm.isOffEndListener(listeners[i]);
}
if (allOffEndListeners)
{
try
{
// if the buffers are the ones used by the FOR block,
// process them and trigger an UNDO, LEAVE
wa.tm.processOffEndListeners(true);
wa.tm.rollback(label, ce);
break loop;
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
}
try
{
// if the exception was triggered by something else, then
// the off-end interested buffers must remain on the
// currently referenced record
wa.tm.processOffEndListeners(true);
// normal condition processing
switch (processCondition(wa, on, defOn, ce, enclosing, label))
{
case BREAK:
break loop;
case CONTINUE:
continue loop;
default:
break;
}
}
finally
{
wa.tm.processOffEndListeners(false);
}
}
catch (RetryUnwindException rue)
{
wa.tm.honorRetry(rue);
}
catch (LeaveUnwindException lue)
{
if (testLeave(wa, enclosing, label) == Disposition.BREAK)
{
// the LEAVE targeted this block or an enclosing non-managed block
break loop;
}
// the LEAVE must be referencing an enclosing block which IS
// known to the block manager OR to one of the other
// enclosing managed blocks, so keep unwinding the stack
throw lue;
}
catch (NextUnwindException nue)
{
switch (testNext(wa, enclosing, label))
{
case BREAK:
// the NEXT is targeted at an enclosing non-managed block
break loop;
case CONTINUE:
// the NEXT is targeted at the current loop
continue loop;
default:
break;
}
// the NEXT must be referencing an enclosing block which IS
// known to the block manager OR to one of the other
// enclosing managed blocks, so keep unwinding the stack
throw nue;
}
catch (ReturnUnwindException rue)
{
// RETURN can't be targeted at a DO block so keep unwinding
throw rue;
}
catch (Throwable thr)
{
wa.tm.abnormalEnd(thr);
}
}
while (wa.tm.needsRetry());
if (wa.tm.isBreakPending())
{
break loop;
}
}
}
finally
{
wa.tm.popScope();
}
}
/**
* Test the given expressions to determine if the calling loop should
* iterate or if the loop should exit. Either or both parameters
* may be <code>null</code> individually or simultaneously.
*
* @param to
* The TO clause that defines a loop condition. The loop control
* variable is initialized on the first pass through and on
* subsequent passes it is incremented by a given factor. Before
* the loop body is entered, the loop control variable is
* compared to the termination value (which is dynamically
* resolved at each loop iteration). When the termination
* condition is met, the loop ends. If this is <code>null</code>,
* then a WHILE clause MUST be present to provide the condition
* for maintaining the loop.
* @param expr
* The WHILE clause that defines a loop condition. This
* expression is evaluated every time the loop body is about to
* be entered. The loop body will be entered unless the
* expression evaluates to <code>false</code>. If this is
* <code>null</code>, then a TO clause MUST be present to
* provide the condition for maintaining the loop.
*
* @return <code>true</code> if all non-null parameters evaluate to
* <code>true</code> or if both parameters are <code>null</code>.
*/
private static boolean needsIterate(ToClause to, LogicalOp expr)
{
// in a TO WHILE case (where both conditions are specified), the 4GL evaluates the TO condition first
// and then conditionally evaluates the WHILE if needed; the use of && here intentionally
// short-circuits the WHILE expression if the TO is false
return (to == null || to.incrementAndTest()) && (expr == null || expr.evaluate().booleanValue());
}
/**
* Check if any CATCH blocks defined at the current enclosing block can manage this exception.
* <p>
* If none found, ignore this exception. 4GL doesn't seem to propagate the errors further than
* then current block.
* <p>
* If a CATCH block is found, then execute it.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param lex
* The thrown legacy error.
* @param on
* List of user-defined ON phrases. May be {@code null}.
* @param defOn
* List of implicit ON phrases for this block. May be {@code null}.
*
* @throws LegacyErrorException
* If the processing needs to be deferred.
*/
private static void processLegacyError(WorkArea wa, LegacyErrorException lex, OnPhrase[] on, OnPhrase[] defOn)
{
ObjectVar<? extends LegacyError> error = lex.getError();
if (error.isUnknown())
{
return;
}
boolean implicit = (on == null);
if (implicit)
{
on = defOn;
}
LegacyError legacyError = error.ref;
Class<?> errCls = legacyError.getClass();
boolean isFromReturn = wa.tm.getBlock().wasReturnError;
boolean mustManage = mustManageLegacyError(wa);
// do not throw if we are exiting a top-level block
boolean canThrow = mustManage || isFromReturn || (lex.isExplicit() && !wa.tm.isTopLevelBlock());
boolean noThrowOnError = false;
if (on != null && wa.tm.hasErrorProp() && (!implicit || !mustManage))
{
OnPhrase imple = matchCondition(on, null, Condition.ERROR);
if (imple != null)
{
canThrow = canThrow || (imple.action == Action.THROW);
noThrowOnError = (imple.action != Action.THROW);
}
}
int i = 0;
int topLvlBlocks = 0;
BlockDefinition block = wa.tm.getBlock(i);
if (isFromReturn)
{
// skip all CATCH blocks from current top-level block
while (block != null && !block.topLevel)
{
i = i + 1;
block = wa.tm.getBlock(i);
}
if (block != null)
{
i = i + 1;
block = wa.tm.getBlock(i);
}
lex.setFromReturn(false);
}
while (block != null)
{
topLvlBlocks += (block.topLevel ? 1 : 0);
if (block.catchBlocks != null)
{
for (Class<?> cls : block.catchBlocks.keySet())
{
if (cls.isAssignableFrom(errCls))
{
if (!canThrow && topLvlBlocks > 1)
{
displayErrorMessage(wa.tm, legacyError, 1, true, true, false);
// we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
error.decrement();
// release the reference
error.set(null);
return;
}
if (i == 0)
{
BlockDefinition blk = block;
String label = blk.label;
wa.tm.setupCatchProcessing(() ->
{
try
{
// clear any pending errors
wa.tm.errHlp.clearPending();
Block catchBlock = new Block()
{
@Override
public void body()
{
wa.tm.getBlock().type = BlockType.CATCH;
blk.catchBlocks.get(cls).accept(error);
}
};
doTerminationBlockWorker(wa,
TransactionType.NONE,
CATCH_BLOCK_LABEL + label,
false,
catchBlock);
}
finally
{
// we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
error.decrement();
// release this reference
error.set(null);
}
});
// the error was registered, will be processed in popScope, undo and leave the block
undoLeave("", "");
return;
}
else if (noThrowOnError)
{
throw new ErrorConditionException(error.ref.getMessage(new integer(1)).toStringMessage());
}
else if (canThrow)
{
// this is re-thrown, so mark it as 'explicit'
lex.setExplicit(true);
throw lex;
}
}
}
}
i = i + 1;
block = wa.tm.getBlock(i);
}
if (noThrowOnError)
{
throw new ErrorConditionException(error.ref.getMessage(new integer(1)).toStringMessage());
}
if (canThrow)
{
displayErrorMessages(wa.tm, legacyError, false, true);
throw lex;
}
// release it was not found, and is from a RETURN ERROR statement
if (isFromReturn)
{
if (ErrorManager.isPending())
{
throw lex;
}
displayErrorMessage(wa.tm, legacyError, 1, true, true, false);
}
else
{
displayErrorMessages(wa.tm, legacyError, true, false);
}
// we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
error.decrement();
// release the reference
error.set(null);
if (lex.isFromReturn())
{
leave(wa, "");
}
}
/**
* Returns if the legacy error needs to be displayed based on several criteria: if the error has already
* been displayed, if this is part of the top block execution and if it's a silent block (suppressed
* error).
*
* @param tm
* The transaction helper with information about the block.
* @param legacyError
* The error to be displayed.
*
* @return See above.
*/
private static boolean shouldDisplayError(TransactionHelper tm, LegacyError legacyError)
{
return !legacyError._isDisplayed() && tm.isTopLevelBlock() && !tm.isSuppressError();
}
/**
* Displays all messages of the legacy error if it is eligible for display, and then marks the error as
* displayed.
*
* @param tm
* The transaction helper with information about the block.
* @param legacyError
* The error to be displayed.
* @param addCallStack
* Flag to indicate if callstack needs to be added to the message.
* @param onlyLog
* Flag to record a log instead of displaying the error.
*/
private static void displayErrorMessages(TransactionHelper tm,
LegacyError legacyError,
boolean addCallStack,
boolean onlyLog)
{
if (!shouldDisplayError(tm, legacyError))
{
return;
}
for (int i = 0; i < legacyError.getNumMessages().intValue(); i++)
{
displayErrorMessage(tm, legacyError, i + 1, false, addCallStack, onlyLog);
}
legacyError._setDisplayed();
}
/**
* Displays the message on the selected index of the legacy error, if the error is eligible for display,
* and marks the error as displayed, if needed.
*
* @param tm
* The transaction helper with information about the block.
* @param legacyError
* The error to be displayed.
* @param markDisplayed
* Flag to indicate if the error should be marked as displayed.
* @param addCallStack
* Flag to indicate if callstack needs to be added to the message.
* @param onlyLog
* Flag to record a log instead of displaying the error.
*/
private static void displayErrorMessage(TransactionHelper tm,
LegacyError legacyError,
int msgIndex,
boolean markDisplayed,
boolean addCallStack,
boolean onlyLog)
{
character errMsg = legacyError.getMessage(new integer(msgIndex));
String errMsgString = errMsg.toJavaType();
if (!StringHelper.hasContent(errMsgString) || !shouldDisplayError(tm, legacyError))
{
return;
}
if (markDisplayed)
{
legacyError._setDisplayed();
}
if (onlyLog)
{
ErrorManager.writeLog(errMsgString);
}
else if (addCallStack)
{
ErrorManager.displayError(errMsgString);
}
else
{
ErrorManager.displayError(errMsgString, false, null, false);
}
}
/**
* Check if any CATCH blocks defined at the current enclosing block can manage thisSTOP exception.
* <p>
* If a CATCH block is found, then execute it.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param lex
* The thrown legacy error.
*
* @throws LegacyErrorException
* If the processing needs to be deferred.
*/
private static void processLegacyStop(WorkArea wa, LegacyStopException lex)
{
ObjectVar<? extends Stop> error = lex.getError();
if (error.isUnknown())
{
return;
}
Stop legacyStop = error.ref;
Class<?> stopCls = legacyStop.getClass();
boolean mustManage = mustManageLegacyStop(wa);
// do not throw if we are exiting a top-level block
boolean canThrow = mustManage;
boolean noThrowOnError = !mustManage;
int i = 0;
BlockDefinition block = wa.tm.getBlock(i);
while (block != null)
{
if (block.catchBlocks != null)
{
for (Class<?> cls : block.catchBlocks.keySet())
{
if (cls.isAssignableFrom(stopCls))
{
if (i == 0)
{
BlockDefinition blk = block;
wa.tm.setupCatchProcessing(() ->
{
// clear any pending errors
wa.tm.errHlp.clearPending();
Block catchBlock = new Block()
{
@Override
public void body()
{
wa.tm.getBlock().type = BlockType.CATCH;
blk.catchBlocks.get(cls).accept(error);
}
};
doTerminationBlockWorker(wa,
TransactionType.NONE,
CATCH_BLOCK_LABEL,
false,
catchBlock);
});
if (error.ref instanceof StopAfter)
{
wa.tm.setupStopAfterProccessing(lex);
}
// the error was registered, will be processed in popScope, undo and leave the block
undoLeave("", "");
return;
}
else if (noThrowOnError)
{
throw new StopConditionException("Thread was asynchronously interupted");
}
else if (canThrow)
{
// this is re-thrown, so mark it as 'explicit'
throw lex;
}
}
}
}
i = i + 1;
block = wa.tm.getBlock(i);
}
// we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
error.decrement();
// release the reference
error.set(null);
throw new StopConditionException("Thread was asynchronously interupted");
}
/**
* Check if any CATCH blocks defined at the specified enclosing block can manage this exception.
* <p>
* If none found, ignore this exception. 4GL doesn't seem to propagate the errors further than
* then current block.
*
* @param wa
* Context local data or {@code null} if not available in caller.
* @param type
* The error type to process.
* @param levels
* Flag indicating which block to use (0 for current, 1 for parent, etc). Use -1 to search the
* entire stack.
*
* @return <code>true</code> if this exception can be processed by the current block.
*/
private static boolean hasLegacyError(WorkArea wa,
Class<? extends LegacyError> type,
int levels)
{
if (wa == null)
{
wa = work.obtain();
}
for (int i = (levels == -1 ? 0 : levels); i <= (levels == -1 ? wa.tm.getNestingLevel() - 1 : levels); i++)
{
BlockDefinition block = wa.tm.getBlock(i);
// Note: block can be null when this method is called from JUnit
if (block == null || block.catchBlocks == null || block.catchBlocks.isEmpty())
{
continue;
}
for (Class<?> cls : block.catchBlocks.keySet())
{
if (cls.isAssignableFrom(type))
{
return true;
}
}
}
return false;
}
/**
* Check if any CATCH blocks defined at the specified enclosing block can manage this STOP exception.
* <p>
* If none found, on the path upward. But a ON STOP phrase is found of the block, then it takes precedence.
*
* @param wa
* Context local data or {@code null} if not available in caller.
* @param type
* The error type to process.
* @param levels
* Flag indicating which block to use (0 for current, 1 for parent, etc). Use -1 to search the
* entire stack.
*
* @return <code>true</code> if this exception can be processed by the current block.
*/
private static boolean hasLegacyStop(WorkArea wa,
Class<? extends Stop> type)
{
if (wa == null)
{
wa = work.obtain();
}
boolean throwInCatch = wa.tm.getBlock().type == BlockType.CATCH;
for (int i = throwInCatch ? 2 : 0; i <= wa.tm.getNestingLevel() - 1; i++)
{
BlockDefinition block = wa.tm.getBlock(i);
// Note: block can be null when this method is called from JUnit
if (block == null || block.catchBlocks == null || block.catchBlocks.isEmpty())
{
if (testProps(block.props, Condition.STOP))
{
return false;
}
continue;
}
for (Class<?> cls : block.catchBlocks.keySet())
{
if (type.isAssignableFrom(cls))
{
return true;
}
}
}
return false;
}
/**
* Make sure that the legacy exception is honoring the roll-back of transactions
* in the current block. For now, this is not honoring the labeling of undo statements.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param e
* The legacy error exception that caused the unwinding.
*/
private static void processLegacyException(WorkArea wa, LegacyErrorException e)
{
BlockDefinition blk = wa.tm.getBlock();
if (!blk.undoThrow)
{
wa.tm.errHlp.setPending(false);
wa.tm.attemptRollback();
}
blk.undoThrow = false;
throw e;
}
/**
* Make sure that the legacy stop exception is further thrown.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param e
* The legacy stop exception that caused the unwinding.
*/
private static void processLegacyStopException(WorkArea wa, LegacyStopException e)
{
BlockDefinition blk = wa.tm.getBlock();
if (!blk.undoThrow)
{
wa.tm.attemptRollback();
}
blk.undoThrow = false;
throw e;
}
/**
* Core worker to handle all the possible behavior in response to a
* condition being raised in an inner block (DO, REPEAT or FOR). The
* given condition exception will first be matched with the user-defined
* on phases and then if no match is found, with the default on phrases
* for the calling block. If nothing is found, then the condition
* exception will be re-thrown. If a match is found then condition-specific
* processing will be done to UNDO and then either unwind the stack using
* exceptions or a disposition will be returned so that the caller can
* properly implement a LEAVE or NEXT that is targetted at the current
* block or at an enclosing non-managed block.
* <p>
* This honors infinite loop protection for converting NEXT to LEAVE
* based on runtime state.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param user
* List of user-defined on phrases.
* @param def
* List of default on phrases for the current block type.
* @param ce
* The condition being raised.
* @param enclosing
* The list of non-managed block names that enclose the current
* block.
* @param label
* The block name of the current block.
*
* @return If an exception is not thrown (or re-thrown), then the caller
* will get a disposition code that should be honored to
* properly implement a LEAVE or NEXT action.
*/
private static Disposition processCondition(WorkArea wa,
OnPhrase[] user,
OnPhrase[] def,
ConditionException ce,
String[] enclosing,
String label)
throws ConditionException,
StackUnwindException,
RetryUnwindException
{
if (def != null &&
(wa.pm.isBlockLevelUndoThrow() ||
wa.tm.isTopLevelDatabaseTrigger()))
{
// change default ERROR, <action> to ERROR, THROW if BLOCK-LEVEL ON ERROR UNDO, THROW
for (OnPhrase on : def)
{
if (on.condition == Condition.ERROR)
{
on.action = Action.THROW;
}
}
}
Condition current = exceptionToCondition(ce);
OnPhrase imple = matchCondition(user, def, current);
if (imple != null)
{
// ERROR processing has a special mode (RETURN ERROR) and STOP
// processing mode which must unwind the stack to a specific
// point, so we must check if we are in either of those modes now
// (before the UNDO or secondary action for the block can be
// executed)
if (current == Condition.ERROR)
{
ErrorConditionException err = (ErrorConditionException) ce;
// END-ERROR is propagated to the parent block in blocks that
// have the ERROR property but do NOT have the ENDKEY property
if (err.isEndError() && !wa.tm.hasEndkeyProp())
{
// detect the case in which a END-ERROR would have been
// converted to ENDKEY, in such a case we must rethrow
if (wa.tm.getInteractions() < 2)
{
// let the parent see this (this will re-throw the
// exception after handling rollback state/processing)
wa.tm.abnormalEnd(err, false);
}
}
// if we must unwind, this call will re-throw the exception,
// otherwise it will return and we can continue with "normal"
// exception processing
wa.tm.honorError((ErrorConditionException) ce);
}
else if (current == Condition.STOP)
{
// if we must unwind, this call will re-throw the exception,
// otherwise it will return and we can continue with "normal"
// exception processing
wa.tm.honorStop((StopConditionException) ce);
// on stop condition triggered by stop-after timer,
// right block should be targeted
StopAfterTimer stopAfterTimer = wa.stopAfterTimer;
if (stopAfterTimer != null && stopAfterTimer.isStopAfterConditionRaised())
{
if (!stopAfterTimer.isStoppedBlock(wa.tm.getBlock()))
{
throw ce;
}
else
{
stopAfterTimer.cleanUp();
}
}
}
// first we UNDO at the specified label (which may be null meaning
// we UNDO the current block)
if (imple.condition == Condition.QUIT_COMMIT)
{
// let the action proceed without rollback
}
else
{
wa.tm.rollback(imple.undoLabel);
}
Action target = imple.action;
// honor ILP for NEXT
if (target == Action.NEXT)
{
if (!wa.tm.honorNext(imple.actionLabel))
{
// convert to a LEAVE
target = Action.LEAVE;
}
}
// second we implement the specified action
switch (target)
{
case THROW:
if (ce instanceof LegacyErrorException)
{
throw (LegacyErrorException) ce;
}
else if (ce instanceof ErrorConditionException)
{
throw (ErrorConditionException) ce;
}
break;
case LEAVE:
if (imple.actionLabel == null ||
imple.actionLabel.length() == 0 ||
imple.actionLabel.equals(label))
{
return Disposition.BREAK;
}
else
{
// at this point we must have a non-null and non-empty
// label that is the leave target
wa.deferredLeave = imple.actionLabel;
if (matches(enclosing, imple.actionLabel))
{
// the target is a non-managed block that directly
// encloses the current block, break out and let the
// calling code check to see that this needs to be
// honored
return Disposition.BREAK;
}
else
{
// unwind the stack
throw wa.leaveExc;
}
}
case NEXT:
if (imple.actionLabel == null ||
imple.actionLabel.length() == 0 ||
imple.actionLabel.equals(label))
{
return Disposition.CONTINUE;
}
else
{
// at this point we must have a non-null and non-empty
// label that is the next target
wa.deferredNext = imple.actionLabel;
if (matches(enclosing, imple.actionLabel))
{
// the target is a non-managed block that directly
// encloses the current block, break out and let the
// calling code check to see that this needs to be
// honored
return Disposition.BREAK;
}
else
{
// unwind the stack
throw wa.nextExc;
}
}
case RETRY:
// if this retry is being triggered by an ENDKEY, remember
// that fact so that the retry processing can be customized
// (this enables the "stuttering" quirk and some custom
// behavior with PAUSE
if (current == Condition.ENDKEY)
{
wa.tm.markEndkeyRetry();
}
// RETRY is always targetted at the same block as UNDO
wa.tm.triggerRetry(imple.undoLabel);
return Disposition.NONE;
case RETURN_NORMAL:
// this will throw an exception, it is OK because this method
// will always be called in the context of an inner block and
// WILL NEVER be called directly from a top-level block
returnWorker(wa, imple.value, ReturnType.NORMAL);
break;
case RETURN_CONSUME:
// this will throw an exception, it is OK because this method
// will always be called in the context of an inner block and
// WILL NEVER be called directly from a top-level block
returnWorker(wa, imple.value, ReturnType.CONSUME);
break;
case RETURN_ERROR:
// this will throw an exception, it is OK because this method
// will always be called in the context of an inner block and
// WILL NEVER be called directly from a top-level block
returnWorker(wa, imple.value, ReturnType.ERROR);
break;
default:
break;
}
}
StopAfterTimer stopAfterTimer = wa.stopAfterTimer;
if (stopAfterTimer != null && stopAfterTimer.isStopAfterConditionRaised())
{
if (stopAfterTimer.isStoppedBlock(wa.tm.getBlock()))
{
stopAfterTimer.cleanUp();
}
}
// no match so we just re-throw the exception and continue to unwind
// the stack; but we must process it as an unexpected exception which
// will maintain rollback state properly
wa.tm.abnormalEnd(ce, false);
// never reached because the code above will re-throw the exception
return null;
}
/**
* Translate exception into {@link Condition} code.
*
* @param ce
* Source exception.
*
* @return one of the {@link Condition} codes or <code>null</code> if no
* match is found.
*/
static Condition exceptionToCondition(ConditionException ce)
{
Condition current = null;
if (ce instanceof ErrorConditionException)
{
current = Condition.ERROR;
}
else if (ce instanceof EndConditionException)
{
current = Condition.ENDKEY;
}
else if (ce instanceof StopConditionException)
{
current = Condition.STOP;
}
else if (ce instanceof QuitConditionException)
{
current = Condition.QUIT;
}
return current;
}
/**
* Find a matching condition in the user-defined on phrases or the default
* on phrases for the block and return the on phrase that is matched. The
* user-defined on phrases are searched first and only if there is no
* match will the default on phrases be searched.
*
* @param user
* The set of user-defined on phrases for the current block.
* @param def
* The set of default on phrases for the current block.
* @param cond
* The condition being matched.
*
* @return The on phrase that defines the behavior to be implemented or
* <code>null</code> if there is no match in either list.
*/
private static OnPhrase matchCondition(OnPhrase[] user, OnPhrase[] def, Condition cond)
{
if (cond == null)
{
return null;
}
if (user != null)
{
for (OnPhrase next : user)
{
if (next.condition == cond || (cond == Condition.QUIT && next.condition == Condition.QUIT_COMMIT))
{
return next;
}
}
}
if (def != null)
{
for (OnPhrase next : def)
{
if (next.condition == cond)
{
return next;
}
}
}
return null;
}
/**
* Encode the conditions supported by this block as a bitfield.
* <p>
* The inputs are analyzed to match <code>Condition</code> values with
* their corresponding bits in the <code>TransactionManager</code>
* properties bitfield.
* <p>
* The bits are defined by {@link TransactionManager#PROP_NONE},
* {@link TransactionManager#PROP_ERROR},
* {@link TransactionManager#PROP_ENDKEY},
* {@link TransactionManager#PROP_STOP} or
* {@link TransactionManager#PROP_QUIT}.
*
* @param user
* The set of user-defined on phrases for the current block.
* @param def
* The set of default on phrases for the current block.
*
* @return The calculated bitmask with each bit set that matches one of
* the ON phrase conditions. <code>PROP_NONE</code> will be
* returned if both parameters are <code>null</code> and/or
* empty.
*/
private static int decodeConditions(OnPhrase[] user, OnPhrase[] def)
{
int bits = PROP_NONE;
if (user != null)
{
for (OnPhrase next : user)
{
bits |= conditionMask(next.condition);
}
}
if (def != null)
{
for (OnPhrase next : def)
{
bits |= conditionMask(next.condition);
}
}
return bits;
}
/**
* Matches a <code>Condition</code> with its corresponding
* <code>TransactionManager</code> constant.
*
* @param props
* The calculated bitmask with each bit set that matches one of
* the ON phrase conditions.
* @param cond
* The condition to match.
*
* @return <code>true</code> if the condition is present in the bitmask,
* <code>false</code> otherwise.
*/
public static boolean testProps(int props, Condition contition)
{
return (props & conditionMask(contition)) != 0;
}
/**
* Matches a <code>Condition</code> with its corresponding
* <code>TransactionManager</code> constant.
*
* @param cond
* The condition to match.
*
* @return The integer constant that represents the given condition.
*/
private static int conditionMask(Condition cond)
{
int rc = PROP_NONE;
switch (cond)
{
case ERROR:
rc = PROP_ERROR;
break;
case ENDKEY:
rc = PROP_ENDKEY;
break;
case STOP:
rc = PROP_STOP;
break;
case QUIT:
rc = PROP_QUIT;
break;
default:
break;
}
return rc;
}
/**
* Detect if the leave event is referencing this block OR if it is
* referencing a directly enclosing block which is not managed by this
* class. In either case, the result will be to break out of the current
* block. In all other cases, the result will be to re-throw the exception
* and cause the stack to unwind to the nearest enclosing managed block.
* <p>
* The target of the leave operation must have been stored in context
* local data when the leave exception was thrown (which caused the
* stack to unwind).
* <p>
* This method is called from within a catch block to determine how to
* respond to the deferred leave operation for the current block.
*
* @param wa
* Context local work area. Must not be {@code null}.
* @param enclosing
* The list of non-managed blocks that directly enclose the
* current block.
* @param label
* The name of the current block. If this matches the target of
* the deferred leave operation, then the current block must
* be left.
*
* @return Either <code>BREAK</code> or <code>THROW</code>.
*/
private static Disposition testLeave(WorkArea wa, String[] enclosing, String label)
{
// test if the LEAVE is destined for this block
if (deferredLeaveWorker(wa, label))
{
// it is, so honor the LEAVE
return Disposition.BREAK;
}
else
{
// handle of LEAVE on an enclosing block that is not one
// of which the block manager is aware
if (matches(enclosing, wa.deferredLeave))
{
return Disposition.BREAK;
}
}
// the LEAVE must be referencing an enclosing block which IS known
// to the block manager OR to one of the other enclosing managed
// blocks, so keep unwinding the stack
return Disposition.THROW;
}
/**
* Detect if the next event is referencing this block OR if it is
* referencing a directly enclosing block which is not managed by this
* class. In the first case, the result will be to continue the current
* block. In the second case, the caller must break out of the current
* block. In all other cases, the result will be to re-throw the exception
* and cause the stack to unwind to the nearest enclosing managed block.
* <p>
* The target of the next operation must have been stored in context
* local data when the next exception was thrown (which caused the
* stack to unwind).
* <p>
* This method is called from within a catch block to determine how to
* respond to the deferred next operation for the current block.
*
* @param wa
* Context local work area. Must not be {@code null}.
* @param enclosing
* The list of non-managed blocks that directly enclose the
* current block.
* @param label
* The name of the current block. If this matches the target of
* the deferred leave operation, then the current block must
* be left.
*
* @return Either <code>BREAK</code>, <code>CONTINUE</code> or
* <code>THROW</code>.
*/
private static Disposition testNext(WorkArea wa, String[] enclosing, String label)
{
// test if the NEXT is destined for this block
if (deferredNextWorker(wa, label))
{
// it is, so honor the NEXT
return Disposition.CONTINUE;
}
else
{
// handle of NEXT on an enclosing block that is not one
// of which the block manager is aware
if (matches(enclosing, wa.deferredNext))
{
return Disposition.BREAK;
}
}
// the NEXT must be referencing an enclosing block which IS known
// to the block manager OR to one of the other enclosing managed
// blocks, so keep unwinding the stack
return Disposition.THROW;
}
/**
* Common worker to cleanup top-level block state just before exiting.
*
* @param wa
* The local context.
*/
private static void exitTopLevel(WorkArea wa)
{
wa.topType.pop();
wa.deferredLeave = null;
wa.deferredNext = null;
}
/**
* Preserve certain work area state before running the given code and then restore that state
* afterward. The code may contain and/or invoke arbitrarily complex code and control flow.
* Direct invocation (without the state backup/restore) would otherwise corrupt the current
* work area state.
*
* @param wa
* Context local data or {@code null} if not available in the caller.
* @param code
* The code to execute.
*/
private static void executeStateManaged(WorkArea wa, Runnable code)
{
// preserve current work area state
ReturnType rtype = wa.rtype;
String deferredLeave = wa.deferredLeave;
String deferredNext = wa.deferredNext;
boolean pendingDynCall = wa.pendingDynCall;
// set a clean slate for validate processing
wa.rtype = null;
wa.deferredLeave = null;
wa.deferredNext = null;
wa.pendingDynCall = false;
try
{
code.run();
}
finally
{
// restore previous state
wa.rtype = rtype;
wa.deferredLeave = deferredLeave;
wa.deferredNext = deferredNext;
wa.pendingDynCall = pendingDynCall;
}
}
/**
* Set the return value for the nearest enclosing function. This should only be called if the
* nearest enclosing top-level block is a {@code FUNCTION}. Multiple calls to this before
* returning from the function block will cause the value passed on the last call to be
* honored.
*
* @param bdt
* The return value to set. Passing {@code null} will reset the return value to
* {@code unknown}.
* @param wa
* The current context's data or {@code null} to force a lookup of the context data.
* @param nearest
* The nearest top-level block. Should be a FUNCTION block. Pass {@code null} to
* use the context data to find the block.
*/
private static void setFuncReturn(Object bdt, WorkArea wa, BlockType nearest)
{
if (bdt == null)
{
return;
}
// replace the current latest value with the given instance
if (wa == null)
{
wa = work.obtain();
}
if (nearest == null)
{
nearest = topLevelType(wa);
}
if (nearest == BlockType.FUNCTION)
{
if (wa.funcRet.size() > 0)
{
wa.funcRet.pop();
wa.funcRet.push(bdt);
Class<?> rclass = bdt.getClass();
if (rclass.isArray() && rclass.getComponentType() == object.class)
{
for (object<?> obj : (object[]) bdt)
{
if (obj == null || obj.isUnknown())
{
continue;
}
_BaseObject_ ref = obj.ref;
// mark this object as a pending assign - it will not be implicitly deleted
// if it's current referent gets out of scope
wa.objHelper.pendingAssign(ref);
}
}
else if (bdt instanceof object)
{
if (!((object) bdt).isUnknown())
{
_BaseObject_ ref = ((object) bdt).ref;
// mark this object as a pending assign - it will not be implicitly deleted
// if it's current referent gets out of scope
wa.objHelper.pendingAssign(ref);
}
}
}
}
}
/**
* Given a list of strings, detect if the given entry matches (case
* sensitively) any of the elements in the list.
*
* @param list
* The list of strings to check against.
* @param entry
* The element for which to search.
*
* @return <code>true</code> if the given entry is found in the given
* list.
*/
private static boolean matches(String[] list, String entry)
{
if (list == null || entry == null)
return false;
for (String element : list)
{
if (entry.equalsIgnoreCase(element))
{
return true;
}
}
return false;
}
/**
* Helper to convert between this class' enum and the corresponding {@link TransactionManager} constants.
*
* @param ttype
* The enum to convert.
* @param btype
* The block type.
*
* @return The corresponding {@link TransactionManager} constant.
*/
private static int convertTransType(TransactionType ttype, BlockType btype)
{
int newType = -1;
switch (ttype)
{
case NONE:
newType = NO_TRANSACTION;
break;
case SUB:
newType = SUB_TRANSACTION;
break;
case FULL:
newType = TRANSACTION;
break;
default:
break;
}
return newType;
}
/**
* Accesses the type of the nearest enclosing top level block.
*
* @param wa
* The current context's data or {@code null} to force a lookup of the context data.
*
* @return The type of the enclosing top level block or {@code null} if there is no top-level
* block in the call stack.
*/
private static BlockType topLevelType(WorkArea wa)
{
if (wa == null)
{
wa = work.obtain();
}
return wa.topType.peek();
}
/**
* Check if we are on the top level of a persistent trigger.
*
* @param wa
* The current context's data.
*
* @return <code>true</code> if we are on the top level of a persistent trigger
*/
private static boolean isPersistentTriggerTopLevel(WorkArea wa)
{
// The top level of a persistent trigger has the following top-level blocks stack:
// EXTERNAL_PROC/INTERNAL_PROC and then persistent TRIGGER.
Iterator<BlockType> iter = wa.topType.iterator();
if (!iter.hasNext())
{
return false;
}
BlockType top = iter.next();
if (top != BlockType.EXTERNAL_PROC &&
top != BlockType.INTERNAL_PROC)
{
return false;
}
if (!iter.hasNext() || iter.next() != BlockType.TRIGGER)
{
return false;
}
return LogicalTerminal.isTopTriggerPersistent();
}
/**
* Update block execution statistics for the given block instance. Depending
* of the block type, either the class name of the block will be inspected
* or the call stack will be inspected to determine the block name and then
* the usage statistics for that block will be incremented.
*
* @param type
* The type of the block.
* @param block
* The block that is about to be executed.
* @param start
* The start time of the block's execution.
*/
private static void recordExecutionStats(BlockType type, Block block, long start)
{
long end = System.currentTimeMillis();
// the first application entry in the stack is the one that describes
// what we are executing
character sname = EnvironmentOps.getSourceName(1);
String descr = null;
// this shouldn't be null, but we will be safe anyway
if (sname == null)
{
descr = "Unknown (call stack analysis failed)";
}
else
{
descr = sname.toStringMessage();
}
// triggers will appear as the same as an external procedure
if (type == BlockType.TRIGGER ||
type == BlockType.DATABASETRIGGER)
{
// calculate the specific trigger that was executed
String className = block.getClass().getName();
int idx = className.lastIndexOf('$');
if (idx >= 0)
{
className = className.substring(idx + 1);
}
// append the trigger portion of the class name to the description
descr = descr + ' ' + className;
}
// update the statistics
AtomicInteger count = stats.get(descr);
AtomicLong time = times.get(descr);
if (count == null)
{
stats.put(descr, count = new AtomicInteger(0));
times.put(descr, time = new AtomicLong(0));
}
time.addAndGet(end - start);
count.incrementAndGet();
}
/**
* The CATCH statement. This API must be called from the Block's init method, and it will
* register a listener for the specified STOP/ERROR condition.
* <p>
* The catch order is the order of this API registration calls.
*
* @param type
* The CATCH's error type.
* @param catchBlock
* The code to be executed for this error.
*/
private static <T extends _BaseObject_> void registerCatchBlock(Class<T> type,
Consumer<object<T>> catchBlock)
{
BlockDefinition block = TransactionManager.getBlock();
if (block.catchBlocks == null)
{
block.catchBlocks = new LinkedHashMap<>();
}
// check if any of the current caught types are a super-class or the same as the current
// type; if so, abort
for (Class<?> cls : block.catchBlocks.keySet())
{
if (cls.isAssignableFrom(type))
{
return;
}
}
block.catchBlocks.put(type, (Consumer) catchBlock);
}
/**
* Generates a CSV file with the recorded execution statistics.
*/
private static void dumpExecutionStats()
{
if (statsFile != null)
{
PrintWriter out = null;
try
{
out = new PrintWriter(new File(statsFile));
}
catch (FileNotFoundException fnfe)
{
// TODO: log this?
}
if (out != null)
{
out.println("\"Entry Point\",\"Execution Counter\",\"Execution total time\"");
Set<String> keyset = stats.keySet();
Iterator<String> keys = keyset.iterator();
while (keys.hasNext())
{
String entry = keys.next();
AtomicInteger count = stats.get(entry);
AtomicLong time = times.get(entry);
out.printf("\"%s\",\"%d\",\"%s\"\n", entry, count.get(), time.get());
}
out.flush();
out.close();
}
}
}
/**
* Helper to expose state in a way that avoids context local lookups.
*/
static class BlockManagerHelper
{
/** The {@link WorkArea} instance. */
private WorkArea wa;
/**
* Create a new instance and associate the given WorkArea instance.
*
* @param wa
* The {@link WorkArea} instance.
*/
public BlockManagerHelper(WorkArea wa)
{
this.wa = wa;
}
/**
* Mark the start of a pending dynamic call, via {@link ControlFlowOps}.
*/
public void markPendingDynCall()
{
wa.pendingDynCall = true;
}
}
/**
* Stores global data relating to the state of the current context's
* blocks.
*/
private static class WorkArea
{
/** Helper to use the TM without any context local lookups. */
public TransactionManager.TransactionHelper tm = TransactionManager.getTransactionHelper();
/** Helper to use the ProcedureManager without any context local lookups. */
public ProcedureManager.ProcedureHelper pm = ProcedureManager.getProcedureHelper();
/** Helper to use the ControlFlowOps without any context local lookups. */
public ControlFlowOps.ControlFlowOpsHelper cfops = ControlFlowOps.getHelper();
/** Helper to use the ObjectOps without any context local lookups. */
public ObjectOps.ObjectHelper objHelper = ObjectOps.getObjectHelper();
/** Helper to use the ErrorManager without any context local lookups. */
public ErrorManager.ErrorHelper errHelper = ErrorManager.getErrorHelper();
/** A return value for each function block on the call stack. */
public Deque<Object> funcRet = new ArrayDeque<>();
/** Return processing type for the current function block on the call stack. */
public ReturnType rtype = null;
/** Tracks the type of each top-level block as a stack. */
public ArrayDeque<BlockType> topType = new ArrayDeque<BlockType>();
/** Common, long-lived instance to make leave processing faster. */
public LeaveUnwindException leaveExc = new LeaveUnwindException();
/** Common, long-lived instance to make next processing faster. */
public NextUnwindException nextExc = new NextUnwindException();
/** Common, long-lived instance to make return processing faster. */
public ReturnUnwindException retExc = new ReturnUnwindException();
/** Object responsible for managing stop-after on Progress blocks. */
public StopAfterTimer stopAfterTimer = null;
/** Block name which should be left. */
public String deferredLeave = null;
/** Block name which should be iterated. */
public String deferredNext = null;
/** Flag indicating if a proc/function is executed via ControlFlowOps.invoke APIs. */
public boolean pendingDynCall = false;
/** Flag indicating if stop-after is enabled in directory */
public boolean isStopAfterActive = true;
/** A code to execute instead of the next top-level block, as the argument assignment failed. */
public Runnable ignoreNextCall = null;
/** Parameter indicating whether Stop condition should be raised as OO error. */
public int catchStopParameter = SessionUtils._startupParameters().getCatchStop() != null ?
SessionUtils._startupParameters().getCatchStop() :
0;
}
/**
* Simple container that stores and returns a context-local instance of
* the global work area.
*/
private static class ContextContainer
extends ContextLocal<WorkArea>
{
/**
* Obtains the context-local instance of the contained global work
* area.
*
* @return The work area associated with this context.
*/
public WorkArea obtain()
{
return this.get();
}
/**
* Initializes the work area, the first time it is requested within a
* new context.
*
* @return The newly instantiated work area.
*/
protected synchronized WorkArea initialValue()
{
boolean stopAfter = Utils.getDirectoryNodeBoolean(null,
"legacy-system/stop-after",
true,
Utils.DirScope.BOTH,
null);
WorkArea wa = new WorkArea();
if (!stopAfter)
{
wa.isStopAfterActive = false;
}
return wa;
}
}
/**
* Server-wide hook that gets called at initialization and termination. We
* use this to write out execution statistics when the statistics counters
* are enabled.
*/
private static class StatsHelper
implements InitTermListener
{
/**
* This method is invoked when server is about to be started.
*/
public void initialize()
{
// do nothing
}
/**
* This method is invoked when the server is terminating.
*
* @param t
* Error or exception which caused exit of the server. Can
* be <code>null</code> if there was a normal end.
*/
public void terminate(Throwable t)
{
dumpExecutionStats();
}
}
}