# 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)
       {
       }
    }