DeferredDeletablesManager.java

/*
** Module   : DeferredDeletablesManager.java
** Abstract : Defines a manager for deletables which postpones them to a specific block.
**
** Copyright (c) 2020-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 AIL 20200518 Created initial version.
**     AIL 20200616 Moved buffer logic to the procedure manager. Remade the getHandlingBlock().
**     AIL 20200617 Moved the StaleProcedureHelper as separate class.
**                  Javadoc update.
** 002 CA  20220120 Improved performance for finalizables, keep them already sorted by their weight.
**     CA  20221006 Check if 'block.finalizables' exists before iterating it.  Refs #6824
** 003 CA  20231216 Avoid iterators when processing BlockDefinition.finalizables.
*/
/*
** 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.util;

import java.util.*;

/**
 * Provides a mean of postponing deletion of deletable resources at a specific block level. This is useful
 * where there are postpone deletes which can't be determined at the target place of deletion.
 */
public class DeferredDeletablesManager
implements Finalizable
{   
   /** The core collection of resources which are to be deleted when the manager is finished */
   private final Set<DeferredDeletable> deletables = new HashSet<>();

   /**
    * Registers a resource at a specific block depth. This also handles the scenario in which there
    * is already such manager registered at that block.
    * 
    * @param     blockDepth
    *            The index of the outermost block at which a manager should be registered; blockDepth 0
    *            means the global scope.
    * @param     resource
    *            The resource which is to be registered.
    *            
    * @return    <code>false</code> if the registration was skipped as this resource was already registered,
    *            <code>true</code> otherwise.
    */
   public static boolean registerAt(int blockDepth, DeferredDeletable resource)
   {
      BlockDefinition block = TransactionManager.getBlockAtDepth(blockDepth);
    
      Set<Finalizable>[] fini = block.finalizables;
      if (fini != null)
      {
         for (int i = 0; i < fini.length; i++)
         {
            Set<Finalizable> l = fini[i];
            
            if (l == null)
            {
               continue;
            }
            
            for (Finalizable finalizable : l)
            {
               if (finalizable instanceof DeferredDeletablesManager)
               {
                  return ((DeferredDeletablesManager) finalizable).register(resource);
               }
            }
         }
      }
      
      DeferredDeletablesManager ddm = new DeferredDeletablesManager();
      ddm.register(resource);
      TransactionManager.registerFinalizableAt(blockDepth, ddm);
      return true;
   }

   /**
    * Registers a specific deletable to this manager. While the collection is a set, the 
    * deletable won't be deleted twice.
    * 
    * @param     deletable 
    *            A resource meant to be registered for deletion. 
    *            
    * @return    <code>true</code> if the register was successful or <code>false</code> if the 
    *            deletable was already registered in this manager.
    */
   public boolean register(DeferredDeletable deletable)
   {
      return deletables.add(deletable);
   }

   /**
    * Does the effective delete of the registered resources when this manager is finished.
    */
   @Override
   public void finished()
   {
      for (DeferredDeletable deletable : deletables)
      {
         deletable.deferredDelete();
      }
   }

   /**
    * The method is a no-op due to the fact that the delete defer is made only when the 
    * the manager is notified through the {@code finished} method.
    */
   @Override
   public void deleted()
   {
      // no-op
   }
   
   /**
    * The method is a no-op due to the fact that the delete defer is made only when the 
    * the manager is notified through the {@code finished} method.
    */
   @Override
   public void iterate()
   {
      // no-op
   }
   
   /**
    * The method is a no-op due to the fact that the delete defer is made only when the 
    * the manager is notified through the {@code finished} method.
    */
   @Override
   public void retry()
   {
      // no-op
   }
}