IndexDefinition.java
/*
** Module : IndexDefinition.java
** Abstract : A container for a table index metadata.
**
** Copyright (c) 2022-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 IAS 20221104 Created initial version.
** 002 OM 20230517 Fixed deserialization. Improved javadocs and local optimization.
*/
/*
** 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 static com.goldencode.util.NativeTypeSerializer.*;
import java.io.*;
import java.util.*;
import java.util.stream.*;
import com.goldencode.p2j.persist.TableMapper.*;
import com.goldencode.p2j.util.*;
/**
* Container for a table index metadata. Used to send the metadata of a
* DMO to a remote side, when remote appserver calls are involved.
*/
public class IndexDefinition
implements Externalizable
{
/** Flag for default (none) index attribute. */
private static final int IA_NONE = 0;
/** Flag for 'primary' / 'effective primary' index attribute. */
private static final int IA_PRIMARY = 1;
/** Flag for 'unique' index attribute. */
private static final int IA_UNIQUE = 2;
/** Flag for 'word' index attribute. */
private static final int IA_WORD = 4;
/** The legacy name of this index. */
private String legacyName;
/**
* The collection of index attribute. It is a OR-ed combination of the following flags:
* <ul>
* <li>{@code IA_PRIMARY} - determines if the index is a primary index: the one with the "primary"
* annotation or, if there is no such one, the first in the definition order;</li>
* <li>{@code IA_UNIQUE} - determines if the index is a unique index;</li>
* <li>{@code IA_WORD} - determines if the index is a word-index index.</li>
* </ul>
* The collection is serialized as a single byte because there are only 3 attributes. When/if we include
* additional attributes and the 8 bits of the byte are not enough, we will use larger data type.
*/
private int indexAttribute = IA_NONE;
/** Index components (fields with sorting directions). */
private List<IndexComponentDefinition> components;
/**
* Default c'tor
*/
public IndexDefinition()
{
}
/**
* Constructor. Creates an {@code IndexDefinition} staring from the {@code TableMapper} legacy data.
*
* @param lii
* ORM index info
*/
public IndexDefinition(LegacyIndexInfo lii)
{
this.legacyName = lii.getLegacyName();
indexAttribute = (lii.isEffectivePrimary() ? IA_PRIMARY : IA_NONE) |
(lii.isUnique() ? IA_UNIQUE : IA_NONE) |
(lii.isWord() ? IA_WORD : IA_NONE);
this.components = lii.indexComponents().map(IndexComponentDefinition::new).collect(Collectors.toList());
}
/**
* Add current index to the {@code TableBuilder}.
*
* @param tb
* {@code TableBuilder} instance.
*/
public void addTo(TempTableBuilder tb)
{
tb.addNewIndex(new character(legacyName),
new logical((indexAttribute & IA_UNIQUE) != 0),
new logical((indexAttribute & IA_PRIMARY) != 0),
new logical((indexAttribute & IA_WORD) != 0));
for (int i = 0; i < components.size(); i++)
{
IndexComponentDefinition c = components.get(i);
tb.addFieldToIndex(legacyName, c.fieldLegacyName, c.effectiveDescending ? "desc" : "asc");
}
}
/**
* Read the index definition from the specified input source.
*
* @param in
* The input source from which the index definition will be read.
*
* @throws IOException
* In case of I/O errors.
* @throws ClassNotFoundException
* If the class of property could not be found/loaded.
*/
@Override
public void readExternal(ObjectInput in)
throws IOException,
ClassNotFoundException
{
legacyName = readString(in);
indexAttribute = in.readByte(); // reading a single byte because there are only 3 attributes
components = readList(in, () -> new IndexComponentDefinition());
}
/**
* Send the index definition to the specified output destination.
*
* @param out
* The output destination to which the index definition will be sent.
*
* @throws IOException
* In case of I/O errors.
*/
@Override
public void writeExternal(ObjectOutput out)
throws IOException
{
writeString(out, legacyName);
out.writeByte(indexAttribute); // writing a single byte because there are only 3 attributes
writeList(out, components);
}
/** A container with an index component information. */
public static class IndexComponentDefinition
implements Externalizable
{
/** The legacy name of the field participating in the index. */
private String fieldLegacyName;
/** Determines if this component has descending sorting. */
private boolean effectiveDescending;
/**
* Default c'tor
*/
public IndexComponentDefinition()
{
}
/**
* Constructor.
*
* @param lici
* DMO ORM index component info.
*/
public IndexComponentDefinition(LegacyIndexComponentInfo lici)
{
this.fieldLegacyName = lici.fieldLegacyName;
this.effectiveDescending = lici.effectiveDescending;
}
/**
* Read the index definition from the specified input source.
*
* @param in
* The input source from which the index component definition will be read.
*
* @throws IOException
* In case of I/O errors.
* @throws ClassNotFoundException
* If the class of property could not be found/loaded.
*/
@Override
public void readExternal(ObjectInput in)
throws IOException,
ClassNotFoundException
{
fieldLegacyName = readString(in);
effectiveDescending = in.readByte() != 0;
}
/**
* Send the index definition to the specified output destination.
*
* @param out
* The output destination to which the index component definition will be sent.
*
* @throws IOException
* In case of I/O errors.
*/
@Override
public void writeExternal(ObjectOutput out)
throws IOException
{
writeString(out, fieldLegacyName);
out.writeByte(effectiveDescending ? 1 : 0);
}
}
}