Class PNSpoolerRoot

All Implemented Interfaces:
EventListener, IGProp<GProp<?>[]>, IPropCnr, Cloneable

public class PNSpoolerRoot extends PropCnr
The root of the push spool, i.e. the container of the PNSpoolEntry children that could not be delivered yet.

One live tree, mirrored to disk. The spool is a single in-memory container that is written out at chosen moments - a timer, the end of a batch, shutdown - and never once per event. A send that cannot complete adds a child; a retry that succeeds removes one, so a delivered notification is simply gone from the next file written. Replay on start-up is the reverse: load the file, drop whatever has passed its PNSpoolEntry.TTL_DEADLINE, and work through what is left. The spool, the app-session retention and crash recovery are therefore one mechanism, not three.

Concurrency needs no layer of its own. Every structural mutation of a property container already takes the tree lock and then the container's own monitor, so concurrent addProp/removeProp from many dispatch threads is safe by construction. The one rule the spool must keep is on PNSpoolEntry: an entry is immutable once added, because clone() deep-clones children outside the monitors and a clone-then-write persist is only consistent if nothing edits a child while it is being copied.

usesPropIndex() is false, and the replay order comes from a sort on load. Index relevance buys indexed access - getProp(int) used as identity, the way an ordered UI container needs it - and the spool has no such access: it adds pending entries, removes them on success, and replays in time order. Time order is a property of the entries, not of their position, so it is recovered by sorting on load. The churn settles it either way: because a retry is remove-then-add-new, positions are rewritten constantly, and a stored index would be meaningless by the second attempt.

Server-only. The spool never reaches a JavaScript client. It is nevertheless registered in com/iizix/schema/base-properties.xml like every serialised class, because PropFactory throws for any class it has no entry for, on the way out as well as on the way in.

Author:
Christopher Mindus
  • Field Details

    • ATOM

      public static final Atom ATOM
      The atom for the push spool root container: "$pnSpooler".
  • Constructor Details

    • PNSpoolerRoot

      public PNSpoolerRoot()
      Creates a push spool root container without name and with a null value.
    • PNSpoolerRoot

      public PNSpoolerRoot(Atom propertyAtom)
      Creates a push spool root container with the specified name with a null value.
      Parameters:
      propertyAtom - The property atom.
  • Method Details

    • clone

      public PNSpoolerRoot clone()
      Creates a clone out of this property.

      This is the snapshot used to persist the spool without blocking dispatch: clone the live tree, then write the clone. See PNSpoolEntry for the immutability rule that makes the snapshot consistent.

      Overrides:
      clone in class PropCnr
      Returns:
      The clone of the spool root.
    • usesPropIndex

      public final boolean usesPropIndex()
      Use of index for this property container is disabled: the spool has no positional access and its replay order is recovered by sortEntries() on load. Declared final because the choice is load-bearing - see the class documentation.
      Specified by:
      usesPropIndex in interface IPropCnr
      Overrides:
      usesPropIndex in class PropCnr
      Returns:
      false for this container.
    • getEntries

      public PNSpoolEntry[] getEntries()
      Gets the spool entries in their current container order, which is replay order after a load and after any call to sortEntries().
      Returns:
      The entries; an empty array when the spool is empty, never null.
    • sortEntries

      public boolean sortEntries() throws PropException
      Sorts the children into replay order: by creation time, then by next-attempt time, then by property name.

      This is called automatically once the whole tree has been loaded from XML, which is the only moment the order is not already known. It is public because a caller that has just added a batch of entries out of order may want the same guarantee without a round trip through the file.

      Returns:
      true if the order changed, false if it was already correct.
      Throws:
      PropException - If the reordering is rejected by the container.
    • onPropTreeInitialized

      public void onPropTreeInitialized() throws IOException, PropException
      Called once the whole property tree has been loaded from XML. The children are sorted into replay order here, which is what replaces an index-relevant container for the spool.
      Specified by:
      onPropTreeInitialized in interface IGProp<GProp<?>[]>
      Overrides:
      onPropTreeInitialized in class PropCnr
      Throws:
      IOException - For file errors.
      PropException - When there is an initialization problem.