You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opennlp.apache.org by kr...@apache.org on 2026/08/14 03:17:31 UTC

(opennlp) 13/16: model: Document installer schemes, tar formats, and the Limits builder

This is an automated email from the ASF dual-hosted git repository.

krickert pushed a commit to branch OPENNLP-1909-resource-installer
in repository https://gitbox.apache.org/repos/asf/opennlp.git

commit 3d90f4f1b2757e0635f1b7c4fc4e92f8cfd6bbdc
Author: Kristian Rickert <kr...@gmail.com>
AuthorDate: Wed Aug 12 15:04:09 2026 -0400

    model: Document installer schemes, tar formats, and the Limits builder
    
    States the accepted source schemes and why the others are refused: those
    handlers carry no connection or read timeout. The byte ceilings applied on
    that path either way, so the manual does not claim otherwise.
    
    Records which tar formats unpack under their real paths, namely bsdtar,
    tar --format=posix, and tar --format=gnu, and which entries are refused and
    why.
    
    Scopes the staged-installation guarantee to symbolic links that already
    exist below the target, which is what the check covers.
    
    Switches the Limits example to Limits.builder(), so it states only the
    limits that differ from the defaults instead of five positional arguments.
    The listing is mirrored by
    ResourceInstallerTest#testInstallWithinCustomCeilingsSucceeds.
---
 opennlp-docs/src/docbkx/model-loading.xml | 36 ++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/opennlp-docs/src/docbkx/model-loading.xml b/opennlp-docs/src/docbkx/model-loading.xml
index 19e259320..ade9da741 100644
--- a/opennlp-docs/src/docbkx/model-loading.xml
+++ b/opennlp-docs/src/docbkx/model-loading.xml
@@ -169,12 +169,23 @@ for(ClassPathModelEntry entry : models) {
     <title>Installing archived resources</title>
     <para>
       <code>ResourceInstaller</code> fetches a third-party resource, such as a training corpus or a
-      lexicon, into a target directory. An optional checksum is verified before anything is
+      lexicon, into a target directory. The location must be an <code>http</code>, <code>https</code>,
+      or <code>file</code> URI; any other scheme is rejected, because it would be opened through
+      whichever URL handler the runtime has installed, none of which honor the connection and read
+      timeouts below. An optional checksum is verified before anything is
       unpacked: a 64-character hex digest selects SHA-256, a 128-character one SHA-512. Archive
       entries that would escape the target directory are rejected. The content format is detected
       from the bytes, not from the name: gzip-compressed tar archives and zip archives are unpacked
-      with their relative structure, plain gzip files are decompressed, and anything else is stored
-      as a file under its source name.
+      with their relative structure (tar entry names may use the ustar name prefix field, so paths
+      longer than 100 bytes are read in full from the pax or GNU extension header that carries them,
+      so archives written by <code>bsdtar</code>, <code>tar --format=posix</code>, and
+      <code>tar --format=gnu</code> all unpack under their real paths; every header must carry a valid
+      checksum; entries of 8 GiB and above state their length in the base-256 form GNU writes for it;
+      sparse entries are refused, because their archived bytes encode holes rather than the file
+      content), plain gzip files are decompressed, and anything else is stored
+      as a file under its source name. One name rule overrides byte detection: a source named
+      <code>*.bin</code> is always stored packed, because an OpenNLP model file is itself a zip
+      archive that its consumers load packed.
       <code>ResourceInstallerTest#testInstallEndToEndUsageExample</code> asserts the behavior
       shown here.
 
@@ -186,8 +197,11 @@ for(ClassPathModelEntry entry : models) {
 
       Installation is staged: content unpacks into a hidden staging directory on the target
       filesystem and moves into the target only after the download was verified and every entry
-      unpacked cleanly. A failed installation therefore leaves the target directory as it was,
-      without partially written files.
+      unpacked cleanly. A fetch, verification, or unpacking failure therefore leaves the target
+      directory as it was, without partially written files. Promotion refuses to descend through a
+      symbolic link that already exists below the target, so a link planted there beforehand cannot
+      steer content out of the target. It is not a defense against a tree modified while the
+      installation runs.
       <code>ResourceInstallerTest#testFailedTarUnpackLeavesTargetEmpty</code> and its zip and
       truncated-archive siblings assert this guarantee.
     </para>
@@ -202,15 +216,17 @@ for(ClassPathModelEntry entry : models) {
       asserted by <code>ResourceInstallerTest#testDefaultLimitsArePinned</code>; the network
       behavior is exercised against a local scripted server in
       <code>ResourceInstallerHttpTest</code>. Pass a
-      <code>ResourceInstaller.Limits</code> to tighten or widen the defaults.
+      <code>ResourceInstaller.Limits</code> to tighten or widen them. <code>Limits.builder()</code>
+      starts from the defaults, so only the limits that differ need to be stated.
       <code>ResourceInstallerTest#testInstallWithinCustomCeilingsSucceeds</code> asserts the
       behavior shown here.
 
       <programlisting language="java">
-<![CDATA[ResourceInstaller.Limits limits = new ResourceInstaller.Limits(
-    Duration.ofSeconds(10), Duration.ofSeconds(10), 5,
-    1024 * 1024,   // download ceiling in bytes
-    1024 * 1024);  // expansion ceiling in bytes
+<![CDATA[ResourceInstaller.Limits limits = ResourceInstaller.Limits.builder()
+    .readTimeout(Duration.ofSeconds(10))
+    .maxDownloadBytes(1024L * 1024)   // download ceiling in bytes
+    .maxExpandedBytes(1024L * 1024)   // expansion ceiling in bytes
+    .build();                         // connect timeout and redirects stay at the defaults
 Path result = ResourceInstaller.install(
     corpusTarGz.toUri(), targetDirectory, expectedSha256, limits);]]>
       </programlisting>