TableHighIdentityManager.java
/*
** Module : TableHighIdentityManager.java
** Abstract : Identity manager implementation which uses high-water ID of each
** table as a starting point for new IDs
**
** Copyright (c) 2004-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
** 001 SVL 20071231 @36636 Created initial version. Default
** implementation of IdentityManager interface.
** 002 ECF 20080805 @39305 Adapted from DefaultIdentityManager. Modified
** to produce 64-bit keys. Conformed to new
** IdentityManager API.
** 003 SVL 20080901 @39646 Implements IdentityPoolManager instead of
** IdentityManager.
** 004 SVL 20120331 Upgraded to Hibernate 4.
** 005 EVL 20160223 Javadoc fixes to make compatible with Oracle Java 8 for Solaris 10.
** 006 ECF 20200906 Removed Hibernate dependencies.
** TODO: ensure there are no dependencies on this class and remove it.
** 007 TJD 20220504 Upgrade do Java 11 minor changes
** 008 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 009 OM 20241128 Multi-tenant runtime support: selected the proper persistence context, eventually
** based on [sharedDb] parameter.
*/
/*
** 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.id;
import java.util.*;
import com.goldencode.p2j.persist.*;
import com.goldencode.p2j.util.logging.*;
/**
* @deprecated Use {@link SequenceIdentityManager} or other identity manager
* which supports database-wide unique ids.
*
* Implementation of the {@link IdentityManager} interface. During server
* initialization, each database table is queried to determine its maximum
* primary key ID. This information is stored in a map for later use in
* providing the next available ID for each table. The per-table value is
* incremented for each {@link #nextPrimaryKey(String) ID request}.
* <p>
* Current limitations:
* <ul>
* <li><b>Does not produce database-wide unique IDs</b>. Note that this
* does not match Progress behavior.
* <li>Wrapping to a negative number after we increment beyond
* <code>Long.MAX_VALUE</code> is not handled at this time.
* <li>Does not recycle IDs which are allocated but never used.
* <li>Does not reclaim IDs for deleted records.
* <li>Does not detect/repair fragmentation of the primary key address
* space for a table; existing gaps in primary keys are never plugged.
* Note that a solution for this item may preclude having to address the
* previous three items.
* </ul>
*/
@Deprecated
public final class TableHighIdentityManager
implements IdentityPoolManager
{
/** Logger */
private static final CentralLogger LOG = CentralLogger.get(IdentityManager.class.getName());
/** Map for storing table name -> current maximum ID relations. */
private final Map<String, Long> ids;
/** Persistence service object used to interact with the database */
private Persistence persistence = null;
/**
* Default constructor.
*/
public TableHighIdentityManager()
{
ids = new HashMap<String, Long>();
}
/**
* Specify the database for the identity manager.
* <code>TableHighIdentityManager</code> is initialized here - current
* maximum IDs for each table are retrieved.
*
* @param persistence
* Persistence service object associated with identity manager.
*/
public void setPersistence(Persistence persistence)
{
// TODO: remove this deprecated class
/*
this.persistence = persistence;
Database database = persistence.getDatabase();
Session session = null;
boolean debug = LOG.isDebugEnabled();
try
{
SessionFactory factory = DatabaseManager.getSessionFactory(database);
Configuration cfg = DatabaseManager.getHibernateConfiguration(database);
Iterator iter = cfg.getClassMappings();
session = factory.openSession();
while (iter.hasNext())
{
Object obj = iter.next();
if (obj instanceof RootClass)
{
RootClass rc = (RootClass) obj;
String className = rc.getClassName();
String tableName = rc.getTable().getName();
StringBuilder buf = new StringBuilder();
buf.append("select max(obj.id) from ");
buf.append(className);
buf.append(" obj");
Query query = session.createQuery(buf.toString());
Object res = query.uniqueResult();
Long max = (res == null ? 0 : (Long) res);
synchronized (ids)
{
ids.put(tableName, max);
}
if (debug)
{
buf = new StringBuilder();
buf.append("Last ID for '");
buf.append(database.getName());
buf.append(".");
buf.append(tableName);
buf.append("': ");
buf.append(max);
LOG.debug(buf.toString());
}
}
}
}
catch (Exception exc)
{
String msg = "Error initializing identity manager for database '" +
database.getName() +
"'";
LOG.log(Level.SEVERE, msg, exc);
throw new RuntimeException(msg, exc);
}
finally
{
if (session != null)
{
session.close();
}
}
*/
}
/**
* Return the next primary key for the specified table.
*
* @param table
* Table for which the next primary key will be returned.
*
* @return The next primary key for the given table.
*
* @throws PersistenceException
* if there is an error determining the next primary key ID.
*/
public Long nextPrimaryKey(String table)
throws PersistenceException
{
synchronized (ids)
{
Long id = ids.get(table);
if (id == null)
{
throw new PersistenceException(
"Cannot locate next ID for table '" +
persistence.getDatabase(Persistence.SHARED_CTX).getName() +
"." +
table +
"'");
}
id++;
ids.put(table, id);
return id;
}
}
/**
* Inform ithe dentity manager that the given primary keys can be reused.
* No-op in this implementation.
*
* @param keys
* Keys for reuse.
*/
public void reclaimKeys(Long[] keys)
{
}
/**
* Sets identity pool which can be used by this identity manager. No-op in
* this implementaion.
*
* @param identityPool
* Identity pool for use.
*/
public void setIdentityPool(IdentityPool identityPool)
{
}
}