DirtyInfo.java
/*
** Module : DirtyInfo.java
** Abstract : Encapsulates information found in a dirty database check
**
** Copyright (c) 2004-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- --------------------------Description-------------------------------
** 001 ECF 20080516 @38628 Created initial version. Encapsulates information
** found in a dirty database check.
** 002 ECF 20080611 @38715 Replaced boolean state variables with a bitfield.
** Added public constants.
** 003 ECF 20090603 @42561 Added support for Progress isolation leak quirk.
** Added new methods and instance variable.
** 004 ECF 20090609 @42641 Fixed isFullyPublished() method.
** 005 ECF 20140829 Added isLocal() and setLocal() methods.
** 006 ECF 20160820 Made constructor and setDeleted method public.
** 007 OM 20200906 New ORM implementation.
** 008 TJD 20240123 Java 17 compatibility updates
** 009 TJD 20231106 Implement methods to check if dirty DMOs are leaked snaphots
** TJD 20240619 Implement toString() for debugging purposes
*/
/*
** 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.persist.dirty;
import com.goldencode.p2j.persist.Record;
/**
* Encapsulates information found in a dirty database check. The information
* reported is the {@link #getDirtyDMO() DMO found} by the check, if any, and
* whether that record was {@link #isInserted() newly inserted} (as opposed to
* representing an update to an pre-existing record). If no DMO was found,
* this object will indicate whether a candidate DMO found in the primary
* database was {@link #isDeleted() deleted} in an uncommitted transaction.
* It will also indicate whether a candidate DMO found in the primary database
* has been {@link #isModified() modified} in an uncommitted transaction.
*/
public final class DirtyInfo
{
@Override
public String toString() {
return "DirtyInfo [dirtyDMO=" + dirtyDMO + ", comparableDMO=" + comparableDMO + ", status=" + status + "]";
}
/** Status flag indicating no change */
public static final int NONE = 0;
/** Status flag indicating an insert and/or update */
public static final int CHANGE = 0x01;
/** Status flag indicating inserted record specifically */
public static final int INSERT = 0x02;
/** Status flag indicating delete */
public static final int DELETE = 0x04;
/** Status flag indicating found DMO was added to dirty tracking by the local context */
public static final int LOCAL = 0x08;
/** Status flag indicating leaked record specifically */
public static final int LEAKED = 0x10;
/** DMO found in dirty database during dirty check (or snapshot) */
private Record dirtyDMO = null;
/** Actual DMO found in dirty database during dirty check */
private Record comparableDMO = null;
/** Bitfield of status flags */
private int status = NONE;
/**
* Default constructor.
*/
public DirtyInfo()
{
}
/**
* Indicate whether the candidate DMO found in the primary database has
* been deleted in an uncommitted transaction.
*
* @return <code>true</code> if candidate DMO was deleted, else
* <code>false</code>.
*/
public boolean isDeleted()
{
return ((status & DELETE) != 0);
}
/**
* Indicate whether a {@link #getDirtyDMO() dirty DMO} found during a dirty
* database check has been newly inserted in an uncommitted transaction.
*
* @return <code>true</code> if dirty DMO is newly inserted, else
* <code>false</code>.
*/
public boolean isInserted()
{
return ((status & INSERT) != 0);
}
/**
* Indicate whether the candidate DMO found in the primary database has
* been modified in an uncommitted transaction.
*
* @return <code>true</code> if candidate DMO was modified, else
* <code>false</code>.
*/
public boolean isModified()
{
return ((status & CHANGE) != 0);
}
/**
* Indicate whether the record found in the dirty database was added to dirty share tracking
* by the current/local context.
*
* @return <code>true</code> if the record in this object is local to the current context,
* else <code>false</code>.
*/
public boolean isLocal()
{
return ((status & LOCAL) != 0);
}
/**
* Get the DMO, if any, found in the dirty database during a dirty check.
* This will be either the actual DMO as stored in the database (in the
* event of a change to an existing record in the primary database), or it
* will be a copy of a newly created DMO which has not yet been committed
* to the primary database. In the latter case the copy will represent a
* snapshot of the record at the moment it was first shared with the dirty
* share manager, regardless of whether its properties have changed with
* subsequent updates.
*
* @return Dirty DMO (or snapshot), or <code>null</code> if no record was
* found.
*
* @see #setDirtyDMOs(Record, Record)
*/
public Record getDirtyDMO()
{
return dirtyDMO;
}
/**
* Get the DMO, if any, found in the dirty database during a dirty check.
* This will be the actual DMO as stored in the dirty database, and it will
* include any changes which have been made subsequent to its initial
* insertion.
* <p>
* This version of the DMO should not be exposed to business logic. It is
* provided for persistence runtime purposes, to allow the correct record
* to be found during dynamic navigation.
*
* @return Dirty DMO as stored in the dirty database, or <code>null</code>
* if no record was found. In cases where the comparable DMO is
* the same as the dirty DMO, the dirty DMO is returned.
*
* @see #getDirtyDMO()
* @see #setDirtyDMOs(Record, Record)
*/
public Record getComparableDMO()
{
return (comparableDMO != null ? comparableDMO : dirtyDMO);
}
/**
* Indicate whether the dirty DMO (assumed to be non-<code>null</code>)
* contains all changes known to the dirty database, as opposed to being a
* potentially outdated snapshot taken at the point the record was first
* stored in the dirty database.
*
* @return <code>true</code> if all uncommitted changes are included in
* the dirty DMO, else <code>false</code>.
*/
public boolean isFullyPublished()
{
return (comparableDMO == null || dirtyDMO == comparableDMO);
}
/**
* Record the fact that the candidate DMO found in the primary database has
* been deleted in an uncommitted transaction.
*/
public void setDeleted()
{
status |= DELETE;
}
/**
* Record the fact that the dirty DMO stored in this object is newly
* inserted in an uncommitted transaction.
*/
void setInserted()
{
status |= INSERT;
}
/**
* Record the fact that the candidate DMO found in the primary database has
* been modified in an uncommitted transaction.
*/
void setModified()
{
status |= CHANGE;
}
/**
* Record the fact that the record contained in this object was added to dirty share tracking
* by the current/local context.
*/
void setLocal()
{
status |= LOCAL;
}
/**
* Store DMOs found in the dirty share manager during a dirty check.
*
* @param dirtyDMO
* Copy of the dirty record which is suitable for use by business logic. This use
* should be read-only, unless {@link #isLocal()} returns <code>true</code>.
* @param comparableDMO
* Dirty record which is not suitable for use by business logic, but is intended for
* internal runtime use only.
*
* @see #getDirtyDMO()
*/
void setDirtyDMOs(Record dirtyDMO, Record comparableDMO)
{
this.dirtyDMO = dirtyDMO;
if (dirtyDMO != comparableDMO)
{
this.comparableDMO = comparableDMO;
}
else
{
this.comparableDMO = null;
}
}
/**
* Record the fact that the dirty DMO stored in this object is
* leaked from an uncommitted transaction
*/
public void setLeaked()
{
status |= LEAKED;
}
/**
* Indicate whether a {@link #getDirtyDMO() dirty DMO} found during a dirty
* database check has been leaked from other sessions an uncommitted transaction.
*
* @return <code>true</code> if dirty DMO is leaked snapshot, else
* <code>false</code>.
*/
public boolean isLeaked()
{
return ((status & LEAKED) != 0);
}
}