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 -&gt; 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)
   {
   }
}