PrometheusControlData.java
/*
* Prometheus: Application Framework
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.prometheus.data;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet.PrometheusCryptographyDataType;
import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
/**
* ControlData definition and list. The Control Data represents the data version of the entire data
* set, allowing for migration code to be written to map between different versions. It also holds a
* pointer to the active ControlKey.
* <p>
* When code is loaded from a database, it is possible that more than one control key will be
* active. This will occur if a failure occurs when we are writing the results of a renew security
* request to the database and we have changed some records, but not all to the required controlKey.
* This record points to the active controlKey. All records that are not encrypted by the correct
* controlKey should be re-encrypted and written to the database.
*
* @author Tony Washer
*/
public class PrometheusControlData
extends PrometheusDataItem {
/**
* Object name.
*/
public static final String OBJECT_NAME = PrometheusCryptographyDataType.CONTROLDATA.getItemName();
/**
* List name.
*/
public static final String LIST_NAME = PrometheusCryptographyDataType.CONTROLDATA.getListName();
/**
* Report fields.
*/
private static final MetisFieldVersionedSet<PrometheusControlData> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(PrometheusControlData.class);
/*
* FieldIds.
*/
static {
FIELD_DEFS.declareIntegerField(PrometheusDataResource.CONTROLDATA_VERSION);
FIELD_DEFS.declareLinkField(PrometheusCryptographyDataType.CONTROLKEY);
}
/**
* Error message for already exists.
*/
public static final String ERROR_CTLEXISTS = PrometheusDataResource.CONTROLDATA_ERROR_EXISTS.getValue();
/**
* Copy Constructor.
*
* @param pList the associated list
* @param pSource The source
*/
protected PrometheusControlData(final PrometheusControlDataList pList,
final PrometheusControlData pSource) {
/* Set standard values */
super(pList, pSource);
}
/**
* Values constructor.
*
* @param pList the List to add to
* @param pValues the values constructor
* @throws OceanusException on error
*/
private PrometheusControlData(final PrometheusControlDataList pList,
final PrometheusDataValues pValues) throws OceanusException {
/* Initialise the item */
super(pList, pValues);
/* Store the Version */
Object myValue = pValues.getValue(PrometheusDataResource.CONTROLDATA_VERSION);
if (myValue instanceof Integer i) {
setValueDataVersion(i);
} else if (myValue instanceof String s) {
setValueDataVersion(Integer.valueOf(s));
}
/* Store the ControlKey */
myValue = pValues.getValue(PrometheusCryptographyDataType.CONTROLKEY);
if (myValue instanceof Integer myInt) {
/* Store value */
setValueControlKey(myInt);
/* Resolve the ControlKey */
final PrometheusDataSet myData = getDataSet();
resolveDataLink(PrometheusCryptographyDataType.CONTROLKEY, myData.getControlKeys());
}
}
@Override
public MetisFieldSetDef getDataFieldSet() {
return FIELD_DEFS;
}
/**
* Get the data version.
*
* @return data version
*/
public Integer getDataVersion() {
return getValues().getValue(PrometheusDataResource.CONTROLDATA_VERSION, Integer.class);
}
/**
* Get the control key.
*
* @return the control key
*/
public PrometheusControlKey getControlKey() {
return getValues().getValue(PrometheusCryptographyDataType.CONTROLKEY, PrometheusControlKey.class);
}
/**
* Get the ControlKeyId for this item.
*
* @return the ControlKeyId
*/
public Integer getControlKeyId() {
final PrometheusControlKey myKey = getControlKey();
return (myKey == null)
? null
: myKey.getIndexedId();
}
/**
* Set the data version value.
*
* @param pValue the value
* @throws OceanusException on error
*/
private void setValueDataVersion(final Integer pValue) throws OceanusException {
getValues().setValue(PrometheusDataResource.CONTROLDATA_VERSION, pValue);
}
/**
* Set the control key value.
*
* @param pValue the value
* @throws OceanusException on error
*/
private void setValueControlKey(final PrometheusControlKey pValue) throws OceanusException {
getValues().setValue(PrometheusCryptographyDataType.CONTROLKEY, pValue);
}
/**
* Set the control key value as Id.
*
* @param pId the value
* @throws OceanusException on error
*/
private void setValueControlKey(final Integer pId) throws OceanusException {
getValues().setValue(PrometheusCryptographyDataType.CONTROLKEY, pId);
}
@Override
public PrometheusControlData getBase() {
return (PrometheusControlData) super.getBase();
}
@Override
public PrometheusControlDataList getList() {
return (PrometheusControlDataList) super.getList();
}
@Override
public int compareValues(final PrometheusDataItem pThat) {
/* Check the versions */
final PrometheusControlData myThat = (PrometheusControlData) pThat;
return getDataVersion() - myThat.getDataVersion();
}
@Override
public void resolveDataSetLinks() throws OceanusException {
/* Resolve the ControlKey */
final PrometheusDataSet myData = getDataSet();
resolveDataLink(PrometheusCryptographyDataType.CONTROLKEY, myData.getControlKeys());
}
/**
* Set a new ControlKey.
*
* @param pControl the new control key
* @throws OceanusException on error
*/
protected void setControlKey(final PrometheusControlKey pControl) throws OceanusException {
/* If we do not have a control Key */
if (getControlKey() == null) {
/* Store the control details and return */
setValueControlKey(pControl);
return;
}
/* Store the current detail into history */
pushHistory();
/* Store the control details */
setValueControlKey(pControl);
/* Check for changes */
checkForHistory();
}
/**
* Control Data List.
*/
public static class PrometheusControlDataList
extends PrometheusDataList<PrometheusControlData> {
/**
* Report fields.
*/
private static final MetisFieldSet<PrometheusControlDataList> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusControlDataList.class);
/**
* Construct an empty CORE Control Data list.
*
* @param pData the DataSet for the list
*/
protected PrometheusControlDataList(final PrometheusDataSet pData) {
this(pData, PrometheusListStyle.CORE);
}
/**
* Construct an empty generic ControlData list.
*
* @param pData the DataSet for the list
* @param pStyle the style of the list
*/
protected PrometheusControlDataList(final PrometheusDataSet pData,
final PrometheusListStyle pStyle) {
super(PrometheusControlData.class, pData, PrometheusCryptographyDataType.CONTROLDATA, pStyle);
}
/**
* Constructor for a cloned List.
*
* @param pSource the source List
*/
private PrometheusControlDataList(final PrometheusControlDataList pSource) {
super(pSource);
}
@Override
public MetisFieldSet<PrometheusControlDataList> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String listName() {
return LIST_NAME;
}
@Override
public MetisFieldSet<PrometheusControlData> getItemFields() {
return PrometheusControlData.FIELD_DEFS;
}
@Override
public boolean includeDataXML() {
return false;
}
/**
* Get the single element.
*
* @return the control data
*/
public PrometheusControlData getControl() {
return isEmpty()
? null
: get(0);
}
@Override
protected PrometheusControlDataList getEmptyList(final PrometheusListStyle pStyle) {
final PrometheusControlDataList myList = new PrometheusControlDataList(this);
myList.setStyle(pStyle);
return myList;
}
@Override
public PrometheusControlDataList deriveList(final PrometheusListStyle pStyle) throws OceanusException {
return (PrometheusControlDataList) super.deriveList(pStyle);
}
@Override
public PrometheusControlDataList deriveDifferences(final PrometheusDataSet pDataSet,
final PrometheusDataList<?> pOld) {
return (PrometheusControlDataList) super.deriveDifferences(pDataSet, pOld);
}
@Override
public PrometheusControlData addCopyItem(final PrometheusDataItem pItem) {
/* Can only clone a ControlData */
if (!(pItem instanceof PrometheusControlData)) {
return null;
}
/* Clone the control data */
final PrometheusControlData myControl = new PrometheusControlData(this, (PrometheusControlData) pItem);
add(myControl);
return myControl;
}
@Override
public PrometheusControlData addNewItem() {
throw new UnsupportedOperationException();
}
/**
* Add new ControlData item for new security.
*
* @param pVersion the version
* @throws OceanusException on error
*/
public void addNewControl(final Integer pVersion) throws OceanusException {
/* Create the ControlData */
final PrometheusDataValues myValues = new PrometheusDataValues(OBJECT_NAME);
myValues.addValue(PrometheusDataResource.CONTROLDATA_VERSION, pVersion);
/* Add the item */
addValuesItem(myValues);
}
@Override
public PrometheusControlData addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
/* Create the controlData */
final PrometheusControlData myControl = new PrometheusControlData(this, pValues);
/* Check that this controlId has not been previously added */
if (!isIdUnique(myControl.getIndexedId())) {
myControl.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
throw new PrometheusDataException(myControl, ERROR_VALIDATION);
}
/* Add to the list */
add(myControl);
/* Return it */
return myControl;
}
@Override
public void postProcessOnLoad() throws OceanusException {
/* Just sort the list */
reSort();
}
@Override
protected PrometheusDataMapItem allocateDataMap() {
/* Unused */
throw new UnsupportedOperationException();
}
}
}