ReservedProperty.java
/*
** Module : ReservedProperty.java
** Abstract : Pseudo-annotations for special temp-table fields in order to handle all DMO properties in a
** unified way.
**
** Copyright (c) 2020-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 OM 20200110 Added constants and method implementations.
** 002 CA 20200922 Added getByName(), to resolve the reserved property for a 'hidden field' in 4GL.
** OM 20201001 Improved DMO manipulation performance by caching slow Property annotation access.
** OM 20201218 Fixed implementation for error and rejected attributes/hidden fields.
** CA 20210831 Track the getter method for TempRecord reserved properties.
** OM 20211020 Added _DATASOURCE_ROWID property.
** OM 20220212 Added isReservedProperty static utility method for testing reserved properties names.
** OM 20220713 Decreased constructor's visibility to private.
*/
/*
** 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.orm;
import com.goldencode.p2j.persist.*;
import com.goldencode.p2j.util.*;
import java.lang.reflect.*;
import java.util.*;
/**
* These are reserved {@code Property}/es which may take part of a SQL record of a temporary table:
* <ul>
* <li>{@code id} - the record identifier. FWD-specific;</li>
* <li>{@code _multiplex} - the temp-table multiplexer. FWD-specific, allows multiple users
* to store same-structure records in a single TEMP-TABLE;</li>
* <li>{@code parent__id} - the foreign-key for composite table to its parent;</li>
* <li>{@code list__index} - extent index for composite table;</li>
*
* <li>{@code _errorFlag}, {@code _originRowid}, {@code _dataSourceRowid}, {@code _errorString},
* {@code _peerRowid}, and {@code _rowState} - the before-table specific hidden fields.</li>
* </ul>
*/
public class ReservedProperty
extends Property
{
/** The id of the {@code parent__id} reserved property. */
public static final int ID_PARENT__ID = -2;
/** The id of the {@code list__index} reserved property. */
public static final int ID_LIST__INDEX = -3;
/** The id of the {@code _row_state} reserved property. */
public static final int ID_ROW_STATE = -4;
/** The id of the {@code _peer_rowid} reserved property. */
public static final int ID_PEER_ROWID = -5;
/** The id of the {@code _error_string} reserved property. */
public static final int ID_ERROR_STRING = -6;
/** The id of the {@code _datasource-rowid} reserved property. */
public static final int ID_DATASOURCE_ROWID = -7;
/** The id of the {@code _origin_rowid} reserved property. */
public static final int ID_ORIGIN_ROWID = -8;
/** The id of the {@code _error_flag} reserved property. */
public static final int ID_ERROR_FLAG = -9;
/** The id of the {@code _multiplex} reserved property. */
public static final int ID_MULTIPLEX = -10;
/** The id of the {@code primary_key} reserved property. */
public static final int ID_PRIMARY_KEY = -11;
/** The {@code id} reserved (by FWD) property. */
public static final ReservedProperty ID = new ReservedProperty(
ID_PRIMARY_KEY, Session.PK, null, Session.PK, true, Long.class, false);
/** The {@code _multiplex} reserved (by FWD) property. */
public static final ReservedProperty _MULTIPLEX = new ReservedProperty(
ID_MULTIPLEX, TemporaryBuffer.MULTIPLEX_FIELD_NAME, null, TemporaryBuffer.MULTIPLEX_FIELD_NAME, true, Integer.class, false);
/** The {@code __error-flag__} reserved (by P4GL) property. */
public static final ReservedProperty _ERRORFLAG = new ReservedProperty(
ID_ERROR_FLAG, TempRecord._ERROR_FLAG, Buffer.__ERROR_FLAG__, TempRecord._ERROR_FLAG, false, integer.class, true);
/** The {@code __origin-rowid__} reserved (by P4GL) property. */
public static final ReservedProperty _ORIGINROWID = new ReservedProperty(
ID_ORIGIN_ROWID, TempRecord._ORIGIN_ROWID, Buffer.__ORIGIN_ROWID__, TempRecord._ORIGIN_ROWID, false, rowid.class, true);
/** The {@code __datasource-rowid__} reserved (by P4GL) property. */
public static final ReservedProperty _DATASOURCEROWID = new ReservedProperty(
ID_DATASOURCE_ROWID, TempRecord._DATASOURCE_ROWID, Buffer.__DATA_SOURCE_ROWID__, TempRecord._DATASOURCE_ROWID, false, rowid.class, true);
/** The {@code _errorString} reserved (by P4GL) property. */
public static final ReservedProperty _ERRORSTRING = new ReservedProperty(
ID_ERROR_STRING, TempRecord._ERROR_STRING, Buffer.__ERROR_STRING__, TempRecord._ERROR_STRING, false, character.class, true);
/** The {@code __after-rowid__} reserved (by P4GL) property. */
public static final ReservedProperty _PEERROWID = new ReservedProperty(
ID_PEER_ROWID, TempRecord._PEER_ROWID, Buffer.__AFTER_ROWID__, TempRecord._PEER_ROWID, false, rowid.class, true);
/** The {@code __row-state__} reserved (by P4GL) property. */
public static final ReservedProperty _ROWSTATE = new ReservedProperty(
ID_ROW_STATE, TempRecord._ROW_STATE, Buffer.__ROW_STATE__, TempRecord._ROW_STATE, false, integer.class, true);
/** The {@code list__index} reserved (by FWD) property. */
public static final ReservedProperty LIST__INDEX = new ReservedProperty(
ID_LIST__INDEX, "list__index", "index", "list__index", true, Integer.class, false); // or integer ?
/** The {@code list__index} reserved (by FWD) property. */
public static final ReservedProperty PARENT__ID = new ReservedProperty(
ID_PARENT__ID, "parent__id", "fk_parent", "parent__id", true, Long.class, false); // or int64 ?
/** The map of reserved properties which exist in 4GL, but are hidden. */
private static final Map<String, ReservedProperty> HIDDEN_PROPERTIES = new HashMap<>();
static
{
HIDDEN_PROPERTIES.put(_ERRORFLAG.legacy, _ERRORFLAG);
HIDDEN_PROPERTIES.put(_ORIGINROWID.legacy, _ORIGINROWID);
HIDDEN_PROPERTIES.put(_DATASOURCEROWID.legacy, _DATASOURCEROWID);
HIDDEN_PROPERTIES.put(_ERRORSTRING.legacy, _ERRORSTRING);
HIDDEN_PROPERTIES.put(_PEERROWID.legacy, _PEERROWID);
HIDDEN_PROPERTIES.put(_ROWSTATE.legacy, _ROWSTATE);
}
/**
* Creates a new {@code ReservedProperty} object
*
* @param id
* The id of this field in the sequence of the fields of the buffer.
* @param name
* The name of the DMO property.
* @param legacy
* The name of the legacy field associated with the DMO property.
* @param column
* The name of the column in the SQL database, associated with the DMO property.
* @param mandatory
* Flag for not-null fields.
* @param type
* property type
* @param initialNull
* The property has {@code null} as default value.
*/
private ReservedProperty(int id,
String name,
String legacy,
String column,
boolean mandatory,
Class<?> type,
boolean initialNull)
{
super(id, name, legacy, column, mandatory, type, initialNull, getMethod(id));
}
/**
* Get the specified hidden property.
*
* @param name
* The name of the reserved property.
*
* @return The {@link ReservedProperty} instance for it.
*/
public static ReservedProperty getByName(String name)
{
return HIDDEN_PROPERTIES.get(name.toLowerCase());
}
/**
* Check whether the {@code name} argument is the name of a reserved property.
*
* @param name
* The name to test
*
* @return {@code true} if {@code name} is the name of a reserved property.
*/
public static boolean isReservedProperty(String name)
{
if (!name.startsWith("__"))
{
// the reserved property names always start with double underscore. If not, quick out.
return false;
}
switch (name)
{
case Buffer.__AFTER_ROWID__:
case Buffer.__DATA_SOURCE_ROWID__:
case Buffer.__ERROR_FLAG__:
case Buffer.__ERROR_STRING__:
case Buffer.__ORIGIN_ROWID__:
case Buffer.__ROW_STATE__:
return true;
}
return false;
}
/**
* Get the method for the specified reserved property.
*
* @param id
* The reserved property ID.
*
* @return The method, or <code>null</code> if this is not one of the {@link TempRecord} methods.
*
* @throws RuntimeException
* If the method can't be found, as this is a FWD error.
*/
private static Method getMethod(int id)
{
try
{
switch (id)
{
case ID_ROW_STATE:
return TempRecord.class.getDeclaredMethod("_rowState");
case ID_PEER_ROWID:
return TempRecord.class.getDeclaredMethod("_peerRowid");
case ID_ERROR_STRING:
return TempRecord.class.getDeclaredMethod("_errorString");
case ID_ORIGIN_ROWID:
return TempRecord.class.getDeclaredMethod("_originRowid");
case ID_DATASOURCE_ROWID:
return TempRecord.class.getDeclaredMethod("_datasourceRowid");
case ID_ERROR_FLAG:
return TempRecord.class.getDeclaredMethod("_errorFlags");
default:
return null;
}
}
catch (NoSuchMethodException exc)
{
throw new RuntimeException(exc);
}
}
}