java.lang.Object
overit.geocall.bl.BusinessTask<Void>
overit.geocallapp.utilities.core.bl.common.task.BTHistory
All Implemented Interfaces:
Serializable, Tool
Direct Known Subclasses:
BTAccountContactHistory, BTAccountHistory, BTAddressHistory, BTAddressHistory, BTAgendaHistory, BTAgendaHistory, BTAIConfigurationParamsHistory, BTAIModelHistory, BTAssetCharacteristicValueHistory, BTAssetContactHistory, BTAssetHistory, BTContactHistory, BTMaterialHistory, BTMaterialHistory, BTMeasureHistory, BTMeterConverterHistory, BTMeterHistory, BTMeterHistory, BTPermitObtainedHistory, BTPermitRequiredHistory, BTProjectActivityHistory, BTProjectDiaryHistory, BTProjectHeaderHistory, BTSerializedMaterialHistory, BTSkillConfigurationHistory, BTSkillDivisionHistory, BTStockHistory, BTTaskHistory, BTTechnicalObjectFeatureValueHistory, BTTechnicalObjectHeaderHistory, BTTimesheetHeaderHistory, BTWorkOrderHeaderHistory, BTWorkOrderOperationHistory

public abstract class BTHistory extends BusinessTask<Void>
Abstract business task for managing entity history records.
This class provides a framework for tracking changes to entities by creating history records in dedicated history tables. It supports various operations including:
  • Creating history records alongside entity modifications (insert/update/delete)
  • Creating history records for existing entities without modifying them
  • Comparing current entity state with previous history records
  • Translating entity fields to corresponding history table fields
The class handles the mapping between entity tables and history tables, manages operation codes for different actions, and provides extension points for customization.
Since:
1.0
See Also:
  • Field Details

    • LOG

      protected static final LogChannel LOG
    • HISTORY_TABLE_TRANSLATE_FIELD_CACHE

      protected static ConcurrentHashMap<String,HashGetter> HISTORY_TABLE_TRANSLATE_FIELD_CACHE
    • dao

      protected DAO dao
    • daoHistory

      protected DAO daoHistory
    • validModes

      protected List<Command> validModes
    • operationMode

      protected Command operationMode
    • operationCode

      protected Long operationCode
    • TYPE_COMMAND_AND_HISTORY

      protected static final int TYPE_COMMAND_AND_HISTORY
      See Also:
    • TYPE_ONLY_HISTORY

      protected static final int TYPE_ONLY_HISTORY
      See Also:
    • operationType

      protected int operationType
    • filters

      protected Map<String,Object> filters
    • values

      protected Map<String,Object> values
    • historyFieldsMap

      protected HashGetter historyFieldsMap
    • currentDBValues

      protected DBView currentDBValues
    • elaboratedRows

      protected int elaboratedRows
    • historyWritten

      protected boolean historyWritten
    • newHistoryRecordId

      protected Long newHistoryRecordId
    • HISTORY_CACHE_NAME

      protected static final String HISTORY_CACHE_NAME
      See Also:
  • Constructor Details

    • BTHistory

      public BTHistory()
  • Method Details

    • getValidOperationModes

      protected ArrayList<Command> getValidOperationModes()
      Returns the list of valid operation modes supported by this history task. By default, this includes INSERT, UPDATE (by PK and by filter), and DELETE (by PK and by filter) operations. Subclasses can override this method to provide a different set of valid operations.
      Returns:
      a list of valid Command objects
    • setCommandAndHistoryParams

      public void setCommandAndHistoryParams(Command operationMode, Map<String,Object> filters, Map<String,Object> values)
      Configures the task to perform both an entity operation and history recording. This method sets up the task to execute a database command on the entity table and then record the change in the history table.
      Parameters:
      operationMode - the DAO command to execute (INSERT, UPDATE, DELETE)
      filters - the criteria to identify records for update or delete operations
      values - the new values to apply in insert or update operations
    • setHistoryParams

      public void setHistoryParams(Command.Type type, Map<String,Object> filters)
      Configures the task to perform only history recording without modifying the entity. This method sets up the task to create a history record for an existing entity without performing any modifications to the entity itself.
      Parameters:
      type - the type of operation to record in history (INSERT, UPDATE, DELETE)
      filters - the criteria to identify the entity record for history recording
    • getHistoryRecordId

      public Long getHistoryRecordId()
      Returns the ID of the newly created history record.
      Returns:
      the ID of the history record, or null if no record was created
    • getElaboratedRows

      public int getElaboratedRows()
      Returns the number of entity records affected by the operation.
      Returns:
      the count of affected records
    • isHistoryWritten

      public boolean isHistoryWritten()
      Indicates whether a history record was successfully written.
      Returns:
      true if a history record was written, false otherwise
    • body

      protected void body(Void v, PoolKit pk) throws DAException, DAValidateException
      Main execution method of the history task. This method orchestrates the entire history recording process:
      • Initializes the DAOs
      • Validates input parameters
      • Loads current database data if needed
      • Applies the entity operation if in COMMAND_AND_HISTORY mode
      • Creates the history record
      Specified by:
      body in class BusinessTask<Void>
      Parameters:
      v - void parameter (not used)
      pk - the PoolKit
      Throws:
      DAException - if a data access error occurs
      DAValidateException - if validation fails
    • getBTDescription

      protected abstract String getBTDescription()
      Returns a descriptive name for this history task. This name is used for logging purposes to identify the specific history task being executed.
      Returns:
      a string describing the task
    • initializeDAO

      protected abstract void initializeDAO()
      Initializes the DAOs used by this history task. Implementations must set:
      • dao: for entity table operations (insert/update/delete)
      • daoHistory: for history table operations
    • validateParams

      protected void validateParams() throws DAValidateException
      Validates input parameters before starting the history operation. This method checks that all required parameters are properly set based on the operation type. It verifies:
      • DAOs are initialized
      • Operation type is valid
      • Operation mode is valid (for COMMAND_AND_HISTORY)
      • Filters are provided when required
      • Values are provided when required
      Throws:
      DAValidateException - if any validation check fails
    • loadCurrentDBData

      protected void loadCurrentDBData(PoolKit pk) throws DAException, DAValidateException
      Loads the current database record for update or delete operations. This method retrieves the current state of the entity record before applying modifications, so it can be compared with the new state when creating the history record.
      Parameters:
      pk - the PoolKit
      Throws:
      DAException - if a data access error occurs
      DAValidateException - if validation fails
    • applyCommand

      protected void applyCommand(PoolKit pk) throws DAException, DAValidateException
      Applies the entity operation (insert, update, or delete). This method executes the specified command on the entity table using the provided filters and values. It calls preElaboration before and postElaboration after the command execution to allow for customizations.
      Parameters:
      pk - the PoolKit
      Throws:
      DAException - if a data access error occurs
      DAValidateException - if validation fails
    • postElaboration

      protected void postElaboration(PoolKit pk) throws DAException, DAValidateException
      Hook method called after the entity operation is executed. This method is called after the entity has been modified (inserted, updated, or deleted). Subclasses can override this method to perform additional actions after the entity operation completes successfully.
      Parameters:
      pk - the PoolKit
      Throws:
      DAException - if a data access error occurs
      DAValidateException - if validation fails
    • preElaboration

      protected void preElaboration(PoolKit pk) throws DAException, DAValidateException
      Hook method called before the entity operation is executed. This method is called before the entity is modified (inserted, updated, or deleted). Subclasses can override this method to perform additional actions before the entity operation begins.
      Parameters:
      pk - the PoolKit
      Throws:
      DAException - if a data access error occurs
      DAValidateException - if validation fails
    • createHistoryRecord

      protected void createHistoryRecord(PoolKit pk) throws DAException, DAValidateException
      Creates a history record for the current entity operation. This method orchestrates the history record creation process by:
      • Loading the field translation map between entity and history tables
      • Inserting the appropriate history record based on the operation type
      The history record will contain the relevant entity data and metadata about the operation that was performed.
      Parameters:
      pk - the PoolKit
      Throws:
      DAException - if a data access error occurs
      DAValidateException - if validation fails
    • loadTranslatedFieldMap

      protected void loadTranslatedFieldMap(PoolKit pk) throws DAException, DAValidateException
      Loads the field translation map between entity and history tables. This method retrieves or builds a mapping between entity table fields and their corresponding history table fields. The mapping is cached in a static ConcurrentHashMap to improve performance for subsequent operations. The cache key is constructed from the pool name and table name to ensure uniqueness across different entity types.
      Parameters:
      pk - the PoolKit
      Throws:
      DAValidateException - if validation fails during map building
      DAException - if a data access error occurs during map building
    • buildMap

      protected HashGetter buildMap(PoolKit pk) throws DAException, DAValidateException
      Builds the translation map from entity fields to history fields. This method analyzes the database schema for both the entity table and history table, and creates a mapping between corresponding fields. It follows naming conventions to determine field correspondences, handling different prefixes for standard and custom fields. Special fields like LOGIN, ACTION, and DATASTAMP are excluded from the mapping. The method also provides a hook point for customizations through the customizeFieldMap method.
      Parameters:
      pk - the PoolKit
      Returns:
      a HashGetter containing the translation map from entity field names to history field names
      Throws:
      DAValidateException - if validation fails during schema retrieval
      DAException - if a data access error occurs during schema retrieval
    • getHistorySequenceField

      protected String getHistorySequenceField()
      Returns the name of the sequence field in the history table.
      Returns:
      the name of the sequence field in the history table
    • getHistoryTableField

      protected String getHistoryTableField(String tableField, DBFields historyTableFieldMap)
      Maps an entity table field name to its corresponding history table field name. This method applies naming conventions to determine the corresponding field name in the history table for a given entity table field. It handles several patterns:
      • Standard geocall/crm fields: replaces entity prefix with history prefix
      • Geocall/crm fields mapped to WFM fields: replaces entity prefix with "XWFM" + history prefix
      • WFM/custom fields: handles "X..." prefixed fields with appropriate transformations
      If no corresponding field is found in the history table, the method returns null.
      Parameters:
      tableField - the entity field name to map
      historyTableFieldMap - the DBFields containing all fields in the history table
      Returns:
      the corresponding history field name, or null if no matching field exists
    • customizeFieldMap

      protected void customizeFieldMap(HashGetter hgMap)
      Hook method for customizing the field mapping between entity and history tables. This method provides a customization point for subclasses to modify the automatically generated field mapping. Subclasses can override this method to:
      • Add mappings for fields that don't follow standard naming conventions
      • Remove mappings that should not be included in history records
      • Modify existing mappings to handle special cases
      The default implementation does nothing, preserving the automatically generated mapping.
      Parameters:
      hgMap - the translation map from entity fields to history fields to be customized
    • getEntityTablePrefix

      protected abstract String getEntityTablePrefix()
      Returns the prefix used in field names of the entity table.
      Returns:
      the prefix string used in field names of the entity table
    • getHistoryTablePrefix

      protected abstract String getHistoryTablePrefix()
      Returns the prefix used in field names of the history table.
      Returns:
      the prefix string used in field names of the history table
    • insertHistoryRecord

      protected void insertHistoryRecord(PoolKit pk) throws DAException, DAValidateException
      Inserts a new record into the history table based on the current operation. This method handles different scenarios based on the operation type:
      • For TYPE_COMMAND_AND_HISTORY with INSERT: Creates a history record from the new values
      • For TYPE_COMMAND_AND_HISTORY with UPDATE/DELETE: Creates history records for affected rows
      • For TYPE_ONLY_HISTORY: Loads the current entity record and creates a history record if needed
      The method also checks for changes between the current entity state and the previous history record to avoid creating duplicate history entries for unchanged entities.
      Parameters:
      pk - the PoolKit
      Throws:
      DAValidateException - if validation fails during record insertion
      DAException - if a data access error occurs during record insertion
    • loadPreviousHistoryRecord

      protected HashGetter loadPreviousHistoryRecord(HashGetter hg, PoolKit pk) throws DAException, DAValidateException
      Retrieves the most recent history record for the given entity. This method looks up the previous history record for an entity by using the foreign key stored in the entity record. This allows for tracking the chain of changes made to an entity over time. If no previous history record exists for the entity, or if the foreign key is null, this method returns null.
      Parameters:
      hg - the entity record data as a HashGetter
      pk - the PoolKit
      Returns:
      the previous history record as a HashGetter, or null if no previous record exists
      Throws:
      DAValidateException - if validation fails during record retrieval
      DAException - if a data access error occurs during record retrieval
    • getHistoryField

      protected abstract String getHistoryField()
      Returns the name of the field in the entity table that references the history table.
      Returns:
      the name of the field in the entity table that references the history table
    • getFieldsToExclude

      protected String[] getFieldsToExclude()
      Returns an array of field names to exclude from history record comparisons. When comparing a current entity state with its previous history record to determine if changes have occurred, certain fields should be excluded from the comparison. This method builds a list of such fields, including:
      • Primary key of the history table
      • Foreign key to the previous history record
      • Date field recording when the history record was created
      • Operation field indicating the type of operation (INSERT/UPDATE/DELETE)
      • Standard audit fields (INSERTED, UPDATED, DELETED)
      • Custom fields specified by subclasses via getCustomFieldsToExclude()
      Returns:
      an array of field names to exclude from history record comparisons
    • getHistoryDateField

      protected abstract String getHistoryDateField()
      Returns the name of the field in the history table that stores the creation date.
      Returns:
      the name of the date field in the history table
    • getForeignHistoryField

      protected abstract String getForeignHistoryField()
      Returns the name of the field in the history table that references the previous history record.
      Returns:
      the name of the field in the history table that references the previous history record
    • getHistoryUserField

      protected String getHistoryUserField()
      Returns the name of the field in the history table that stores the user ID.
      Returns:
      the name of the user ID field in the history table, or null if user tracking is not enabled
    • getCustomFieldsToExclude

      protected ArrayList<String> getCustomFieldsToExclude()
      Hook method for specifying additional fields to exclude from history record comparisons.
      Returns:
      a list of additional field names to exclude from history record comparisons
    • translateFields

      protected HashGetter translateFields(Map<String,Object> hgValues)
      Translates entity field values to their corresponding history field values. This method applies the field mapping to convert entity data into the format required for the history table. It:
      • Maps entity field names to history field names using the translation map
      • Adds the foreign key reference to the entity record
      • Sets the operation code (INSERT/UPDATE/DELETE)
      • Sets the timestamp for the history record
      • Sets the user ID if user tracking is enabled
      Parameters:
      hgValues - the entity data to translate
      Returns:
      a new HashGetter containing the translated values for the history record
    • getOperationCodeValue

      protected Long getOperationCodeValue(Command.Type type)
      Converts a command type to its corresponding numeric operation code. This method maps the standard database operation types to numeric codes that can be stored in the history table:
      • INSERT: 1
      • UPDATE: 2
      • DELETE: 3
      Parameters:
      type - the command type to convert
      Returns:
      the numeric operation code, or null if the type is not recognized
    • getHistoryForeignField

      protected abstract String getHistoryForeignField()
      Returns the name of the field in the history table that references the entity table.
      Returns:
      the name of the field in the history table that references the entity table
    • getHistoryOperationField

      protected abstract String getHistoryOperationField()
      Returns the name of the field in the history table that stores the operation code.
      Returns:
      the name of the operation code field in the history table
    • writeHistoryRecord

      protected void writeHistoryRecord(Map<String,Object> currentValues, HashGetter previousHistoryRecord, PoolKit pk) throws DAValidateException, DAException
      Writes a new history record to the history table. This method performs the actual insertion of a history record based on the current entity values and, optionally, the previous history record. It:
      • Translates entity field values to history field values
      • Identifies changed fields if a previous history record exists
      • Adds stack trace information if enabled
      • Inserts the new history record
      • Updates the entity record to reference the new history record
      Parameters:
      currentValues - the current entity values
      previousHistoryRecord - the previous history record, or null if none exists
      pk - the PoolKit
      Throws:
      DAValidateException - if validation fails during record insertion
      DAException - if a data access error occurs during record insertion
    • getChangedFields

      protected List<String> getChangedFields(HashGetter previousHistoryRecord, HashGetter newHistoryRecord)
      Identifies fields that have changed between two history records. This method compares the previous history record with the new history record to determine which fields have changed.
      Parameters:
      previousHistoryRecord - the previous history record
      newHistoryRecord - the new history record
      Returns:
      a list of field names that have changed between the two records
    • getExcludedHistoryFieldsFromComparison

      protected List<String> getExcludedHistoryFieldsFromComparison()
      Returns a list of history table fields to exclude from change detection. This method builds a list of fields that should be ignored when comparing history records to determine if changes have occurred. These include:
      • Standard audit fields (DELETED, INSERTED, UPDATED)
      • Primary key fields of the history table
      • Foreign key to the previous history record
      • Operation code field
      • Date field
      Returns:
      a list of field names to exclude from history record comparisons
    • customizeChangedFields

      protected HashGetter customizeChangedFields(List<String> changedHistoryFields)
      Hook method for customizing history record values based on changed fields. This method is called before inserting a new history record when a previous history record exists.
      Parameters:
      changedHistoryFields - the list of field names that have changed
      Returns:
      a HashGetter containing custom values to add to the history record
    • getStackTraceField

      protected String getStackTraceField()
      Returns the name of the field in the history table that stores stack trace information. By default, this method returns null, indicating that stack trace recording is not enabled. Subclasses can override this method to enable stack trace recording.
      Returns:
      the name of the stack trace field in the history table, or null if stack trace recording is not enabled
    • traceCurrentStack

      protected boolean traceCurrentStack()
      Determines whether to record the current stack trace in the history record. By default, this method returns false, indicating that stack trace recording is not enabled. Subclasses can override this method to enable stack trace recording based on specific conditions.
      Returns:
      true if the current stack trace should be recorded, false otherwise
    • getStackTraceString

      protected String getStackTraceString()
      Generates a string representation of the current stack trace. The resulting string is truncated to a maximum of 4000 characters to ensure it fits within database field size limits.
      Returns:
      a string representation of the filtered stack trace
    • isDelete

      protected boolean isDelete()
      Checks if the current operation is a DELETE operation.
      Returns:
      true if the current operation is a DELETE, false otherwise
    • isInsert

      protected boolean isInsert()
      Checks if the current operation is an INSERT operation.
      Returns:
      true if the current operation is an INSERT, false otherwise
    • isUpdate

      protected boolean isUpdate()
      Checks if the current operation is an UPDATE operation.
      Returns:
      true if the current operation is an UPDATE, false otherwise