BlockDefinition.java
/*
** Module : BlockDefinition.java
** Abstract : stores block-related information for runtime processing
**
** Copyright (c) 2005-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------------Description-----------------------------------
** 001 GES 20050809 @22097 Created initial version, supporting
** block information for undo and retry.
** 002 GES 20060202 @24224 Added external flag to allow processing that
** is dependent upon the external procedure to
** be properly hooked. This enables the proper
** cleanup of resources like temp-tables,
** frames and streams.
** 003 GES 20060202 @24246 Added init and iterate flags to allow
** the blockSetup() method of TransactionManager
** to compensate for Java continue statements
** which otherwise bypass iterate() calls.
** 004 GES 20060314 @25059 Added toString().
** 005 GES 20060510 @26057 Added blockTop flag for use during iterate()
** processing.
** 006 GES 20060626 @27568 Added suppressError flag.
** 007 GES 20060804 @28428 Removed iterate and blockTop flags.
** 008 CA 20080207 @37025 Added block type field.
** 009 ECF 20080218 @37117 Integrated generics.
** 010 GES 20080505 @38208 Changed undoables to be an array for
** performance.
** 011 GES 20080613 @38883 Added hadPause and endkeyRetry flags, the
** retryCount counter and the backupUndoList.
** 012 GES 20080625 @38957 Changed to BlockType enum.
** 013 GES 20080627 @38991 Added isUndoLevel flag.
** 014 CA 20081127 @40707 Added iterated flag - indicates if a block
** was iterated at least once.
** 015 GES 20081120 @40739 Added properties bitmap and interactions
** counter.
** 016 GES 20081210 @40865 Added rollup property.
** 017 GES 20090422 @41904 Converted to standard string formatting.
** 018 ECF 20090816 @43652 Added OutputParameterAssigner field.
** 019 CA 20121220 Added the Block instance to the block definition.
** 020 CA 20160627 Reworked undoable support - the undoables register themselves with
** all blocks up the stack, until either 1. the tx block which created
** it is reached or 2. the last tx block where it was saved is reached.
** 021 ECF 20171030 Added transId for transaction metadata support.
** 022 OM 20190117 Removed transId because it is not used any more.
** CA 20190219 Added CATCH block support.
** 023 ECF 20190714 Added FOR block aggressive flushing support.
** 024 AIL 20191120 Added database trigger flag.
** 025 GES 20210809 Added finallyBlock runnable.
** CA 20220120 Improved performance for finalizables, keep them already sorted by their weight.
** ConditionListener's are kept in their own list.
** 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.
** CA 20221006 Lazy initialization for commitables and conditionListeners. 'finalizables' can be
** a set instead of a list, as their order is not important. Refs #6824
** SVL 20230108 Improved performance by replacing some "for-each" loops with indexed "for" loops.
** 026 CA 20230615 Added possibleCatch runnable, to delay execution of the catch block just before
** the FINALLY block executes.
** 027 CA 20231026 Do not pin the Block instance to memory.
** 028 CA 20231221 Refactored the WidgetPool scopeable support to register for processing as needed.
** 029 ES 20240513 Added hasStopAfter flag.
** 030 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.
** 031 ES 20240919 Added undoThrow flag.
** 032 ES 20240410 Removed catchBlock variable, CATCH block will be marked as BlockType.CATCH.
*/
/*
** 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.function.*;
import com.goldencode.p2j.security.*;
/**
* Container of block information for Progress compatible rollback (undo)
* commit and retry. The members of this class are intentionally made
* <code>public</code> since this is just a simple container.
*/
public class BlockDefinition
{
/** Sprintf format specification for string representation. */
private static final String spec = "[label = %s; type = %s; full = %b; " +
"trans_level = %s; external = %b; " +
"top_level = %b; loop = %b; " +
"loop_protection = %b; had_pause = %b" +
"; endkey_retry = %b; next_or_leave =" +
" %s; is_retry = %b; needs_retry = %b" +
"; FOR (aggressive) flushing = %b" +
"; ilp_count = %d; pending_break = %b" +
"; database_trigger = %b; properties = '%s'" +
"; finally = %s]";
/** Label to identify this block. */
public String label = null;
/** Caches whether or not this block started a transaction. */
public boolean full = false;
/** Level of transaction support for this block. */
public int level = TransactionManager.NO_TRANSACTION;
/**
* The depth of this transaction block, when {@link #level} is
* {@link TransactionManager#TRANSACTION} or {@link TransactionManager#SUB_TRANSACTION}.
*/
public int txNestingLevel = -1;
/** Bitmap specifying the block properties active for this block. */
public int props = TransactionManager.PROP_NONE;
/** Defines if this block is derived from an external procedure. */
public boolean external = false;
/** Defines if this block is a top-level block (a method) or not. */
public boolean topLevel = false;
/** Defines if this block is a loop or not. */
public boolean loop = false;
/** Has this block iterated at least once. */
public boolean iterated = false;
/** This block's type. */
public BlockType type = BlockType.UNKNOWN;
/** Defines if this iteration requires infinite loop protection. */
public boolean loopProtection = true;
/** Defines if this iteration has encountered a pause. */
public boolean hadPause = false;
/** Marks the current retry as one caused by an <code>ENDKEY</code>. */
public boolean endkeyRetry = false;
/** Counts the number of sequential retries converted to NEXT or LEAVE. */
public int ilpCount = -1;
/** Counter for the number of interactive stmts in the current block. */
public int interactions = 0;
/** Aggregate interactions counter when a client block exits. */
public boolean rollup = true;
/** Has this block initialized at least once. */
public boolean init = false;
/**
* Defines if this iteration has a pending break which was generated by
* infinite loop protection during a retry.
*/
public boolean pendingBreak = false;
/** Defines if this iteration requires a retry. */
public boolean retry = false;
/** Defines if this iteration is a retry (versus the first pass). */
public boolean wasRetried = false;
/** Determines if infinite loop protection converts retry into next or leave. */
public boolean next = false;
/** Flag indicating a top-level block is exiting via RETURN ERROR. */
public boolean wasReturnError = false;
/**
* Flag indicating this block is nested within or is itself a FOR block and as such requires
* aggressive buffer flushing.
*/
public boolean forFlushing = false;
/** Defines if this block is a database trigger, as:
* - schema trigger if is topLevel external procedure in Database Trigger class
* - session trigger if is topLevel trigger type
*/
public boolean databaseTrigger = false;
/** Indicates whether the block has a stop-after statement. */
public boolean hasStopAfter = false;
/** Defines if this block was undone. */
public boolean rolledBack = false;
/** Defines if this block was already committed. */
public boolean committed = false;
/** Defines if this blocks is or was the target of UNDO. */
public boolean isUndoLevel = false;
/** Defines if this block's caller requires errors to be suppressed. */
public boolean suppressError = false;
/** Stores the list of undoable objects. */
public ArrayList<UndoablePair> undoables = null;
/**
* Stores the list of commitable objects to be notified at successful
* completion of this block.
*/
public ArrayList<Commitable> commitables = null;
/**
* Stores the list of finalizable objects to be notified when the flow
* of control exist from this block in any manner.
*/
public Set<Finalizable>[] finalizables = new Set[WeightFactor.WEIGHTS_ARRAY_SIZE];
/**
* The list of {@link Scopeable} instances which are required to be processed in this block.
* <p>
* This list is dynamically adjusted - it can be added a new scopeable before or after the block has started.
* If the new instance is registered after the block has started, the {@link Scopeable#scopeStart} will
* be executed at the time of registration.
* <p>
* The index is the scopeable's ID, as only an instance of each type can be registered.
*/
public Scopeable[] scopeList = null;
/** The list of condition listeners. Processed in the registration order.. */
public ArrayList<ConditionListener> conditionListeners = null;
/** Stores the output parameter assigner */
public OutputParameterAssigner outputParmAssigner = null;
/** Map of defined catch blocks*/
public Map<Class<?>, Consumer<object>> catchBlocks = null;
/** FINALLY block to be executed at the next iteration, retry or finished. */
public Runnable finallyBlock = null;
/** Possible CATCH block to be executed at the next iteration, retry or finished. */
public Runnable possibleCatch;
/** Flag indicating if this block has widget pool scoping. */
public boolean widgetPool = false;
/** Flag indicating that a rollback in an undo throw has been raised */
public boolean undoThrow = false;
/**
* Construct an instance to represent a new block.
*
* @param label
* This scope's label.
* @param level
* The type of transaction processing this scope can participate
* in. This must be set to one of the following
* <code>TransactionManager</code> constants:
* <code>NO_TRANSACTION, SUB_TRANSACTION or TRANSACTION</code>.
* @param props
* A bitfield storing block properties which will be a
* combination of <code>TransactionManager</code> constants:
* <code>PROP_NONE, PROP_ERROR, PROP_ENDKEY, PROP_STOP</code>
* and <code>PROP_QUIT</code>.
* @param full
* If <code>true</code> this scope starts a full transaction
* (this is the scope at which database commits will occur).
* @param external
* <code>true</code> if this block is associated with the
* external procedure (in Progress terms). This controls the
* cleanup of certain resources such as temp-tables, frames
* and streams.
* @param topLevel
* <code>true</code> if this block is a method.
* @param loop
* <code>true</code> if this block is a loop.
* @param next
* <code>true</code> if this infinite loop protection should
* convert a retry into a next (continue), otherwise the retry
* will be converted into a leave (break).
* @param databaseTrigger
* <code>true</code> if this is a topLevel block defined as a
* database trigger
* @param type
* This block's type.
*/
public BlockDefinition(String label,
int level,
int props,
boolean full,
boolean external,
boolean topLevel,
boolean loop,
boolean next,
boolean forFlushing,
boolean databaseTrigger,
BlockType type)
{
this.label = label;
this.level = level;
this.props = props;
this.full = full;
this.external = external;
this.topLevel = topLevel;
this.loop = loop;
this.next = next;
this.forFlushing = forFlushing;
this.databaseTrigger = databaseTrigger;
this.type = type;
}
/**
* Render this block's data as a human readable string.
*
* @return The human readable form of this block's data.
*/
public String toString()
{
Object[] parms = new Object[]
{
label,
type.toString(),
full,
TransactionManager.decodeLevel(level),
external,
topLevel,
loop,
loopProtection,
hadPause,
endkeyRetry,
(next ? "next" : "leave"),
wasRetried,
retry,
forFlushing,
ilpCount,
pendingBreak,
databaseTrigger,
TransactionManager.decodeProperties(props),
(finallyBlock == null) ? "none" : finallyBlock.toString()
};
return String.format(spec, parms);
}
}