Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codegen.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "engineHash": "04310d4", "specHash": "88cd5aa", "version": "10.16.2" }
{ "engineHash": "bcfc85f", "specHash": "88cd5aa", "version": "10.16.2" }
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}"
implementation "com.squareup.okio:okio:${okioVersion}"
implementation "org.bitbucket.b_c:jose4j:${jose4jVersion}"
implementation "commons-codec:commons-codec:${commonsCodecVersion}"
implementation "org.bouncycastle:bcprov-jdk18on:${bouncyCastleBcprovJdk18onVersion}"
implementation "org.bouncycastle:bcpkix-jdk18on:${bouncyCastleBcpkixJdk18onVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitApiVersion}"
Expand Down
12 changes: 9 additions & 3 deletions docs/chunkeduploads.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ This operation is performed by calling function `createFileUploadSessionForExist
See the endpoint docs at
[API Reference](https://developer.box.com/reference/post-files-id-upload-sessions/).

*Currently we don't have an example for calling `createFileUploadSessionForExistingFile` in integration tests*
<!-- sample post_files_id_upload_sessions -->
```
client.getChunkedUploads().createFileUploadSessionForExistingFile(uploadedFile.getId(), new CreateFileUploadSessionForExistingFileRequestBody(fileSize))
```

### Arguments

Expand Down Expand Up @@ -357,7 +360,10 @@ This operation is performed by calling function `createFileUploadSessionPlanByUr
See the endpoint docs at
[API Reference](https://developer.box.com/reference/post-files-upload-sessions-id-plan/).

*Currently we don't have an example for calling `createFileUploadSessionPlanByUrl` in integration tests*
<!-- sample post_files_upload_sessions_id_plan -->
```
client.getChunkedUploads().createFileUploadSessionPlanByUrl(planUrl, new UploadSessionPlanRequest(parts))
```

### Arguments

Expand Down Expand Up @@ -496,7 +502,7 @@ This operation is performed by calling function `uploadBigFile`.


```
client.getChunkedUploads().uploadBigFile(fileByteStream, fileName, fileSize, parentFolderId)
client.getChunkedUploads().uploadBigFile(generateByteStreamFromBuffer(fileBuffer), fileName, fileSize, parentFolderId)
```

### Arguments
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ jacksonDatabindVersion=2.21.4
okhttpVersion=4.12.0
okioVersion=3.5.0
jose4jVersion=0.9.6
commonsCodecVersion=1.22.0
bouncyCastleBcprovJdk18onVersion=1.85
bouncyCastleBcpkixJdk18onVersion=1.85
junitApiVersion=5.10.0
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/com/box/sdkgen/internal/utils/Hash.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import org.apache.commons.codec.binary.Hex;

public class Hash {

Expand All @@ -13,7 +14,7 @@ public class Hash {
public Hash(HashName algorithm) {
this.algorithm = algorithm;
try {
this.digest = MessageDigest.getInstance(algorithm.getValue());
this.digest = MessageDigest.getInstance(getAlgorithmName(algorithm));
} catch (NoSuchAlgorithmException ae) {
throw new BoxSDKError("Digest algorithm not found", ae);
}
Expand All @@ -25,10 +26,24 @@ public void updateHash(byte[] data) {

public String digestHash(String encoding) {
byte[] digestBytes = digest.digest();
if ("hex".equals(encoding)) {
return Hex.encodeHexString(digestBytes);
}
return Base64.getEncoder().encodeToString(digestBytes);
}

public HashName getAlgorithm() {
return algorithm;
}

private static String getAlgorithmName(HashName algorithm) {
switch (algorithm) {
case SHA1:
return "SHA-1";
case SHA512:
return "SHA-512";
default:
throw new BoxSDKError("Digest algorithm not supported");
}
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/box/sdkgen/internal/utils/HashName.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import com.box.sdkgen.serialization.json.Valuable;

public enum HashName implements Valuable {
SHA1("sha1");
SHA1("sha1"),
SHA512("sha512");

private final String value;

Expand Down
12 changes: 9 additions & 3 deletions src/main/java/com/box/sdkgen/internal/utils/UtilsManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
Expand All @@ -42,6 +42,8 @@
import java.util.stream.Collectors;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.NumericDate;
Expand Down Expand Up @@ -150,7 +152,7 @@ public static String getUuid() {

public static byte[] generateByteBuffer(int size) {
byte[] bytes = new byte[size];
Arrays.fill(bytes, (byte) 0);
new SecureRandom().nextBytes(bytes);
return bytes;
}

Expand Down Expand Up @@ -306,7 +308,11 @@ public static double random(double min, double max) {
}

public static String hexToBase64(String hex) {
return Base64.getEncoder().encodeToString(new BigInteger(hex, 16).toByteArray());
try {
return Base64.getEncoder().encodeToString(Hex.decodeHex(hex));
} catch (DecoderException e) {
throw new BoxSDKError("Error decoding hex string.", e);
}
}

public static Iterator<InputStream> iterateChunks(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.box.sdkgen.commons.CommonsManager.getDefaultClient;
import static com.box.sdkgen.internal.utils.UtilsManager.bufferLength;
import static com.box.sdkgen.internal.utils.UtilsManager.convertToString;
import static com.box.sdkgen.internal.utils.UtilsManager.delayInSeconds;
import static com.box.sdkgen.internal.utils.UtilsManager.generateByteStream;
import static com.box.sdkgen.internal.utils.UtilsManager.generateByteStreamFromBuffer;
import static com.box.sdkgen.internal.utils.UtilsManager.getUuid;
Expand All @@ -18,15 +19,20 @@
import com.box.sdkgen.managers.chunkeduploads.CreateFileUploadSessionCommitByUrlRequestBody;
import com.box.sdkgen.managers.chunkeduploads.CreateFileUploadSessionCommitHeaders;
import com.box.sdkgen.managers.chunkeduploads.CreateFileUploadSessionCommitRequestBody;
import com.box.sdkgen.managers.chunkeduploads.CreateFileUploadSessionForExistingFileRequestBody;
import com.box.sdkgen.managers.chunkeduploads.CreateFileUploadSessionRequestBody;
import com.box.sdkgen.managers.chunkeduploads.UploadFilePartByUrlHeaders;
import com.box.sdkgen.managers.chunkeduploads.UploadFilePartHeaders;
import com.box.sdkgen.schemas.file.File;
import com.box.sdkgen.schemas.files.Files;
import com.box.sdkgen.schemas.uploadedpart.UploadedPart;
import com.box.sdkgen.schemas.uploadpart.UploadPart;
import com.box.sdkgen.schemas.uploadpartplan.UploadPartPlan;
import com.box.sdkgen.schemas.uploadpartplanhit.UploadPartPlanHit;
import com.box.sdkgen.schemas.uploadparts.UploadParts;
import com.box.sdkgen.schemas.uploadsession.UploadSession;
import com.box.sdkgen.schemas.uploadsessionplanrequest.UploadSessionPlanRequest;
import com.box.sdkgen.schemas.uploadsessionplanresponse.UploadSessionPlanResponse;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -126,6 +132,24 @@ public static TestPartAccumulator reducerByUrl(TestPartAccumulator acc, InputStr
.build();
}

public static TestPartPlanAccumulator reducerForUploadSessionPlan(
TestPartPlanAccumulator acc, InputStream chunk) {
int lastIndex = acc.getLastIndex();
List<UploadPartPlan> parts = acc.getParts();
byte[] chunkBuffer = readByteStream(chunk);
Hash hash = new Hash(HashName.SHA512);
hash.updateHash(chunkBuffer);
String sha512 = hash.digestHash("hex");
int chunkSize = bufferLength(chunkBuffer);
int bytesStart = lastIndex + 1;
int bytesEnd = lastIndex + chunkSize;
UploadPartPlan part = new UploadPartPlan(bytesStart, chunkSize, sha512);
return new TestPartPlanAccumulator(
bytesEnd,
Stream.concat(parts.stream(), Arrays.asList(part).stream()).collect(Collectors.toList()),
acc.getFileSize());
}

@Test
public void testChunkedManualProcessById() {
int fileSize = 20 * 1024 * 1024;
Expand Down Expand Up @@ -221,6 +245,55 @@ public void testChunkedManualProcessByUrl() {
client.getChunkedUploads().deleteFileUploadSessionByUrl(abortUrl);
}

@Test
public void testUploadSessionPlan() {
int fileSize = 20 * 1024 * 1024;
String fileName = getUuid();
String parentFolderId = "0";
InputStream fileContentStream = generateByteStream(fileSize);
byte[] fileBuffer = readByteStream(fileContentStream);
File uploadedFile =
client
.getChunkedUploads()
.uploadBigFile(
generateByteStreamFromBuffer(fileBuffer), fileName, fileSize, parentFolderId);
delayInSeconds(5);
UploadSession uploadSession =
client
.getChunkedUploads()
.createFileUploadSessionForExistingFile(
uploadedFile.getId(),
new CreateFileUploadSessionForExistingFileRequestBody(fileSize));
String uploadSessionId = uploadSession.getId();
String planUrl = uploadSession.getSessionEndpoints().getPlan();
long partSize = uploadSession.getPartSize();
int totalParts = uploadSession.getTotalParts();
Iterator<InputStream> chunksIterator =
iterateChunks(generateByteStreamFromBuffer(fileBuffer), partSize, fileSize);
TestPartPlanAccumulator results =
reduceIterator(
chunksIterator,
(TestPartPlanAccumulator acc, InputStream chunk) ->
reducerForUploadSessionPlan(acc, chunk),
new TestPartPlanAccumulator(-1, Collections.emptyList(), fileSize));
List<UploadPartPlan> parts = results.getParts();
UploadSessionPlanResponse plan =
client
.getChunkedUploads()
.createFileUploadSessionPlanByUrl(planUrl, new UploadSessionPlanRequest(parts));
assert plan.getUploadSessionId().equals(uploadSessionId);
assert plan.getHits().size() == totalParts;
assert plan.getMisses().size() == 0;
UploadPartPlan firstPart = parts.get(0);
UploadPartPlanHit firstHit = plan.getHits().get(0);
assert firstHit.getOffset() == firstPart.getOffset();
assert firstHit.getSize() == firstPart.getSize();
assert firstHit.getSha512().equals(firstPart.getSha512());
assert !(firstHit.getPartId().equals(""));
client.getChunkedUploads().deleteFileUploadSessionById(uploadSessionId);
client.getFiles().deleteFileById(uploadedFile.getId());
}

@Test
public void testChunkedUploadConvenienceMethod() {
int fileSize = 20 * 1024 * 1024;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.box.sdkgen.chunkeduploads;

import com.box.sdkgen.schemas.uploadpartplan.UploadPartPlan;
import java.util.List;

public class TestPartPlanAccumulator {

public final int lastIndex;

public final List<UploadPartPlan> parts;

public final long fileSize;

public TestPartPlanAccumulator(int lastIndex, List<UploadPartPlan> parts, long fileSize) {
this.lastIndex = lastIndex;
this.parts = parts;
this.fileSize = fileSize;
}

public int getLastIndex() {
return lastIndex;
}

public List<UploadPartPlan> getParts() {
return parts;
}

public long getFileSize() {
return fileSize;
}
}
Loading