TempRecord.java
/*
** Module : TempRecord.java
** Abstract : The abstract base class for all business data model object classes which represent temp-tables.
**
** Copyright (c) 2019-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 ECF 20191001 Created initial version with basic data and accessors.
** OM 20200110 Added constants and method implementations.
** CA 20200714 Refactored to keep the reserved properties in the record's data, to be persisted in the
** table.
** 002 OM 20201218 Fixed implementation for error and rejected attributes/hidden fields.
** OM 20211020 Added _DATASOURCE_ROWID property.
** CA 20220110 Refactored the temp-table's row-meta state to use constants for the indexes in the array
** used for serialization.
** 003 OM 20230228 The updateObjectRefCount() must use the same key as the delete (getAnnotatedInterface()).
** 004 CA 20240918 Removed default methods from interfaces and moved them as concrete implementations, as
** default methods cause the Java metaspace to spike one order of magnitude.
** 005 AS 20241009 Refactored activeOffset into activeOffsets(Bitset).
*/
/*
** 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;
import com.goldencode.p2j.persist.orm.*;
import com.goldencode.p2j.util.object;
import java.util.BitSet;
/**
* The abstract base class for all business data model object classes which represent temp-tables.
* Subclasses are intended to be generated at runtime, rather than coded by hand.
*/
public abstract class TempRecord
extends Record
implements TempTableRecord
{
/** The property/column name of "__error-flag__" field. */
public static final String _ERROR_FLAG = "_errorFlag";
/** The property/column name of "__origin-rowid__" field. */
public static final String _ORIGIN_ROWID = "_originRowid";
/** The property/column name of data-source field. */
public static final String _DATASOURCE_ROWID = "_datasourceRowid";
/** The property/column name of "__error-string__" field. */
public static final String _ERROR_STRING = "_errorString";
/** The property/column name of "__after-rowid__" field. */
public static final String _PEER_ROWID = "_peerRowid";
/** The property/column name of "__row-state__" field. */
public static final String _ROW_STATE = "_rowState";
/**
* The index in the {@link BaseRecord#data} and {@link TempRecord#toArray()} for the {@link #_ERROR_FLAG}
* field.
*/
public static final int _ERROR_FLAG_DATA_INDEX = 0;
/**
* The index in the {@link BaseRecord#data} and {@link TempRecord#toArray()} for the {@link #_ORIGIN_ROWID}
* field.
*/
public static final int _ORIGIN_ROWID_DATA_INDEX = _ERROR_FLAG_DATA_INDEX + 1;
/**
* The index in the {@link BaseRecord#data} and {@link TempRecord#toArray()} for the
* {@link #_DATASOURCE_ROWID} field.
*/
public static final int _DATASOURCE_ROWID_INDEX = _ORIGIN_ROWID_DATA_INDEX + 1;
/**
* The index in the {@link BaseRecord#data} and {@link TempRecord#toArray()} for the {@link #_ERROR_STRING}
* field.
*/
public static final int _ERROR_STRING_DATA_INDEX = _DATASOURCE_ROWID_INDEX + 1;
/**
* The index in the {@link BaseRecord#data} and {@link TempRecord#toArray()} for the {@link #_PEER_ROWID}
* field.
*/
public static final int _PEER_ROWID_DATA_INDEX = _ERROR_STRING_DATA_INDEX + 1;
/**
* The index in the {@link BaseRecord#data} and {@link TempRecord#toArray()} for the {@link #_ROW_STATE}
* field.
*/
public static final int _ROW_STATE_DATA_INDEX = _PEER_ROWID_DATA_INDEX + 1;
/** The index in the {@link TempRecord#toArray()} for the {@link BaseRecord#id} field; always last. */
public static final int _PK_DATA_INDEX = _ROW_STATE_DATA_INDEX + 1;
/**
* The number of meta properties, used when transferring meta properties via {@link TempRecord#toArray()}.
*/
public static final int _META_PROPERTIES_LENGTH = _PK_DATA_INDEX + 1;
/**
* Multiplex ID. It must be {@code protected} or else an {@code IllegalAccessError} is thrown
* when Impl constructor is called.
* TODO: this does not seem normal, the constructor does not access the field from super class,
* it merely calls its super, see {@code DmoClass.createConstructor} :(.
*/
protected Integer _multiplex = null;
/** The default constructor is protected. */
protected TempRecord()
{
super();
}
/**
* Get an array with this record's meta information.
*
* @param ttr
* The temp-table record.
*
* @return See above.
*/
public static Object[] asArray(TempTableRecord ttr)
{
// this order is hard-linked with the constants defined in TempRecord.
Object[] res = new Object[TempRecord._META_PROPERTIES_LENGTH];
res[TempRecord._PK_DATA_INDEX] = ttr.primaryKey();
res[TempRecord._ROW_STATE_DATA_INDEX] = ttr._rowState();
res[TempRecord._PEER_ROWID_DATA_INDEX] = ttr._peerRowid();
res[TempRecord._ORIGIN_ROWID_DATA_INDEX] = ttr._originRowid();
res[TempRecord._DATASOURCE_ROWID_INDEX] = ttr._datasourceRowid();
res[TempRecord._ERROR_FLAG_DATA_INDEX] = ttr._errorFlags();
res[TempRecord._ERROR_STRING_DATA_INDEX] = ttr._errorString();
return res;
}
/**
* Gets the rowid (as {@code Long} value) of the peer record. Exclusively, for a BEFORE-TABLE
* record this is the {@code after-rowid} and {@code before-rowid} for AFTER-TABLE record.
*
* @return The rowid value of the peer record or {@code null} if there is none.
*
* @see #_PEER_ROWID
*/
@Override
public final Long _peerRowid()
{
return (Long) data[_PEER_ROWID_DATA_INDEX];
}
/**
* Sets the rowid (as {@code Long} value) of the peer record. Exclusively, for a BEFORE-TABLE
* record this is the {@code after-rowid} and {@code before-rowid} for AFTER-TABLE record.
*
* @param rowid
* The new long rowid value of the peer record or {@code null}.
*
* @see #_PEER_ROWID
*/
@Override
public final void _peerRowid(Long rowid)
{
BitSet savedActiveOffset = (BitSet) this.activeOffsets.clone();
try
{
setDatum(_PEER_ROWID_DATA_INDEX, rowid);
}
finally
{
// restore the activeOffset
this.activeOffsets = savedActiveOffset;
}
}
/**
* Gets the current value of the {@code ROW-STATE} property for this record. Valid values
* are defined as constants in {@link Buffer} interface. Additionally, {@code null} value is
* returned if property is not available.
*
* @return The current value of the {@code ROW-STATUS} property for this record as
* explained above.
*
* @see #_ROW_STATE
*/
@Override
public final Integer _rowState()
{
return (Integer) data[_ROW_STATE_DATA_INDEX];
}
/**
* Sets the value of the {@code ROW-STATUS} property for this record. Valid values are defined
* as constants in {@link Buffer} interface. Additionally {@code null} value is allowed if
* property is not available.
*
* @param state
* The new value of the {@code ROW-STATE} property for this record as explained above.
*
* @see #_ROW_STATE
*/
@Override
public final void _rowState(Integer state)
{
BitSet savedActiveOffset = (BitSet) this.activeOffsets.clone();
try
{
setDatum(_ROW_STATE_DATA_INDEX, state);
}
finally
{
// restore the activeOffset
this.activeOffsets = savedActiveOffset;
}
}
/**
* Gets the current value of the {@code ORIGIN-ROWID} property for this record. This property
* of a record in a buffer of a CHANGE DATASET points to original record of the change.
* Additionally, {@code null} value is returned if property is not available.
*
* @return The current value of the {@code ORIGIN-ROWID} property for this record as
* explained above.
*
* @see #_ORIGIN_ROWID
*/
@Override
public final Long _originRowid()
{
return (Long) data[_ORIGIN_ROWID_DATA_INDEX];
}
/**
* Sets the current value of the {@code ORIGIN-ROWID} property for this record. This property
* of a record in a buffer of a CHANGE DATASET points to original record of the change.
* Additionally, {@code null} value is returned if property is not available.
*
* @param rowid
* The new value of the {@code ORIGIN-ROWID} property for this record as explained above.
*
* @see #_ORIGIN_ROWID
*/
@Override
public final void _originRowid(Long rowid)
{
BitSet savedActiveOffset = (BitSet) this.activeOffsets.clone();
try
{
setDatum(_ORIGIN_ROWID_DATA_INDEX, rowid);
}
finally
{
// restore the activeOffset
this.activeOffsets = savedActiveOffset;
}
}
/**
* Gets the current value of the {@code DATA_SOURCE_ROWID} property for this record. This property of a
* record in a buffer of a CHANGE DATASET points to original record of the change. Additionally,
* {@code null} value is returned if property is not available.
*
* @return The current value of the {@code DATA_SOURCE_ROWID} property for this record as explained above.
*
* @see #_DATASOURCE_ROWID
*/
@Override
public final Long _datasourceRowid()
{
return (Long) data[_DATASOURCE_ROWID_INDEX];
}
/**
* Sets the current value of the {@code DATA_SOURCE_ROWID} property for this record. This property of a
* record in a buffer of a CHANGE DATASET points to original record of the change. Additionally,
* {@code null} value is returned if property is not available.
*
* @param rowid
* The new value of the {@code DATA_SOURCE_ROWID} property for this record as explained above.
*
* @see #_DATASOURCE_ROWID
*/
@Override
public final void _datasourceRowid(Long rowid)
{
BitSet savedActiveOffset = (BitSet) this.activeOffsets.clone();
try
{
setDatum(_DATASOURCE_ROWID_INDEX, rowid);
}
finally
{
// restore the activeOffset
this.activeOffsets = savedActiveOffset;
}
}
/**
* Gets the current value of the {@code __error-flag__} for this record.
*
* @return The current value of the {@code __error-flag__} for this record.
*
* @see #_ERROR_FLAG
*/
@Override
public final Integer _errorFlags()
{
return (Integer) data[_ERROR_FLAG_DATA_INDEX];
}
/**
* Sets the current value of the {@code __error-flag__} for this record.
*
* @param flag
* The current value of the {@code __error-flag__} for this record.
*
* @see #_ERROR_FLAG
*/
@Override
public final void _errorFlags(Integer flag)
{
BitSet savedActiveOffset = (BitSet) this.activeOffsets.clone();
try
{
setDatum(_ERROR_FLAG_DATA_INDEX, flag);
}
finally
{
// restore the activeOffset
this.activeOffsets = savedActiveOffset;
}
}
/**
* Gets the current value of the {@code __error-string__} for this record.
*
* @return The current value of the {@code __error-string__} for this record.
*
* @see #_ERROR_STRING
*/
@Override
public final String _errorString()
{
return (String) data[_ERROR_STRING_DATA_INDEX];
}
/**
* Sets the current value of the {@code __error-string__} for this record.
*
* @param error
* The current value of the {@code __error-string__} for this record.
*
* @see #_ERROR_STRING
*/
@Override
public final void _errorString(String error)
{
BitSet savedActiveOffset = (BitSet) this.activeOffsets.clone();
try
{
setDatum(_ERROR_STRING_DATA_INDEX, error);
}
finally
{
// restore the activeOffset
this.activeOffsets = savedActiveOffset;
}
}
/**
* Creates a snapshot copy of the current record. Since this is a {@code TempRecord}, the
* returned object is also a {@code TempRecord}.
*
* @return a new {@code TempRecord} instance of this record with all fields set to values of
* the respective fields in this {@code TempRecord} at the moment of the call.
*/
@Override
public TempRecord snapshot()
{
return (TempRecord) super.snapshot();
}
/**
* Makes this a copy of a source {@code BaseRecord} object. For _temp databases, the
* {@code _multiplex} identifier, internal {@code data} and the {@code id} of the
* {@code BaseRecord} are copied.
* <p>
* TODO: check whether {@code _rowState}, {@code _peerRowid}, {@code _originRowid},
* {@code _errorFlag} and {@code _errorString} should also be copied.
*
* @param from
* The source to copy data from.
*/
@Override
public void copy(BaseRecord from)
{
super.copy(from);
this._multiplex = ((TempRecord) from)._multiplex;
}
/**
* Obtain the {@code _multiplex} identifier of this record.
*
* @return the {@code _multiplex} identifier of this record.
*/
public final Integer _multiplex()
{
return _multiplex;
}
/**
* Sets the {@code _multiplex} identifier for this record.
*
* @param newMultiplex
* The new {@code _multiplex} identifier of this record.
*/
public final void _multiplex(int newMultiplex)
{
_multiplex = newMultiplex;
}
/**
* Return a string representation of this object, primarily for debug purposes.
*
* @return String representation of this object.
*/
@Override
public String toString()
{
return super.toString() + System.lineSeparator() + "multiplex: " + _multiplex;
}
/**
* Get an array with this record's meta information.
*
* @return See above.
*/
@Override
public Object[] toArray()
{
return asArray(this);
}
/**
* Update the object reference count. It will decrement the old value reference and increment the new
* value reference.
*
* @param oldVal
* The old value.
* @param newVal
* The new value.
*/
@Override
protected final void updateObjectRefCount(object<?> oldVal, object<?> newVal)
{
Class<?> implIFace = _recordMeta().getDmoMeta().getAnnotatedInterface();
TemporaryBuffer.updateObjectRefCount(implIFace, oldVal, newVal);
}
}