Skip to content

Commit dc4b103

Browse files
authored
Merge pull request #485 from RachelTucker/4-0-JSDK-242
JSDK 242 fix for 4.0 branch
2 parents 480d9b3 + d3fad53 commit dc4b103

File tree

10 files changed

+207
-10
lines changed

10 files changed

+207
-10
lines changed

ds3-sdk-integration/src/test/java/com/spectralogic/ds3client/helpers/FileSystemHelper_Test.java

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@
1515

1616
package com.spectralogic.ds3client.helpers;
1717

18-
import org.slf4j.Logger;
19-
import org.slf4j.LoggerFactory;
20-
2118
import com.spectralogic.ds3client.Ds3Client;
19+
import com.spectralogic.ds3client.commands.decorators.PutFolderResponse;
2220
import com.spectralogic.ds3client.helpers.events.SameThreadEventRunner;
2321
import com.spectralogic.ds3client.integration.Util;
2422
import com.spectralogic.ds3client.integration.test.helpers.TempStorageIds;
@@ -31,6 +29,8 @@
3129
import org.junit.Before;
3230
import org.junit.BeforeClass;
3331
import org.junit.Test;
32+
import org.slf4j.Logger;
33+
import org.slf4j.LoggerFactory;
3434

3535
import java.io.BufferedReader;
3636
import java.io.IOException;
@@ -39,17 +39,15 @@
3939
import java.nio.file.Files;
4040
import java.nio.file.Path;
4141
import java.nio.file.Paths;
42-
import java.util.*;
42+
import java.util.ArrayList;
43+
import java.util.Arrays;
44+
import java.util.List;
45+
import java.util.UUID;
4346
import java.util.concurrent.atomic.AtomicInteger;
4447
import java.util.concurrent.atomic.AtomicLong;
4548

4649
import static com.spectralogic.ds3client.integration.Util.deleteAllContents;
47-
48-
import static org.junit.Assert.assertEquals;
49-
import static org.junit.Assert.assertTrue;
50-
import static org.junit.Assert.assertFalse;
51-
import static org.junit.Assert.assertNull;
52-
import static org.junit.Assert.assertNotNull;
50+
import static org.junit.Assert.*;
5351

5452
public class FileSystemHelper_Test {
5553
private static final Logger LOG = LoggerFactory.getLogger(FileSystemHelper_Test.class);
@@ -313,4 +311,28 @@ public long getAvailableFileSpace(final Path path) throws IOException {
313311
throw new IOException("IOExceptionAtor");
314312
}
315313
}
314+
315+
@Test
316+
public void createFolderWithSlash() throws IOException {
317+
final String folderName = "FolderNameWithSlash/";
318+
319+
try {
320+
final PutFolderResponse response = HELPERS.createFolder(BUCKET_NAME, folderName);
321+
assertNotNull(response);
322+
} finally {
323+
deleteAllContents(client, BUCKET_NAME);
324+
}
325+
}
326+
327+
@Test
328+
public void createFolderWithNoSlash() throws IOException {
329+
final String folderName = "FolderNameNoSlash";
330+
331+
try {
332+
final PutFolderResponse response = HELPERS.createFolder(BUCKET_NAME, folderName);
333+
assertNotNull(response);
334+
} finally {
335+
deleteAllContents(client, BUCKET_NAME);
336+
}
337+
}
316338
}

ds3-sdk-integration/src/test/java/com/spectralogic/ds3client/integration/Smoke_Test.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515

1616
package com.spectralogic.ds3client.integration;
1717

18+
import com.google.common.collect.ImmutableList;
1819
import com.google.common.collect.ImmutableMap;
1920
import com.google.common.collect.Iterables;
2021
import com.google.common.collect.Lists;
2122
import com.spectralogic.ds3client.Ds3Client;
2223
import com.spectralogic.ds3client.commands.*;
24+
import com.spectralogic.ds3client.commands.decorators.PutFolderRequest;
25+
import com.spectralogic.ds3client.commands.decorators.PutFolderResponse;
2326
import com.spectralogic.ds3client.commands.interfaces.BulkResponse;
2427
import com.spectralogic.ds3client.commands.spectrads3.*;
2528
import com.spectralogic.ds3client.helpers.*;
@@ -1656,4 +1659,21 @@ public void testGetObjectsWithFullDetails() throws IOException, URISyntaxExcepti
16561659
deleteAllContents(client, bucketName);
16571660
}
16581661
}
1662+
1663+
@Test
1664+
public void createFolderWithSlash() throws IOException {
1665+
final String folderName = "FolderNameWithSlash/";
1666+
final String bucketName = "FolderNameWithSlashTestBucket";
1667+
1668+
try {
1669+
HELPERS.ensureBucketExists(bucketName, envDataPolicyId);
1670+
final Ds3Object ds3Object = new Ds3Object(folderName, 0);
1671+
final PutBulkJobSpectraS3Response jobResponse = client.putBulkJobSpectraS3(new PutBulkJobSpectraS3Request(bucketName, ImmutableList.of(ds3Object)));
1672+
1673+
final PutFolderResponse response = client.putFolder(new PutFolderRequest(bucketName, folderName, jobResponse.getMasterObjectList().getJobId()));
1674+
assertNotNull(response);
1675+
} finally {
1676+
deleteAllContents(client, bucketName);
1677+
}
1678+
}
16591679
}

ds3-sdk/src/main/java/com/spectralogic/ds3client/Ds3Client.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import com.spectralogic.ds3client.annotations.Resource;
2121
import com.spectralogic.ds3client.annotations.ResponsePayloadModel;
2222
import com.spectralogic.ds3client.commands.*;
23+
import com.spectralogic.ds3client.commands.decorators.PutFolderRequest;
24+
import com.spectralogic.ds3client.commands.decorators.PutFolderResponse;
2325
import com.spectralogic.ds3client.commands.spectrads3.*;
2426
import com.spectralogic.ds3client.commands.spectrads3.notifications.*;
2527
import com.spectralogic.ds3client.models.JobNode;
@@ -35,6 +37,8 @@ public interface Ds3Client extends Closeable {
3537

3638
ConnectionDetails getConnectionDetails();
3739

40+
PutFolderResponse putFolder(final PutFolderRequest request)
41+
throws IOException;
3842

3943

4044
AbortMultiPartUploadResponse abortMultiPartUpload(final AbortMultiPartUploadRequest request)

ds3-sdk/src/main/java/com/spectralogic/ds3client/Ds3ClientImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.io.IOException;
2020
import com.spectralogic.ds3client.commands.*;
21+
import com.spectralogic.ds3client.commands.decorators.PutFolderRequest;
22+
import com.spectralogic.ds3client.commands.decorators.PutFolderResponse;
2123
import com.spectralogic.ds3client.commands.parsers.*;
2224
import com.spectralogic.ds3client.commands.spectrads3.*;
2325
import com.spectralogic.ds3client.commands.spectrads3.notifications.*;
@@ -45,6 +47,12 @@ public ConnectionDetails getConnectionDetails() {
4547
return this.netClient.getConnectionDetails();
4648
}
4749

50+
@Override
51+
public PutFolderResponse putFolder(final PutFolderRequest request) throws IOException {
52+
final PutObjectResponse response = putObject(request.getPutObjectRequest());
53+
return new PutFolderResponse(response);
54+
}
55+
4856
@Override
4957
public AbortMultiPartUploadResponse abortMultiPartUpload(final AbortMultiPartUploadRequest request) throws IOException {
5058
return new AbortMultiPartUploadResponseParser().response(this.netClient.getResponse(request));
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* ******************************************************************************
3+
* Copyright 2014-2017 Spectra Logic Corporation. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the "license" file accompanying this file.
10+
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
* ****************************************************************************
14+
*/
15+
16+
package com.spectralogic.ds3client.commands.decorators;
17+
18+
import com.spectralogic.ds3client.commands.PutObjectRequest;
19+
import com.spectralogic.ds3client.exceptions.FolderNameMissingTrailingForwardSlash;
20+
21+
import java.util.UUID;
22+
23+
/**
24+
* Decorates the {@link com.spectralogic.ds3client.commands.PutObjectRequest} and is used to
25+
* ensure the correct creation of a folder using the Put Object command.
26+
*
27+
* A folder is created by putting an object with no content, of zero size, and with the
28+
* content-length=0. Also, the name of the folder must end with a forward slash '/'.
29+
*/
30+
public class PutFolderRequest {
31+
32+
private final PutObjectRequest putObjectRequest;
33+
34+
public PutFolderRequest(final String bucketName, final String folderName, final UUID job) {
35+
validateNameEndsWithSlash(folderName);
36+
putObjectRequest = new PutObjectRequest(bucketName, folderName, job, 0, 0, null);
37+
putObjectRequest.getHeaders().put("Content-Length", "0");
38+
}
39+
40+
private static void validateNameEndsWithSlash(final String folderName) {
41+
if (!folderName.endsWith("/")) {
42+
throw new FolderNameMissingTrailingForwardSlash(folderName);
43+
}
44+
}
45+
46+
public PutObjectRequest getPutObjectRequest() {
47+
return putObjectRequest;
48+
}
49+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* ******************************************************************************
3+
* Copyright 2014-2017 Spectra Logic Corporation. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the "license" file accompanying this file.
10+
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
* ****************************************************************************
14+
*/
15+
16+
package com.spectralogic.ds3client.commands.decorators;
17+
18+
import com.spectralogic.ds3client.commands.PutObjectResponse;
19+
20+
/**
21+
* Decorates the {@link com.spectralogic.ds3client.commands.PutObjectResponse} and is used
22+
* by command {@link com.spectralogic.ds3client.Ds3Client#putFolder(PutFolderRequest)}
23+
*/
24+
public class PutFolderResponse extends PutObjectResponse {
25+
26+
public PutFolderResponse(final PutObjectResponse response) {
27+
super(response.getChecksum(), response.getChecksumType());
28+
}
29+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* ******************************************************************************
3+
* Copyright 2014-2017 Spectra Logic Corporation. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the "license" file accompanying this file.
10+
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
* ****************************************************************************
14+
*/
15+
16+
package com.spectralogic.ds3client.exceptions;
17+
18+
/**
19+
* Denotes an invalid folder name. Folder names must end with a forward slash '/'.
20+
*/
21+
public class FolderNameMissingTrailingForwardSlash extends IllegalArgumentException {
22+
23+
public FolderNameMissingTrailingForwardSlash(final String folderName) {
24+
super("Invalid folder name '" + folderName + "': folder names must end with a forward slash '/'.");
25+
}
26+
}

ds3-sdk/src/main/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpers.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.common.base.Function;
1919
import com.google.common.collect.FluentIterable;
2020
import com.spectralogic.ds3client.Ds3Client;
21+
import com.spectralogic.ds3client.commands.decorators.PutFolderResponse;
2122
import com.spectralogic.ds3client.helpers.options.ReadJobOptions;
2223
import com.spectralogic.ds3client.helpers.options.WriteJobOptions;
2324
import com.spectralogic.ds3client.helpers.strategy.transferstrategy.TransferStrategy;
@@ -580,4 +581,9 @@ public static String stripLeadingPath(final String objectName, final String pref
580581
public abstract ObjectStorageSpaceVerificationResult objectsFromBucketWillFitInDirectory(final String bucketName,
581582
final Collection<String> objectNames,
582583
final Path destinationDirectory);
584+
585+
/**
586+
* Creates a folder in the specified bucket
587+
*/
588+
public abstract PutFolderResponse createFolder(final String bucketName, final String folderName) throws IOException;
583589
}

ds3-sdk/src/main/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpersImpl.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.spectralogic.ds3client.commands.HeadBucketRequest;
2626
import com.spectralogic.ds3client.commands.HeadBucketResponse;
2727
import com.spectralogic.ds3client.commands.PutBucketRequest;
28+
import com.spectralogic.ds3client.commands.decorators.PutFolderRequest;
29+
import com.spectralogic.ds3client.commands.decorators.PutFolderResponse;
2830
import com.spectralogic.ds3client.commands.spectrads3.*;
2931
import com.spectralogic.ds3client.helpers.events.EventRunner;
3032
import com.spectralogic.ds3client.helpers.events.SameThreadEventRunner;
@@ -593,4 +595,28 @@ public ObjectStorageSpaceVerificationResult objectsFromBucketWillFitInDirectory(
593595
return fileSystemHelper.objectsFromBucketWillFitInDirectory(this,
594596
bucketName, objectNames, destinationDirectory);
595597
}
598+
599+
/**
600+
* Creates a folder in the specified bucket.
601+
*/
602+
@Override
603+
public PutFolderResponse createFolder(final String bucketName, final String folderName) throws IOException {
604+
final String normalizedFolderName = ensureNameEndsWithSlash(folderName);
605+
final Ds3Object ds3Object = new Ds3Object(normalizedFolderName, 0);
606+
final PutBulkJobSpectraS3Response jobResponse = client
607+
.putBulkJobSpectraS3(new PutBulkJobSpectraS3Request(bucketName, ImmutableList.of(ds3Object)));
608+
609+
return client.putFolder(new PutFolderRequest(bucketName, normalizedFolderName, jobResponse.getMasterObjectList().getJobId()));
610+
}
611+
612+
/**
613+
* Ensures that a folder names ends with a trailing forward slash. This prevents the
614+
* accidental creation of zero-length files when attempting to create a folder.
615+
*/
616+
private static String ensureNameEndsWithSlash(final String folderName) {
617+
if (folderName.endsWith("/")) {
618+
return folderName;
619+
}
620+
return folderName + "/";
621+
}
596622
}

ds3-sdk/src/test/java/com/spectralogic/ds3client/Ds3Client_Test.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import com.google.common.collect.Multimap;
2121
import com.google.common.collect.TreeMultimap;
2222
import com.spectralogic.ds3client.commands.*;
23+
import com.spectralogic.ds3client.commands.decorators.PutFolderRequest;
2324
import com.spectralogic.ds3client.commands.spectrads3.*;
2425
import com.spectralogic.ds3client.exceptions.ContentLengthNotMatchException;
26+
import com.spectralogic.ds3client.exceptions.FolderNameMissingTrailingForwardSlash;
2527
import com.spectralogic.ds3client.models.*;
2628
import com.spectralogic.ds3client.models.Objects;
2729
import com.spectralogic.ds3client.models.bulk.Ds3Object;
@@ -1136,4 +1138,9 @@ public void getObjectVerifyFullPayload() throws IOException {
11361138
jobIdString,
11371139
0));
11381140
}
1141+
1142+
@Test (expected = FolderNameMissingTrailingForwardSlash.class)
1143+
public void createFolderWithNoSlash() throws IOException {
1144+
new PutFolderRequest("BucketName", "FolderNameNoSlash", UUID.randomUUID());
1145+
}
11391146
}

0 commit comments

Comments
 (0)