You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2018/08/22 08:40:54 UTC

svn commit: r1838616 - in /jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api: JackrabbitValueFactory.java binary/BinaryDownload.java binary/BinaryDownloadOptions.java binary/BinaryUpload.java

Author: mreutegg
Date: Wed Aug 22 08:40:54 2018
New Revision: 1838616

URL: http://svn.apache.org/viewvc?rev=1838616&view=rev
Log:
JCR-4355: Javadoc fixes and improvements for new direct binary access API

Patch provided by Alexander Klimetschek, with review and contribution from Julian Reschke

Modified:
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValueFactory.java
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownload.java
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownloadOptions.java
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryUpload.java

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValueFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValueFactory.java?rev=1838616&r1=1838615&r2=1838616&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValueFactory.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValueFactory.java Wed Aug 22 08:40:54 2018
@@ -18,12 +18,14 @@
 
 package org.apache.jackrabbit.api;
 
+import java.io.InputStream;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Binary;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.ValueFactory;
 
+import org.apache.jackrabbit.api.binary.BinaryDownloadOptions;
 import org.apache.jackrabbit.api.binary.BinaryUpload;
 import org.apache.jackrabbit.api.binary.BinaryDownload;
 import org.jetbrains.annotations.NotNull;
@@ -32,42 +34,57 @@ import org.osgi.annotation.versioning.Pr
 
 /**
  * Defines optional functionality that a {@link ValueFactory} may choose to
- * provide.  A {@link ValueFactory} may also implement this interface without
- * supporting all of the capabilities in this interface.  Each method of the
+ * provide. A {@link ValueFactory} may also implement this interface without
+ * supporting all of the capabilities in this interface. Each method of the
  * interface describes the behavior of that method if the underlying capability
  * is not available.
+ *
  * <p>
- * Currently this interface defines the following optional features:
+ * This interface defines the following optional features:
  * <ul>
- *     <li>Direct Binary Access - enable a client to upload or download binaries
+ *     <li>
+ *         Direct Binary Access - enable a client to upload or download binaries
  *         directly to/from a storage location
+ *     </li>
  * </ul>
+ *
  * <p>
  * The features are described in more detail below.
  *
  * <h2>Direct Binary Access</h2>
- * <p>
+ *
  * The Direct Binary Access feature provides the capability for a client to
- * upload or download binaries directly to/from a storage location.  For
- * example, this might be a cloud storage providing high-bandwidth direct
- * network access.  This API allows for requests to be authenticated and for
- * access permission checks to take place within the repository, but for clients
- * to then access the storage location directly.
+ * upload or download binaries directly to/from a storage location. For example,
+ * this might be a cloud storage providing high-bandwidth direct network access.
+ * This API allows for requests to be authenticated and for access permission
+ * checks to take place within the repository, but for clients to then access
+ * the storage location directly.
+ *
  * <p>
- * The feature consists of two parts, direct binary upload and direct binary
- * download.
+ * The feature consists of two parts, download and upload.
+ *
+ * <h3>Direct Binary Download</h3>
+ *
+ * This feature enables remote clients to download binaries directly from a
+ * storage location without streaming the binary through the Jackrabbit-based
+ * application.
+ *
  * <p>
+ * For an existing {@link Binary} value that implements {@link BinaryDownload},
+ * a read-only URI (see {@link BinaryDownload#getURI(BinaryDownloadOptions)})
+ * can be retrieved and passed to a remote client, such as a browser.
  *
  * <h3>Direct Binary Upload</h3>
- * <p>
+ *
  * This feature enables remote clients to upload binaries directly to a storage
  * location.
+ *
  * <p>
- * When adding binaries already present on the same JVM or server as Jackrabbit
- * or Oak, for example because they were generated locally, please use the
- * regular JCR API for {@link javax.jcr.Property#setValue(Binary) adding
- * binaries through input streams} instead. This feature is solely designed for
- * remote clients.
+ * Note: When adding binaries already present on the same JVM/server as
+ * the JCR repository, for example because they were generated locally, please
+ * use the regular JCR API {@link ValueFactory#createBinary(InputStream)}
+ * instead. This feature is solely designed for remote clients.
+ *
  * <p>
  * The direct binary upload process is split into 3 phases:
  * <ol>
@@ -75,112 +92,93 @@ import org.osgi.annotation.versioning.Pr
  *         <b>Initialize</b>: A remote client makes request to the
  *         Jackrabbit-based application to request an upload, which calls {@link
  *         #initiateBinaryUpload(long, int)} and returns the resulting {@link
- *         BinaryUpload information} to the remote client.
+ *         BinaryUpload instructions} to the remote client.
  *     </li>
  *     <li>
  *         <b>Upload</b>: The remote client performs the actual binary upload
- *         directly to the binary storage provider.  The {@link BinaryUpload}
+ *         directly to the binary storage provider. The {@link BinaryUpload}
  *         returned from the previous call to {@link
  *         #initiateBinaryUpload(long, int)} contains detailed instructions on
- *         how to complete the upload successfully. For more information, see
- *         the BinaryUpload documentation.
+ *         how to complete the upload successfully.
  *     </li>
  *     <li>
  *         <b>Complete</b>: The remote client notifies the Jackrabbit-based
- *         application that step 2 is complete.  The upload token returned in
+ *         application that step 2 is complete. The upload token returned in
  *         the first step (obtained by calling {@link
- *         BinaryUpload#getUploadToken()} is passed by the client to {@link
+ *         BinaryUpload#getUploadToken()} is passed by the application to {@link
  *         #completeBinaryUpload(String)}. This will provide the application
  *         with a regular {@link Binary JCR Binary} that can then be used to
  *         write JCR content including the binary (such as an nt:file structure)
- *         and {@link Session#save() persist} it.
+ *         and persist it using {@link Session#save}.
  *     </li>
  * </ol>
- * <p>
- * <h3>Direct Binary Download</h3>
- * <p>
- * The direct binary download process is described in detail in {@link
- * BinaryDownload}.
  */
 @ProviderType
 public interface JackrabbitValueFactory extends ValueFactory {
+
     /**
-     * Initiate a transaction to upload binary data directly to a storage
-     * location.  {@link IllegalArgumentException} will be thrown if an upload
-     * cannot be supported for the required parameters, or if the parameters are
-     * otherwise invalid.  For example, if the value of {@code maxSize} exceeds
-     * the size limits for a single binary upload for the implementation or the
-     * service provider, or if the value of {@code maxSize} divided by {@code
-     * maxParts} exceeds the size limit for an upload or upload part of the
-     * implementation or the service provider, {@link IllegalArgumentException}
-     * may be thrown.
-     * <p>
-     * Each service provider has specific limitations on upload sizes,
-     * multi-part upload support, part sizes, etc. which can result in {@link
-     * IllegalArgumentException} being thrown.  You should consult the
-     * documentation for your underlying implementation and your service
-     * provider for details.
+     * Initiate a transaction to upload a binary directly to a storage
+     * location and return {@link BinaryUpload} instructions for a remote client.
+     * Returns {@code null} if the feature is not available.
+     *
      * <p>
-     * If this call is successful, a {@link BinaryUpload} is returned
-     * which contains the information a client needs to successfully complete
-     * a direct upload.
-     *
-     * @param maxSize The expected maximum size of the binary to be uploaded by
-     *         the client.  If the actual size of the binary is known, this
-     *         size should be used; otherwise, the client should make a best
-     *         guess.  If a client calls this method with one size and then
-     *         later determines that the guess was too small, the transaction
-     *         should be restarted by calling this method again with the correct
-     *         size.
+     * {@link IllegalArgumentException} will be thrown if an upload
+     * cannot be supported for the required parameters, or if the parameters are
+     * otherwise invalid. Each service provider has specific limitations.
+     *
+     * @param maxSize The exact size of the binary to be uploaded or the
+     *                estimated maximum size if the exact size is unknown.
+     *                If the estimation was too small, the transaction
+     *                should be restarted by invoking this method again
+     *                using the correct size.
      * @param maxURIs The maximum number of upload URIs that the client can
-     *         accept.  The implementation will ensure that an upload of size
-     *         {@code maxSize} can be completed by splitting the value of {@code
-     *         maxSize} into parts, such that the size of the largest part does
-     *         not exceed any known implementation or service provider
-     *         limitations on upload part size and such that the number of parts
-     *         does not exceed the value of {@code maxURIs}.  If this is not
-     *         possible, {@link IllegalArgumentException} will be thrown.  A
-     *         client may specify -1 for this value, indicating that any number
-     *         of URIs may be returned.
-     * @return A {@link BinaryUpload} that can be used by the client to complete
-     *         the upload via a call to {@link #completeBinaryUpload(String)},
+     *                accept, for example due to message size limitations.
+     *                A value of -1 indicates no limit.
+     *                Upon a successful return, it is ensured that an upload
+     *                of {@code maxSize} can be completed by splitting the
+     *                binary into {@code maxURIs} parts, otherwise
+     *                {@link IllegalArgumentException} will be thrown.
+     *
+     * @return A {@link BinaryUpload} providing the upload instructions,
      *         or {@code null} if the implementation does not support the direct
      *         upload feature.
+     *
      * @throws IllegalArgumentException if the provided arguments are
-     *         invalid or if a valid upload cannot be completed given the
-     *         provided arguments.
-     * @throws AccessDeniedException if it is determined that insufficient
-     *         permission exists to perform the upload.
+     *         invalid or if an upload cannot be completed given the
+     *         provided arguments. For example, if the value of {@code maxSize}
+     *         exceeds the size limits for a single binary upload for the
+     *         implementation or the service provider, or if the value of
+     *         {@code maxSize} divided by {@code maxParts} exceeds the size
+     *         limit for an upload or upload part.
+     *
+     * @throws AccessDeniedException if the session has insufficient
+     *         permission to perform the upload.
      */
     @Nullable
     BinaryUpload initiateBinaryUpload(long maxSize, int maxURIs)
             throws IllegalArgumentException, AccessDeniedException;
 
     /**
-     * Complete a transaction to upload binary data directly to a storage
-     * location.  The client must provide a valid {@code uploadToken} that can
-     * only be obtained via a previous call to {@link
-     * #initiateBinaryUpload(long, int)}.  If the {@code uploadToken} is
-     * unreadable or invalid, {@link IllegalArgumentException} will be thrown.
-     * <p>
-     * Calling this method does not associate the returned {@link Binary} with
-     * any location in the repository.  It is the responsibility of the client
-     * to do this if desired.
+     * Complete the transaction of uploading a binary directly to a storage
+     * location and return a {@link Binary} to set as value for a binary
+     * JCR property. The binary is not automatically associated with
+     * any location in the JCR.
+     *
      * <p>
-     * The {@code uploadToken} can be obtained from the {@link
-     * BinaryUpload} returned from a prior call to {@link
-     * #initiateBinaryUpload(long, int)}.  Clients should treat the {@code
-     * uploadToken} as an immutable string, and should expect that
-     * implementations will sign the string and verify the signature when this
-     * method is called.
+     * The client must provide a valid upload token, obtained from
+     * {@link BinaryUpload#getUploadToken()} when this transaction was initialized
+     * using {@link #initiateBinaryUpload(long, int)}.
+     * If the {@code uploadToken} is unreadable or invalid,
+     * an {@link IllegalArgumentException} will be thrown.
+     *
+     * @param uploadToken A String identifying the upload transaction.
      *
-     * @param uploadToken A String that is used to identify the direct upload
-     *         transaction.
      * @return The uploaded {@link Binary}, or {@code null} if the
      *         implementation does not support the direct upload feature.
-     * @throws IllegalArgumentException if the {@code uploadToken} is
-     *         unreadable or invalid.
-     * @throws RepositoryException if a repository access error occurs.
+     *
+     * @throws IllegalArgumentException if the {@code uploadToken} is invalid or
+     *         does not identify a known binary upload.
+     * @throws RepositoryException if another error occurs.
      */
     @Nullable
     Binary completeBinaryUpload(@NotNull String uploadToken)

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownload.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownload.java?rev=1838616&r1=1838615&r2=1838616&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownload.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownload.java Wed Aug 22 08:40:54 2018
@@ -33,25 +33,72 @@ import org.osgi.annotation.versioning.Pr
 @ProviderType
 public interface BinaryDownload extends Binary {
     /**
-     * Get a URI for downloading a {@link Binary} directly from a storage
-     * location with the provided {@link BinaryDownloadOptions}. This is
-     * probably a signed URI with a short TTL (time to live), although the API
-     * does not require it to be so.
+     *
+     * Returns a URI for downloading this binary directly from the storage location.
+     *
      * <p>
-     * The implementation will attempt to apply the specified {@code
-     * downloadOptions} to the subsequent download. For example, if the caller
-     * knows that the URI refers to a specific type of content, the caller can
-     * specify that content type by setting the internet media type and
-     * character encoding in the {@code downloadOptions}. The caller may also
-     * use a default instance obtained via {@link BinaryDownloadOptions#DEFAULT}
-     * in which case the caller is indicating that the default behavior of the
-     * service provider is acceptable.
+     * Using the {@code downloadOptions} parameter, some response headers of the
+     * download request can be overwritten, if supported by the storage provider.
+     * This is necessary to pass information that is only stored in the JCR in
+     * application specific structures, and not reliably available in the binary
+     * storage.
+     *
+     * {@link BinaryDownloadOptions} supports, but is not limited to:
+     * <ul>
+     *     <li>
+     *         {@link BinaryDownloadOptions.BinaryDownloadOptionsBuilder#withMediaType(String) Content-Type media type}:
+     *         typically available in a {@code jcr:mimeType} property
+     *     </li>
+     *     <li>
+     *         {@link BinaryDownloadOptions.BinaryDownloadOptionsBuilder#withCharacterEncoding(String) Content-Type charset}:
+     *         for media types defining a "charset", typically available in a {@code jcr:encoding} property
+     *     </li>
+     *     <li>
+     *         {@link BinaryDownloadOptions.BinaryDownloadOptionsBuilder#withFileName(String) Content-Disposition filename}:
+     *         download file name, typically taken from a JCR node name in the parent hierarchy, such as the nt:file node name
+     *     </li>
+     *     <li>
+     *         {@link BinaryDownloadOptions.BinaryDownloadOptionsBuilder#withDispositionTypeAttachment() Content-Disposition type}:
+     *         whether to show the content inline of a page (inline) or enforce a download/save as (attachment)
+     *     </li>
+     * </ul>
+     *
+     * Specifying {@link BinaryDownloadOptions#DEFAULT} will use mostly empty
+     * defaults, relying on the storage provider attributes for this binary
+     * (that might be empty or different from the information in the JCR).
+     *
+     * <p>
+     * <b>Security considerations:</b>
+     *
+     * <ul>
+     *     <li>
+     *         The URI cannot be shared with other users. It must only be returned to
+     *         authenticated requests corresponding to this session user or trusted system
+     *         components.
+     *     </li>
+     *     <li>
+     *         The URI must not be persisted for later use and will typically be time limited.
+     *     </li>
+     *     <li>
+     *         The URI will only grant access to this particular binary.
+     *     </li>
+     *     <li>
+     *         The client cannot infer any semantics from the URI structure and path names.
+     *         It would typically include a cryptographic signature. Any change to the URI will
+     *         likely result in a failing request.
+     *     </li>
+     *     <li>
+     *         If the client is a browser, consider use of Content-Disposition type = attachment
+     *         for executable media types such as HTML or Javascript if the content cannot be
+     *         trusted.
+     *     </li>
+     * </ul>
      *
      * @param downloadOptions
      *            A {@link BinaryDownloadOptions} instance which is used to
      *            request specific options on the binary to be downloaded.
      *            {@link BinaryDownloadOptions#DEFAULT} should be used if the
-     *            caller wishes to accept the service provider's default
+     *            caller wishes to accept the storage provider's default
      *            behavior.
      * @return A URI for downloading the binary directly, or {@code null} if the
      *         binary cannot be downloaded directly or if the underlying

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownloadOptions.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownloadOptions.java?rev=1838616&r1=1838615&r2=1838616&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownloadOptions.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryDownloadOptions.java Wed Aug 22 08:40:54 2018
@@ -184,10 +184,10 @@ public final class BinaryDownloadOptions
 
         /**
          * Sets the character encoding of the {@link BinaryDownloadOptions} object to be
-         * built.  This value should be a valid {@code jcr:encoding}.
+         * built. This value should be a valid {@code jcr:encoding} property value.
          * <p>
          * Calling this method has the effect of instructing the service
-         * provider to set {@code charecterEncoding} as the "charset" parameter
+         * provider to set {@code characterEncoding} as the "charset" parameter
          * of the content type in the {@code Content-Type} header field of the
          * response to a request issued with a URI obtained by calling {@link
          * BinaryDownload#getURI(BinaryDownloadOptions)}.  This value can be
@@ -195,9 +195,9 @@ public final class BinaryDownloadOptions
          * BinaryDownloadOptions#getCharacterEncoding()} on the instance returned by a
          * call to {@link #build()}.
          * <p>
-         * Note that setting the character encoding only makes sense if the internet media type has
-         * also been set.  See {@link
-         * #withMediaType(String)}.
+         * Note that setting the character encoding only makes sense if the internet
+         * media type has also been set, and that media type actually defines a
+         * "charset" parameter. See {@link #withMediaType(String)}.
          * <p>
          * The caller should ensure that the proper character encoding has been set for
          * the internet media type; the implementation does not perform any validation of
@@ -216,7 +216,7 @@ public final class BinaryDownloadOptions
 
         /**
          * Sets the filename of the {@link BinaryDownloadOptions} object to be
-         * built.
+         * built. This would typically be based on a JCR node name.
          * <p>
          * Calling this method has the effect of instructing the service
          * provider to set {@code fileName} as the filename in the {@code

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryUpload.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryUpload.java?rev=1838616&r1=1838615&r2=1838616&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryUpload.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/binary/BinaryUpload.java Wed Aug 22 08:40:54 2018
@@ -25,78 +25,104 @@ import org.jetbrains.annotations.NotNull
 import org.osgi.annotation.versioning.ProviderType;
 
 /**
- * This extension interface provides a mechanism whereby a client can upload a
- * binary directly to a storage location.  An object of this type can be
- * created by a call to {@link
- * JackrabbitValueFactory#initiateBinaryUpload(long, int)} which will return an
- * object of this type if the underlying implementation supports direct upload
- * functionality.  When calling this method, the client indicates the expected
- * size of the binary and the number of URIs that it is willing to accept.  The
- * implementation will attempt to create an instance of this class that is
- * suited to enabling the client to complete the upload successfully.
+ * Describes uploading a binary through HTTP requests in a single or multiple
+ * parts. This will be returned by
+ * {@link JackrabbitValueFactory#initiateBinaryUpload(long, int)}. A high-level
+ * overview of the process can be found in {@link JackrabbitValueFactory}.
+ *
  * <p>
- * Using an instance of this class, a client can then use one or more of the
- * included URIs for uploading the binary directly by calling {@link
- * #getUploadURIs()} and iterating through the URIs returned.  Multi-part
- * uploads are supported by the interface, although they may not be supported
- * by the underlying implementation.
+ * Note that although the API allows URI schemes other than "http(s)", the
+ * upload functionality is currently only defined for HTTP.
+ *
  * <p>
- * Once a client finishes uploading the binary data, the client must then call
- * {@link JackrabbitValueFactory#completeBinaryUpload(String)} to complete the
- * upload.  This call requires an upload token which can be obtained from an
- * instance of this class by calling {@link #getUploadToken()}.
+ * A caller usually needs to pass the information provided by this interface to
+ * a remote client that is in possession of the actual binary, who then has to
+ * upload the binary using HTTP according to the logic described below. A remote
+ * client is expected to support multi-part uploads as per the logic described
+ * below, in case multiple URIs are returned.
+ *
  * <p>
- * Below is the detailed direct binary upload algorithm for the remote client.
+ * Once a remote client finishes uploading the binary data, the application must
+ * be notified and must then call
+ * {@link JackrabbitValueFactory#completeBinaryUpload(String)} to complete the
+ * upload. This completion requires the exact upload token obtained from
+ * {@link #getUploadToken()}.
+ *
+ * <h2 id="upload.algorithm">Upload algorithm</h2>
+ *
+ * A remote client will have to follow this algorithm to upload a binary based
+ * on the information provided by this interface.
+ *
  * <p>
- * In this example the following variables are used:
+ * Please be aware that if the size passed to
+ * {@link JackrabbitValueFactory#initiateBinaryUpload(long, int)} was an
+ * estimation, but the actual binary is larger, there is no guarantee the
+ * upload will be possible using all {@link #getUploadURIs()} and the
+ * {@link #getMaxPartSize()}. In such cases, the application should restart the
+ * transaction using the correct size.
+ *
+ * <h3>Variables used</h3>
  * <ul>
  *     <li>{@code fileSize}: the actual binary size (must be known at this
- *     point)
- *     <li>{@code minPartSize}: the value from {@link #getMinPartSize()}
- *     <li>{@code maxPartSize}: the value from {@link #getMaxPartSize()}
+ *     point)</li>
+ *     <li>{@code minPartSize}: the value from {@link #getMinPartSize()}</li>
+ *     <li>{@code maxPartSize}: the value from {@link #getMaxPartSize()}</li>
  *     <li>{@code numUploadURIs}: the number of entries in {@link
- *     #getUploadURIs()}
- *     <li>{@code uploadURIs}: the entries in {@link #getUploadURIs()}
+ *     #getUploadURIs()}</li>
+ *     <li>{@code uploadURIs}: the entries in {@link #getUploadURIs()}</li>
  *     <li>{@code partSize}: the part size to be used in the upload (to be
- *     determined in the algorithm)
+ *     determined in the algorithm)</li>
  * </ul>
  *
- * Steps:
+ * <h3>Steps</h3>
  * <ol>
- *     <li>If (fileSize divided by maxPartSize) is larger than numUploadURIs,
- *     then the client cannot proceed and will have to request a new set of URIs
- *     with the right fileSize as maxSize
- *     <li>If fileSize is smaller than minPartSize, then take the first provided
- *     upload URI to upload the entire binary, with partSize = fileSize</li>
+ *     <li>
+ *         If {@code (fileSize / maxPartSize) > numUploadURIs}, then the
+ *         client cannot proceed and will have to request a new set of URIs
+ *         with the right fileSize as {@code maxSize}
+ *     </li>
+ *     <li>
+ *         If {@code fileSize < minPartSize}, then take the first provided
+ *         upload URI to upload the entire binary, with
+ *         {@code partSize = fileSize}
+ *     </li>
  *     <li>
  *         (optional) If the client has more information to optimize, the
- *         partSize can be chosen, under the condition that all of these are
- *         true for the partSize:
+ *         {@code partSize} can be chosen, under the condition that all of these are
+ *         true:
  *         <ol>
- *             <li>larger than minPartSize
- *             <li>smaller or equal than maxPartSize (unless it is -1 =
- *             unlimited)
- *             <li>larger than fileSize divided by numUploadURIs
+ *             <li>{@code partSize >= minPartSize}</li>
+ *             <li>{@code partSize <= maxPartSize}
+ *             (unless {@code maxPartSize = -1} meaning unlimited)</li>
+ *             <li>{@code partSize > (fileSize / numUploadURIs)}</li>
  *         </ol>
  *     </li>
- *     <li>Otherwise all part URIs are to be used and the partSize = fileSize
- *     divided by numUploadURIs (integer division, discard modulo which will be
- *     the last part)
- *     <li>Upload: segment the binary into partSize, for each segment take the
- *     next URI from uploadURIs (strictly in order), proceed with a standard
- *     HTTP PUT for each (for "http(s)" URIs, otherwise currently unspecified),
- *     and for the last part use whatever segment size is left
- *     <li>If a segment fails during upload, retry (up to a certain time out)
- *     <li>After the upload has finished successfully, notify the application,
- *     for example through a complete request, passing the {@link
- *     #getUploadToken() upload token}, and the application will call {@link
- *     JackrabbitValueFactory#completeBinaryUpload(String)} with the token
+ *     <li>
+ *         Otherwise all part URIs are to be used. The {@code partSize}
+ *         to use for all parts except the last would be calculated using:
+ *         <pre>partSize = (fileSize + numUploadURIs - 1) / numUploadURIs</pre>
+ *     </li>
+ *     <li>
+ *         Upload: segment the binary into {@code partSize}, for each segment take the
+ *         next URI from {@code uploadURIs} (strictly in order), proceed with a standard
+ *         HTTP PUT for each, and for the last part use whatever segment size is left
+ *     </li>
+ *     <li>
+ *         If a segment fails during upload, retry (up to a certain timeout)
+ *     </li>
+ *     <li>
+ *         After the upload has finished successfully, notify the application,
+ *         for example through a complete request, passing the {@link
+ *         #getUploadToken() upload token}, and the application will call {@link
+ *         JackrabbitValueFactory#completeBinaryUpload(String)} with the token
+ *     </li>
  * </ol>
  *
- * <h2>JSON view</h2>
+ * <h2>Example JSON view</h2>
  *
  * A JSON representation of this interface as passed back to a remote client
  * might look like this:
+ * 
  * <pre>
  * {
  *     "uploadToken": "aaaa-bbbb-cccc-dddd-eeee-ffff-gggg-hhhh",
@@ -110,45 +136,64 @@ import org.osgi.annotation.versioning.Pr
  *     ]
  * }
  * </pre>
- * */
+ */
 @ProviderType
 public interface BinaryUpload {
     /**
-     * Returns an Iterable of URIs that can be used for uploading binary data
-     * directly to a storage location.  The first URI can be used for uploading
-     * binary data as a single entity, or multiple URIs can be used if the
-     * client wishes to do multi-part uploads.
-     * <p>
-     * Clients are not necessarily required to use all of the URIs provided.  A
-     * client may choose to use fewer, or even only one of the URIs.  However,
-     * regardless of the number of URIs used, they must be consumed in sequence.
+     * Returns a list of URIs that can be used for uploading binary data
+     * directly to a storage location in one or more parts.
+     *
+     * <p>
+     * Remote clients must support multi-part uploading as per the
+     * <a href="#upload.algorithm">upload algorithm</a> described above. Clients
+     * are not necessarily required to use all of the URIs provided. A client
+     * may choose to use fewer, or even only one of the URIs. However, it must
+     * always ensure the part size is between {@link #getMinPartSize()} and
+     * {@link #getMaxPartSize()}. These can reflect strict limitations of the
+     * storage provider.
+     *
+     * <p>
+     * Regardless of the number of URIs used, they must be consumed in sequence,
+     * without skipping any, and the order of parts the original binary is split
+     * into must correspond exactly with the order of URIs.
+     *
+     * <p>
      * For example, if a client wishes to upload a binary in three parts and
      * there are five URIs returned, the client must use the first URI to
      * upload the first part, the second URI to upload the second part, and
-     * the third URI to upload the third part.  The client is not required to
-     * use the fourth and fifth URIs.  However, using the second URI to upload
+     * the third URI to upload the third part. The client is not required to
+     * use the fourth and fifth URIs. However, using the second URI to upload
      * the third part may result in either an upload failure or a corrupted
      * upload; likewise, skipping the second URI to use subsequent URIs may
      * result in either an upload failure or a corrupted upload.
-     * <p>
-     * Clients should be aware that some storage providers have limitations on
-     * the minimum and maximum size of a binary payload for a single upload, so
-     * clients should take these limitations into account when deciding how many
-     * of the URIs to use.  Underlying implementations may also choose to
-     * enforce their own limitations.
+     *
      * <p>
      * While the API supports multi-part uploading via multiple upload URIs,
-     * implementations are not required to support multi-part uploading.  If the
+     * implementations are not required to support multi-part uploading. If the
      * underlying implementation does not support multi-part uploading, a single
      * URI will be returned regardless of the size of the data being uploaded.
+     *
      * <p>
-     * Some storage providers also support multi-part uploads by reusing a
-     * single URI multiple times, in which case the implementation may also
-     * return a single URI regardless of the size of the data being uploaded.
-     * <p>
-     * You should consult both the DataStore implementation documentation and
-     * the storage service provider documentation for details on such matters as
-     * multi-part upload support, upload minimum and maximum sizes, etc.
+     * <b>Security considerations:</b>
+     *
+     * <ul>
+     *     <li>
+     *         The URIs cannot be shared with other users. They must only be returned to
+     *         authenticated requests corresponding to this session user or trusted system
+     *         components.
+     *     </li>
+     *     <li>
+     *         The URIs must not be persisted for later use and will typically be time limited.
+     *     </li>
+     *     <li>
+     *         The URIs will only grant access to this particular binary.
+     *     </li>
+     *     <li>
+     *         The client cannot infer any semantics from the URI structure and path names.
+     *         It would typically include a cryptographic signature. Any change to the URIs will
+     *         likely result in a failing request.
+     *     </li>
+     * </ul>
      *
      * @return Iterable of URIs that can be used for uploading directly to a
      *         storage location.
@@ -157,54 +202,48 @@ public interface BinaryUpload {
     Iterable<URI> getUploadURIs();
 
     /**
-     * The smallest part size a client may upload for a multi-part upload, not
-     * counting the final part.  This is usually either a service provider or
-     * implementation limitation.
-     * <p>
-     * Note that the API offers no guarantees that uploading parts of this size
-     * can successfully complete the requested upload using the URIs provided
-     * via {@link #getUploadURIs()}.  In other words, clients wishing to perform
-     * a multi-part upload must split the upload into parts of at least this
-     * size, but the sizes may need to be larger in order to successfully
-     * complete the upload.
+     * Return the smallest possible part size in bytes. If a consumer wants to
+     * choose a custom part size, it cannot be smaller than this value. This
+     * does not apply to the final part. This value will be equal or larger than
+     * zero.
      *
-     * @return The smallest size acceptable for multi-part uploads.
+     * <p>
+     * Note that the API offers no guarantees that using this minimal part size
+     * is possible with the number of available {@link #getUploadURIs()}. This
+     * might not be the case if the binary is too large. Please refer to the
+     * <a href="#upload.algorithm">upload algorithm</a> for the correct use of
+     * this value.
+     *
+     * @return The smallest part size acceptable for multi-part uploads.
      */
     long getMinPartSize();
 
     /**
-     * The largest part size a client may upload for a multi-part upload.  This
-     * is usually either a service provider or implementation limitation.
+     * Return the largest possible part size in bytes. If a consumer wants to
+     * choose a custom part size, it cannot be larger than this value.
+     * If this returns -1, the maximum is unlimited.
+     *
      * <p>
-     * The API guarantees that a client can successfully complete a direct
-     * upload of the binary data of the requested size using the provided URIs
-     * by splitting the binary data into parts of the size returned by this
-     * method.
-     * <p>
-     * The client is not required to use part sizes of this size; smaller sizes
-     * may be used so long as they are at least as large as the size returned by
-     * {@link #getMinPartSize()}.
-     * <p>
-     * If the binary size specified by a client when calling {@link
-     * JackrabbitValueFactory#initiateBinaryUpload(long, int)} ends up being
-     * smaller than the actual size of the binary being uploaded, these API
-     * guarantees no longer apply, and it may not be possible to complete the
-     * upload using the URIs provided.  In such cases, the client should restart
-     * the transaction using the correct size.
+     * The API guarantees that a client can split the binary of the requested
+     * size using this maximum part size and there will be sufficient URIs
+     * available in {@link #getUploadURIs()}. Please refer to the
+     * <a href="#upload.algorithm">upload algorithm</a> for the correct use of
+     * this value.
      *
-     * @return The maximum size of an upload part for multi-part uploads.
+     * @return The maximum part size acceptable for multi-part uploads or -1
+     *         if there is no limit.
      */
     long getMaxPartSize();
 
     /**
-     * Returns the upload token to be used in a subsequent call to {@link
-     * JackrabbitValueFactory#completeBinaryUpload(String)}.  This upload token
-     * is used by the implementation to identify this upload.  Clients should
-     * treat the upload token as an immutable string, as the underlying
-     * implementation may choose to implement techniques to detect tampering and
-     * reject the upload if the token is modified.
+     * Returns a token identifying this upload. This is required to finalize the upload
+     * at the end by calling {@link JackrabbitValueFactory#completeBinaryUpload(String)}.
+     *
+     * <p>
+     * The format of this string is implementation-dependent. Implementations must ensure
+     * that clients cannot guess tokens for existing binaries.
      *
-     * @return This upload's unique upload token.
+     * @return A unique token identifying this upload.
      */
     @NotNull
     String getUploadToken();