Class CrashSafeYamlFiles

java.lang.Object
com.ultikits.ultitools.config.CrashSafeYamlFiles

public final class CrashSafeYamlFiles extends Object
Opt-in complete publication of a module's operator-editable YAML file, on an explicit operator create/edit action. Not for automatic saves, value repair, @ConfigEntity files, framework state or credentials.

Why it cannot overwrite operator content. Existing-file writes own only the named complete key paths and reuse the configuration gate's plain-data, fingerprint, parse/render/reparse and unowned-byte checks. Every other byte (comments, unknown keys, BOM and line endings included) must stay unchanged or the edit is refused. Creation owns the whole file only while no directory entry exists. Neither method updates the caller's live objects.

Supported filesystems and metadata. These File-based methods (snapshots also originate from a File) use the default filesystem. Publication requires ordinary files on a local default POSIX filesystem with native atomic rename/link semantics, working POSIX attributes and an existing parent directory. An existing final symlink is refused, not followed; parent links are resolved with filesystem semantics. Paths must be trusted module paths, not unsanitized user input; this is not a path sandbox. Existing files keep the nine POSIX permission bits, owner and group, applied and verified before commit; failure aborts publication. Read-only targets are refused. New files use the process-created owner/group and mode 0600. Staging is created exclusively at 0600 before any content and narrowed to 0000 before a required identity change. Non-POSIX or a Java-exposed ACL view on parent/target/stage is refused. No ACLs are copied. Absence of an ACL view does not establish absence of hidden ACLs/default ACLs, labels or xattrs. Do not adopt this API where preserving those, special mode bits, alternate streams, inode identity, hard-link relationships, creation times or arbitrary flags is required. Replacement uses a new inode; hard-link aliases retain old content. Unknown metadata has replacement/new-file semantics; not every incompatible layout can be detected.

Commit and limits. Complete UTF-8 contents and promised metadata are forced with force(true) and closed before atomic replacement, or exclusive native POSIX hard-link creation. Unsupported rename/link operations fail without copy, ordinary-move, truncate or journal fallback. The POSIX link contract, not a blanket guarantee for every NIO provider, underlies exclusive creation. With a functioning OS/filesystem a process crash leaves old/absent or complete-new final content. Directory forcing after commit is best effort and warns on failure; WRITTEN is not absolute power-loss durability. OS crashes, remote storage, filesystem recovery and device failure are outside this guarantee. This is single-file publication, not a multi-file transaction.

Same-JVM gate writes serialize and recheck bytes/kind/promised metadata before commit. There is no cross-process lock or guarantee against an external edit/rename/chmod in the final check-to-publication interval; do not share the file with concurrent uncoordinated writers. No startup scan, journal, replay, promotion or rollback is performed. Only the exact current invocation's known-file-key regular temp may be cleaned. A crash can leave a partial/complete <name>.ultitools-stage-<32 lower-case hex>.tmp, or a second hard link after creation. Later calls leave it alone. Stop competing writers/server, inspect the target and named temp, and never assume a temp is authoritative or promote it automatically. Delete only one recognized as no longer needed; otherwise keep it and use an independently trusted backup or explicit recreate action. Retained temps may contain new data under the declared final mode: protect them like the YAML file. Legacy OperatorFiles.write(com.ultikits.ultitools.config.OperatorFiles.Snapshot, java.util.Map<java.util.List<java.lang.String>, java.lang.Object>) and internal writer defaults are unchanged.

Since:
6.4.0
  • Constructor Details

    • CrashSafeYamlFiles

      private CrashSafeYamlFiles()
  • Method Details

    • write

      public static OperatorFiles.WriteResult write(OperatorFiles.Snapshot readAt, Map<List<String>,Object> values) throws IOException
      Writes only explicitly edited keys while the existing file still holds the snapshot's bytes. No unowned byte is authorized to change (see the class contract). Empty edits and semantic no-ops do not stage or change metadata.
      Parameters:
      readAt - snapshot from OperatorFiles.read(File) on which the edit was decided
      values - complete key paths to plain-data values; dots within a key are literal, null values are valid
      Returns:
      WRITTEN, UNCHANGED, FILE_CHANGED (including a missing target), or REFUSED with a value-free warning
      Throws:
      IllegalArgumentException - for null arguments, null/empty key paths, null keys or non-plain values, before I/O
      IOException - if staging, promised metadata or publication fails before commit; no new bytes are published
    • create

      public static OperatorFiles.WriteResult create(File file, Map<String,Object> values) throws IOException
      Publishes a complete validated root map only for an explicit operator create action, never replacing any existing entry. This is why whole-file ownership cannot overwrite operator content. The parent must already exist.
      Parameters:
      file - trusted destination on the default local POSIX filesystem
      values - complete plain-data root map; whole literal keys, nullable values, empty map allowed
      Returns:
      WRITTEN, FILE_CHANGED if an entry already exists/appears, or REFUSED; never UNCHANGED
      Throws:
      IllegalArgumentException - for null arguments/keys or non-plain data, before I/O
      IOException - if staging, metadata, parent resolution or native link publication fails before commit
    • outcome

      private static OperatorFiles.WriteResult outcome(OperatorFileWriter.Result result)