├── src ├── docs │ ├── usage-001.md │ ├── gui.md │ ├── test-important.md.templar │ └── usage-002.md ├── main │ └── java │ │ └── synapticloop │ │ └── b2 │ │ ├── io │ │ ├── package-info.java │ │ └── HttpMethodReleaseInputStream.java │ │ ├── package-info.java │ │ ├── util │ │ ├── package-info.java │ │ ├── URLEncoder.java │ │ └── ChecksumHelper.java │ │ ├── exception │ │ ├── package-info.java │ │ └── B2ApiException.java │ │ ├── response │ │ ├── package-info.java │ │ ├── B2ResponseHeaders.java │ │ ├── B2ListPartsResponse.java │ │ ├── B2ListBucketsResponse.java │ │ ├── B2DeleteFileVersionResponse.java │ │ ├── B2GetDownloadAuthorizationResponse.java │ │ ├── B2ResponseProperties.java │ │ ├── B2GetUploadUrlResponse.java │ │ ├── B2GetUploadPartUrlResponse.java │ │ ├── B2StartLargeFileResponse.java │ │ ├── B2UploadPartResponse.java │ │ ├── B2ListFilesResponse.java │ │ ├── B2HideFileResponse.java │ │ ├── B2FinishLargeFileResponse.java │ │ ├── B2AuthorizeAccountResponse.java │ │ ├── B2BucketResponse.java │ │ ├── B2FileInfoResponse.java │ │ └── B2FileResponse.java │ │ ├── request │ │ ├── package-info.java │ │ ├── B2CancelLargeFileRequest.java │ │ ├── B2RequestProperties.java │ │ ├── B2ListBucketsRequest.java │ │ ├── B2GetDownloadAuthorizationRequest.java │ │ ├── B2FinishLargeFileRequest.java │ │ ├── B2HideFileRequest.java │ │ ├── B2GetFileInfoRequest.java │ │ ├── B2DeleteBucketRequest.java │ │ ├── B2UploadPartRequest.java │ │ ├── B2GetUploadUrlRequest.java │ │ ├── B2GetUploadPartUrlRequest.java │ │ ├── B2ListUnfinishedLargeFilesRequest.java │ │ ├── B2ListPartsRequest.java │ │ ├── B2DeleteFileVersionRequest.java │ │ ├── B2AuthorizeAccountRequest.java │ │ ├── B2UpdateBucketRequest.java │ │ ├── B2HeadFileByIdRequest.java │ │ ├── B2CreateBucketRequest.java │ │ ├── B2StartLargeFileRequest.java │ │ ├── B2DownloadFileByNameRequest.java │ │ └── B2DownloadFileByIdRequest.java │ │ ├── BucketType.java │ │ └── Action.java └── test │ ├── resources │ └── log4j2.xml │ └── java │ └── synapticloop │ └── b2 │ ├── request │ ├── B2GetUploadUrlRequestTest.java │ ├── B2ListFileNamesRequestTest.java │ ├── B2ListUnfinishedLargeFilesRequestTest.java │ ├── B2HeadFileRequestTest.java │ ├── B2UpdateBucketRequestTest.java │ ├── B2GetFileInfoRequestTest.java │ ├── B2ListBucketsRequestTest.java │ ├── B2AuthorizeAccountRequestTest.java │ ├── B2CreateAndDeleteBucketRequestTest.java │ ├── B2HideFileRequestTest.java │ ├── B2StartLargeFileRequestTest.java │ ├── B2DeleteFileVersionRequestTest.java │ ├── B2UploadPartRequestTest.java │ ├── B2DownloadFileRequestTest.java │ ├── B2UploadAndDeleteFileRequestTest.java │ └── B2ListFileVersionsRequestTest.java │ ├── QuickExampleMain.java │ ├── exception │ └── B2ApiExceptionTest.java │ ├── response │ ├── B2FileInfoResponseTest.java │ └── B2ListFilesResponseTest.java │ ├── B2ApiClientTest.java │ └── DeleteTestBuckets.java ├── settings.gradle ├── CONTRIBUTORS.txt ├── .travis.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── LICENSE.txt ├── documentr.json ├── gradlew.bat └── gradlew /src/docs/usage-001.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ``` 4 | 5 | 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'backblaze-b2-java-api' 2 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | iterate GmbH (https://github.com/iterate-ch/backblaze-b2-java-api/) -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | script: ./gradlew --info build 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/synapticloop/backblaze-b2-java-api/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/io/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains input-output utilities 3 | * 4 | * @author synapticloop 5 | * 6 | */ 7 | package synapticloop.b2.io; -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains the B2 API Client and enums 3 | * 4 | * @author synapticloop 5 | * 6 | */ 7 | package synapticloop.b2; -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/util/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains helper classes 3 | * 4 | * @author synapticloop 5 | * 6 | */ 7 | package synapticloop.b2.util; -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/exception/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains the B2ApiException 3 | * 4 | * @author synapticloop 5 | * 6 | */ 7 | package synapticloop.b2.exception; -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains the responses to the B2 Api calls 3 | * 4 | * @author synapticloop 5 | * 6 | */ 7 | package synapticloop.b2.response; -------------------------------------------------------------------------------- /src/docs/gui.md: -------------------------------------------------------------------------------- 1 | # Just looking for a GUI? 2 | 3 | We thoroughly recommend either [cyberduck](https://cyberduck.io/) or [mountainduck](https://mountainduck.io/) which includes this code for the awesome BackBlaze storage service. 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 02 08:37:26 BST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip 7 | -------------------------------------------------------------------------------- /src/docs/test-important.md.templar: -------------------------------------------------------------------------------- 1 | {\n} 2 | **!!! IMPORTANT !!!** {\n} 3 | {\n} 4 | You **MUST** have the following environment variables set:{\n} 5 | {\n} 6 | ```{\n} 7 | export B2_ACCOUNT_ID="your-account-id"{\n} 8 | export B2_APPLICATION_KEY="your-application-key"{\n} 9 | ```{\n} 10 | {\n} 11 | -------------------------------------------------------------------------------- /src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains the lower level interfaces to the API request mechanism. 3 | * 4 | * Each request utilises one or more of the following data structures stored in 5 | * the {@link synapticloop.b2.request.BaseB2Request} object: 6 | * 7 | * 22 | * 23 | * @author synapticloop 24 | * 25 | */ 26 | package synapticloop.b2.request; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/gradle,eclipse 2 | api-docs 3 | 4 | ### Gradle ### 5 | .gradle 6 | build/ 7 | 8 | # Ignore Gradle GUI config 9 | gradle-app.setting 10 | 11 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 12 | !gradle-wrapper.jar 13 | 14 | 15 | ### Eclipse ### 16 | *.pydevproject 17 | .metadata 18 | bin/ 19 | tmp/ 20 | *.tmp 21 | *.bak 22 | *.swp 23 | *~.nib 24 | local.properties 25 | .settings/ 26 | .loadpath 27 | 28 | # Eclipse Core 29 | .project 30 | 31 | # External tool builders 32 | .externalToolBuilders/ 33 | 34 | # Locally stored "Eclipse launch configurations" 35 | *.launch 36 | 37 | # CDT-specific 38 | .cproject 39 | 40 | # JDT-specific (Eclipse Java Development Tools) 41 | .classpath 42 | 43 | # Java annotation processor (APT) 44 | .factorypath 45 | 46 | # PDT-specific 47 | .buildpath 48 | 49 | # sbteclipse plugin 50 | .target 51 | 52 | # TeXlipse plugin 53 | .texlipse 54 | 55 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/BucketType.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | /** 20 | * The type of bucket, either allPrivate, or allPublic 21 | * 22 | * @author synapticloop 23 | */ 24 | public enum BucketType { 25 | allPublic, 26 | allPrivate, 27 | snapshot 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2GetUploadUrlRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.apache.http.impl.client.HttpClients; 6 | import org.junit.Test; 7 | 8 | import synapticloop.b2.helper.B2TestHelper; 9 | import synapticloop.b2.response.B2BucketResponse; 10 | import synapticloop.b2.response.B2GetUploadUrlResponse; 11 | 12 | public class B2GetUploadUrlRequestTest { 13 | 14 | @Test 15 | public void testGetUploadUrl() throws Exception { 16 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 17 | 18 | B2GetUploadUrlResponse response = new B2GetUploadUrlRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), privateBucket.getBucketId()).getResponse(); 19 | 20 | assertNotNull(response.getAuthorizationToken()); 21 | assertEquals(privateBucket.getBucketId(), response.getBucketId()); 22 | assertNotNull(response.getBucketId()); 23 | assertNotNull(response.getUploadUrl()); 24 | 25 | B2TestHelper.deleteBucket(privateBucket.getBucketId()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2ListFileNamesRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.apache.http.impl.client.HttpClients; 6 | import org.junit.Test; 7 | 8 | import synapticloop.b2.helper.B2TestHelper; 9 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 10 | import synapticloop.b2.response.B2BucketResponse; 11 | import synapticloop.b2.response.B2ListFilesResponse; 12 | 13 | public class B2ListFileNamesRequestTest { 14 | 15 | @Test 16 | public void testListEmptyBucket() throws Exception { 17 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 18 | B2BucketResponse b2BucketResponse = B2TestHelper.createRandomPrivateBucket(); 19 | 20 | B2ListFilesResponse b2ListFilesResponse = new B2ListFileNamesRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, b2BucketResponse.getBucketId()).getResponse(); 21 | 22 | assertNull(b2ListFilesResponse.getNextFileId()); 23 | assertNull(b2ListFilesResponse.getNextFileName()); 24 | 25 | B2TestHelper.deleteBucket(b2BucketResponse.getBucketId()); 26 | } 27 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Synapticloop 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/QuickExampleMain.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import synapticloop.b2.exception.B2ApiException; 7 | import synapticloop.b2.response.B2BucketResponse; 8 | 9 | public class QuickExampleMain { 10 | 11 | public static void main(String[] args) throws B2ApiException, IOException { 12 | String b2AccountId = ""; // your b2 account ID 13 | String b2ApplicationKey = ""; // your b2 application Key 14 | 15 | try { 16 | B2ApiClient b2ApiClient = new B2ApiClient(); 17 | b2ApiClient.authenticate(b2AccountId, b2ApplicationKey); 18 | 19 | // now create a private bucket 20 | B2BucketResponse createPrivateBucket = b2ApiClient.createBucket("super-secret-bucket" , BucketType.allPrivate); 21 | 22 | // or a public one 23 | B2BucketResponse createPublicBucket = b2ApiClient.createBucket("everyone-has-access" , BucketType.allPublic); 24 | 25 | // upload a file to the private bucket 26 | b2ApiClient.uploadFile(createPrivateBucket.getBucketId(), "myfile.txt", new File("/tmp/temporary-file.txt")); 27 | 28 | } catch(B2ApiException | IOException ex) { 29 | ex.printStackTrace(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/exception/B2ApiExceptionTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.exception; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | public class B2ApiExceptionTest { 8 | 9 | @Test 10 | public void testEmptyException() { 11 | B2ApiException b2Exception = new B2ApiException("", new RuntimeException()); 12 | assertEquals("", b2Exception.getMessage()); 13 | } 14 | 15 | @Test 16 | public void testNullResponseException() { 17 | B2ApiException b2Exception = new B2ApiException(null, new RuntimeException()); 18 | assertEquals(null, b2Exception.getMessage()); 19 | } 20 | 21 | @Test 22 | public void testJsonException() { 23 | B2ApiException b2Exception = new B2ApiException("{\n" + 24 | " \"code\": \"bad_json\",\n" + 25 | " \"message\": \"unknown field in com.backblaze.modules.b2.data.FileNameAndId: accountId\",\n" + 26 | " \"status\": 400\n" + 27 | " }\n" + 28 | ")", new RuntimeException()); 29 | assertEquals(400, b2Exception.getStatus()); 30 | assertEquals("bad_json", b2Exception.getCode()); 31 | assertEquals("unknown field in com.backblaze.modules.b2.data.FileNameAndId: accountId", b2Exception.getMessage()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2ListUnfinishedLargeFilesRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import org.apache.http.impl.client.HttpClients; 4 | import org.junit.Test; 5 | import synapticloop.b2.helper.B2TestHelper; 6 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 7 | import synapticloop.b2.response.B2BucketResponse; 8 | import synapticloop.b2.response.B2ListFilesResponse; 9 | 10 | import static org.junit.Assert.assertNull; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class B2ListUnfinishedLargeFilesRequestTest { 14 | 15 | @Test 16 | public void getResponse() throws Exception { 17 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 18 | 19 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 20 | 21 | String privateBucketId = privateBucket.getBucketId(); 22 | final B2ListFilesResponse b2ListFilesResponse = new B2ListUnfinishedLargeFilesRequest(HttpClients.createDefault(), 23 | b2AuthorizeAccountResponse, privateBucketId).getResponse(); 24 | assertNull(b2ListFilesResponse.getNextFileId()); 25 | assertTrue(b2ListFilesResponse.getFiles().isEmpty()); 26 | 27 | B2TestHelper.deleteBucket(privateBucketId); 28 | } 29 | } -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2HeadFileRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import org.apache.http.impl.client.HttpClients; 9 | import org.junit.Test; 10 | 11 | import synapticloop.b2.helper.B2TestHelper; 12 | import synapticloop.b2.response.B2BucketResponse; 13 | import synapticloop.b2.response.B2DownloadFileResponse; 14 | import synapticloop.b2.response.B2FileResponse; 15 | 16 | public class B2HeadFileRequestTest { 17 | 18 | @Test 19 | public void testHeadFileById() throws Exception { 20 | final B2BucketResponse randomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 21 | 22 | Map fileInfo = new HashMap(); 23 | fileInfo.put("hello", "world"); 24 | 25 | final B2FileResponse b2FileResponse = B2TestHelper.uploadTemporaryFileToBucket(randomPrivateBucket.getBucketId(), fileInfo); 26 | 27 | B2DownloadFileResponse b2DownloadFileResponse = new B2HeadFileByIdRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), b2FileResponse.getFileId()).getResponse(); 28 | assertEquals("world", b2DownloadFileResponse.getFileInfo().get("hello")); 29 | 30 | assertEquals(0, b2DownloadFileResponse.getContent().available()); 31 | 32 | B2TestHelper.deleteFile(b2FileResponse.getFileName(), b2FileResponse.getFileId()); 33 | B2TestHelper.deleteBucket(randomPrivateBucket.getBucketId()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2ResponseHeaders.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import org.apache.http.HttpHeaders; 20 | 21 | public final class B2ResponseHeaders { 22 | public static final String HEADER_CONTENT_TYPE = HttpHeaders.CONTENT_TYPE; 23 | public static final String HEADER_CONTENT_LENGTH = HttpHeaders.CONTENT_LENGTH; 24 | 25 | public static final String HEADER_X_BZ_CONTENT_SHA1 = "X-Bz-Content-Sha1"; 26 | public static final String HEADER_X_BZ_FILE_NAME = "X-Bz-File-Name"; 27 | public static final String HEADER_X_BZ_FILE_ID = "X-Bz-File-Id"; 28 | public static final String HEADER_X_BZ_INFO_PREFIX = "X-Bz-Info-"; 29 | public static final String HEADER_X_BZ_PART_NUMBER = "X-Bz-Part-Number"; 30 | public static final String HEADER_X_BZ_UPLOAD_TIMESTAMP = "X-Bz-Upload-Timestamp"; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/Action.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | /** 20 | * The action for an associated file, either 'hide' or 'upload', "upload" means 21 | * a file that was uploaded to B2 Cloud Storage. "hide" means a file version 22 | * marking the file as hidden, so that it will not show up in b2_list_file_names. 23 | * 24 | * The result of b2_list_file_names will contain only "upload". The result of 25 | * b2_list_file_versions may have both. 26 | * 27 | * @author synapticloop 28 | */ 29 | public enum Action { 30 | /** 31 | * "hide" means a file version marking the file as hidden, so that it will not show up in b2_list_file_names. 32 | */ 33 | hide, 34 | /** 35 | * Pending multipart upload. "start" means that a large file has been started, but not finished or canceled. 36 | */ 37 | upload, 38 | start 39 | } 40 | -------------------------------------------------------------------------------- /documentr.json: -------------------------------------------------------------------------------- 1 | { 2 | "context": { 3 | "dependencyLocation": "bintray" 4 | }, 5 | "templates": [ 6 | { "type":"inbuilt", "value":"badge-travis-ci" }, 7 | { "type":"inbuilt", "value":"badge-bintray" }, 8 | { "type":"inbuilt", "value":"badge-shield-io-github-release" }, 9 | 10 | { "type":"inbuilt", "value":"project-name" }, 11 | { "type":"inbuilt", "value":"project-description" }, 12 | 13 | { "type": "markup", "value": "\n\n# Table of Contents\n\n" }, 14 | 15 | { "type": "toc", "value": "2" }, 16 | { "type": "toclinks", "value": "true" }, 17 | { "type": "toplink", "value": " " }, 18 | { "type": "tocbacktotop", "value": " [top](#documentr_top)" }, 19 | 20 | { "type":"file", "value":"src/docs/gui.md" }, 21 | 22 | { "type":"file", "value":"src/docs/usage-001.md" }, 23 | 24 | { "type":"file", "value":"src/test/java/synapticloop/b2/QuickExampleMain.java" }, 25 | 26 | { "type":"file", "value":"src/docs/usage-002.md" }, 27 | 28 | { "type":"inbuilt", "value":"gradle-build" }, 29 | { "type":"inbuilt", "value":"gradle-test" }, 30 | 31 | { "type":"inbuilt", "value":"test-warn" }, 32 | { "type":"template", "value":"src/docs/test-important.md.templar" }, 33 | 34 | { "type":"inbuilt", "value":"logging-slf4j" }, 35 | 36 | { "type":"inbuilt", "value":"publishing-github" }, 37 | 38 | { "type":"inbuilt", "value":"publishing-bintray" }, 39 | 40 | { "type":"inbuilt", "value":"dependencies" }, 41 | 42 | { "type":"inbuilt", "value":"license-mit" }, 43 | 44 | { "type":"inbuilt", "value":"attribution" } 45 | ] 46 | } -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2UpdateBucketRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.apache.http.impl.client.HttpClients; 6 | import org.junit.Test; 7 | 8 | import synapticloop.b2.BucketType; 9 | import synapticloop.b2.helper.B2TestHelper; 10 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 11 | import synapticloop.b2.response.B2BucketResponse; 12 | 13 | public class B2UpdateBucketRequestTest { 14 | 15 | @Test 16 | public void testUpdateBucket() throws Exception { 17 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 18 | 19 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 20 | 21 | String privateBucketId = privateBucket.getBucketId(); 22 | B2BucketResponse privateToPublicResponse = new B2UpdateBucketRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, privateBucketId, BucketType.allPublic).getResponse(); 23 | assertEquals(BucketType.allPublic, privateToPublicResponse.getBucketType()); 24 | 25 | B2TestHelper.deleteBucket(privateBucketId); 26 | 27 | B2BucketResponse createRandomPublicBucket = B2TestHelper.createRandomPublicBucket(); 28 | 29 | String publicBucketId = createRandomPublicBucket.getBucketId(); 30 | B2BucketResponse publicToPrivateResponse = new B2UpdateBucketRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, publicBucketId, BucketType.allPrivate).getResponse(); 31 | assertEquals(BucketType.allPrivate, publicToPrivateResponse.getBucketType()); 32 | B2TestHelper.deleteBucket(publicBucketId); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2GetFileInfoRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.apache.http.impl.client.HttpClients; 6 | import org.junit.Test; 7 | 8 | import synapticloop.b2.helper.B2TestHelper; 9 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 10 | import synapticloop.b2.response.B2BucketResponse; 11 | import synapticloop.b2.response.B2FileResponse; 12 | 13 | public class B2GetFileInfoRequestTest { 14 | 15 | @Test 16 | public void testGetFileInfo() throws Exception { 17 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 18 | B2BucketResponse b2BucketResponse = B2TestHelper.createRandomPrivateBucket(); 19 | B2FileResponse b2FileResponseIn = B2TestHelper.uploadTemporaryFileToBucket(b2BucketResponse.getBucketId()); 20 | 21 | B2FileResponse b2FileResponseOut = new B2GetFileInfoRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, b2FileResponseIn.getFileId()).getResponse(); 22 | 23 | assertEquals(b2FileResponseIn.getContentLength(), b2FileResponseOut.getContentLength()); 24 | assertEquals(b2FileResponseIn.getContentSha1(), b2FileResponseOut.getContentSha1()); 25 | assertEquals(b2FileResponseIn.getContentType(), b2FileResponseOut.getContentType()); 26 | assertEquals(b2FileResponseIn.getFileId(), b2FileResponseOut.getFileId()); 27 | assertEquals(b2FileResponseIn.getFileName(), b2FileResponseOut.getFileName()); 28 | 29 | new B2DeleteFileVersionRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, b2FileResponseOut.getFileName(), b2FileResponseOut.getFileId()).getResponse(); 30 | 31 | B2TestHelper.deleteBucket(b2BucketResponse.getBucketId()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/response/B2FileInfoResponseTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | import org.json.JSONObject; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.*; 7 | 8 | public class B2FileInfoResponseTest { 9 | 10 | @Test 11 | public void testGetFileInfo() throws Exception { 12 | final String json = 13 | " {\n" + 14 | " \"action\": \"upload\",\n" + 15 | " \"contentSha1\": \"f66ccfc5920c4527a3473cac8418e759fc991a1c\",\n" + 16 | " \"contentType\": \"image/jpeg\",\n" + 17 | " \"fileId\": \"4_zd866c2e0ac0d7d4855110b15_f10583db69f768e88_d20160122_m203004_c000_v0001016_t0021\",\n" + 18 | " \"fileInfo\": {\n" + 19 | " \"meta1\": \"This is some text for meta1.\",\n" + 20 | " \"meta2\": \"This is some more text for meta2.\",\n" + 21 | " \"unicorns-and-rainbows\": \"test header\"\n" + 22 | " },\n" + 23 | " \"fileName\": \"IMG_4666.jpg\",\n" + 24 | " \"size\": 1828156,\n" + 25 | " \"uploadTimestamp\": 1453494604000\n" + 26 | " }"; 27 | final B2FileInfoResponse response = new B2FileInfoResponse(new JSONObject(json)); 28 | assertNotNull(response); 29 | assertNotNull(response.getFileId()); 30 | assertNull(response.getContentLength()); 31 | assertNotNull(response.getAction()); 32 | assertNotNull(response.getFileName()); 33 | assertNotNull(response.getContentSha1()); 34 | assertNotNull(response.getSize()); 35 | assertNotNull(response.getFileInfo()); 36 | assertFalse(response.getFileInfo().isEmpty()); 37 | assertNotNull(response.getFileInfo().get("meta1")); 38 | assertNotNull(response.getFileInfo().get("meta1")); 39 | assertNotNull(response.getFileInfo().get("meta2")); 40 | assertNotNull(response.getFileInfo().get("unicorns-and-rainbows")); 41 | } 42 | } -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2ListBucketsRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.List; 6 | 7 | import org.apache.http.impl.client.HttpClients; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import synapticloop.b2.helper.B2TestHelper; 12 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 13 | import synapticloop.b2.response.B2BucketResponse; 14 | 15 | 16 | public class B2ListBucketsRequestTest { 17 | 18 | private B2AuthorizeAccountResponse b2AuthorizeAccountResponse = null; 19 | 20 | @Before 21 | public void setup() throws Exception { 22 | b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 23 | } 24 | 25 | @Test 26 | public void testListBuckets() throws Exception { 27 | // first we want to create a bucker 28 | B2BucketResponse createRandomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 29 | String bucketName = createRandomPrivateBucket.getBucketName(); 30 | String bucketId = createRandomPrivateBucket.getBucketId(); 31 | 32 | B2ListBucketsRequest b2ListBucketsRequest = new B2ListBucketsRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse); 33 | List responses = b2ListBucketsRequest.getResponse().getBuckets(); 34 | // this may actually not be the greatest test as there may already be more than one bucket... 35 | assertTrue(responses.size() > 0); 36 | 37 | // so we test to ensure that we have the named bucket 38 | 39 | boolean hasFoundBucket = false; 40 | for (B2BucketResponse b2BucketResponse : responses) { 41 | if(bucketName.equals(b2BucketResponse.getBucketName())) { 42 | hasFoundBucket = true; 43 | } 44 | } 45 | 46 | assertTrue(hasFoundBucket); 47 | 48 | // in any case - we want to delete it 49 | B2TestHelper.deleteBucket(bucketId); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2ListPartsResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import org.json.JSONArray; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import synapticloop.b2.exception.B2ApiException; 28 | 29 | public class B2ListPartsResponse extends BaseB2Response { 30 | private static final Logger LOGGER = LoggerFactory.getLogger(B2ListPartsResponse.class); 31 | 32 | private final Integer nextPartNumber; 33 | private final List files; 34 | 35 | public B2ListPartsResponse(String json) throws B2ApiException { 36 | super(json); 37 | 38 | this.nextPartNumber = this.readInt(B2ResponseProperties.KEY_NEXT_PART_NUMBER); 39 | 40 | JSONArray filesArray = this.readObjects(B2ResponseProperties.KEY_PARTS); 41 | 42 | files = new ArrayList(); 43 | for (int i = 0; i < filesArray.length(); i++) { 44 | files.add(new B2UploadPartResponse(filesArray.optJSONObject(i))); 45 | } 46 | 47 | this.warnOnMissedKeys(); 48 | } 49 | 50 | public Integer getNextPartNumber() { 51 | return nextPartNumber; 52 | } 53 | 54 | public List getFiles() { 55 | return files; 56 | } 57 | 58 | @Override 59 | protected Logger getLogger() { return LOGGER; } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2AuthorizeAccountRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.apache.http.impl.client.HttpClients; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import synapticloop.b2.exception.B2ApiException; 10 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 11 | 12 | 13 | public class B2AuthorizeAccountRequestTest { 14 | 15 | private static final String B2_ACCOUNT_ID = "B2_ACCOUNT_ID"; 16 | private static final String B2_APPLICATION_KEY = "B2_APPLICATION_KEY"; 17 | 18 | @Before 19 | public void setup() { 20 | } 21 | 22 | @Test 23 | public void testCorrectCredentials() throws Exception { 24 | boolean isOK = true; 25 | String b2AccountId = System.getenv(B2_ACCOUNT_ID); 26 | String b2ApplicationKey = System.getenv(B2_APPLICATION_KEY); 27 | 28 | if(null == b2AccountId) { 29 | System.err.println("Could not find the environment variable '" + B2_ACCOUNT_ID + "', cannot continue with tests, exiting..."); 30 | isOK = false; 31 | } 32 | 33 | if(null == b2ApplicationKey) { 34 | System.err.println("Could not find the environment variable '" + B2_APPLICATION_KEY + "', cannot continue with tests, exiting..."); 35 | isOK = false; 36 | } 37 | 38 | if(!isOK) { 39 | System.exit(-1); 40 | } 41 | 42 | B2AuthorizeAccountRequest b2AuthorizeAccountRequest = new B2AuthorizeAccountRequest(HttpClients.createDefault(), b2AccountId, b2ApplicationKey); 43 | B2AuthorizeAccountResponse response = b2AuthorizeAccountRequest.getResponse(); 44 | assertNotNull(response.getAuthorizationToken()); 45 | assertNotNull(response.getAccountId()); 46 | assertNotNull(response.getApiUrl()); 47 | assertNotNull(response.getDownloadUrl()); 48 | } 49 | 50 | @Test (expected=B2ApiException.class) 51 | public void testIncorrectCredentials() throws Exception { 52 | B2AuthorizeAccountRequest b2AuthorizeAccountRequest = new B2AuthorizeAccountRequest(HttpClients.createDefault(), "bad", "value"); 53 | b2AuthorizeAccountRequest.getResponse(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2CreateAndDeleteBucketRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.UUID; 6 | 7 | import org.apache.http.impl.client.HttpClients; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | 11 | import synapticloop.b2.BucketType; 12 | import synapticloop.b2.helper.B2TestHelper; 13 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 14 | import synapticloop.b2.response.B2BucketResponse; 15 | 16 | public class B2CreateAndDeleteBucketRequestTest { 17 | private B2CreateBucketRequest b2CreateBucketRequest = null; 18 | private static B2AuthorizeAccountResponse b2AuthorizeAccountResponse = null; 19 | private static String bucketName = null; 20 | 21 | @BeforeClass 22 | public static void setupBeforClass() throws Exception { 23 | b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 24 | bucketName = UUID.randomUUID().toString(); 25 | } 26 | 27 | @Test 28 | public void testBucketCreationAndDeletion() throws Exception { 29 | 30 | b2CreateBucketRequest = new B2CreateBucketRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, bucketName, BucketType.allPrivate); 31 | B2BucketResponse b2BucketResponse = b2CreateBucketRequest.getResponse(); 32 | assertEquals(b2AuthorizeAccountResponse.getAccountId(), b2BucketResponse.getAccountId()); 33 | String bucketId = b2BucketResponse.getBucketId(); 34 | assertNotNull(bucketId); 35 | assertEquals(bucketName, b2BucketResponse.getBucketName()); 36 | assertEquals(BucketType.allPrivate, b2BucketResponse.getBucketType()); 37 | 38 | B2DeleteBucketRequest b2DeleteBucketRequest = new B2DeleteBucketRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, bucketId); 39 | B2BucketResponse response = b2DeleteBucketRequest.getResponse(); 40 | 41 | assertNotNull(response.getBucketId()); 42 | assertEquals(bucketId, response.getBucketId()); 43 | assertEquals(bucketName, b2BucketResponse.getBucketName()); 44 | assertEquals(BucketType.allPrivate, b2BucketResponse.getBucketType()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/B2ApiClientTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.UUID; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import synapticloop.b2.helper.B2TestHelper; 11 | import synapticloop.b2.response.B2BucketResponse; 12 | 13 | public class B2ApiClientTest { 14 | public static final String B2_ACCOUNT_ID = "B2_ACCOUNT_ID"; 15 | public static final String B2_APPLICATION_KEY = "B2_APPLICATION_KEY"; 16 | private B2ApiClient client; 17 | 18 | @Before 19 | public void setup() throws Exception { 20 | boolean isOK = true; 21 | String b2AccountId = System.getenv(B2_ACCOUNT_ID); 22 | String b2ApplicationKey = System.getenv(B2_APPLICATION_KEY); 23 | 24 | if(null == b2AccountId) { 25 | System.err.println("Could not find the environment variable '" + B2_ACCOUNT_ID + "', cannot continue with tests, exiting..."); 26 | isOK = false; 27 | } 28 | 29 | if(null == b2ApplicationKey) { 30 | System.err.println("Could not find the environment variable '" + B2_APPLICATION_KEY + "', cannot continue with tests, exiting..."); 31 | isOK = false; 32 | } 33 | 34 | if(!isOK) { 35 | System.exit(-1); 36 | } 37 | 38 | client = new B2ApiClient(); 39 | client.authenticate(b2AccountId, b2ApplicationKey); 40 | } 41 | 42 | @Test 43 | public void testPrivateBuckets() throws Exception { 44 | B2BucketResponse createPrivateBucket = client.createBucket(B2TestHelper.B2_BUCKET_PREFIX + UUID.randomUUID().toString(), BucketType.allPrivate); 45 | 46 | B2BucketResponse updateBucket = client.updateBucket(createPrivateBucket.getBucketId(), BucketType.allPublic); 47 | assertEquals(updateBucket.getBucketType(), BucketType.allPublic); 48 | 49 | client.deleteBucket(createPrivateBucket.getBucketId()); 50 | } 51 | 52 | @Test 53 | public void testPublicBuckets() throws Exception { 54 | B2BucketResponse createPublicBucket = client.createBucket(B2TestHelper.B2_BUCKET_PREFIX + UUID.randomUUID().toString(), BucketType.allPublic); 55 | client.deleteBucket(createPublicBucket.getBucketId()); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2CancelLargeFileRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import java.io.IOException; 21 | 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | import org.apache.http.util.EntityUtils; 24 | 25 | import synapticloop.b2.exception.B2ApiException; 26 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 27 | import synapticloop.b2.response.B2FileResponse; 28 | 29 | public class B2CancelLargeFileRequest extends BaseB2Request { 30 | private static final String B2_CANCEL_LARGE_FILE = BASE_API_VERSION + "b2_cancel_large_file"; 31 | 32 | /** 33 | * @param client The http client to use 34 | * @param b2AuthorizeAccountResponse the authorize account response 35 | * @param fileId The ID of the file, as returned by {@link B2StartLargeFileRequest}, 36 | */ 37 | public B2CancelLargeFileRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 38 | String fileId) { 39 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_CANCEL_LARGE_FILE); 40 | 41 | this.addProperty(B2RequestProperties.KEY_FILE_ID, fileId); 42 | } 43 | 44 | public B2FileResponse getResponse() throws B2ApiException, IOException { 45 | return new B2FileResponse(EntityUtils.toString(executePost().getEntity())); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2RequestProperties.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | public final class B2RequestProperties { 20 | public static final String KEY_ACCOUNT_ID = "accountId"; 21 | public static final String KEY_BUCKET_ID = "bucketId"; 22 | public static final String KEY_BUCKET_NAME = "bucketName"; 23 | public static final String KEY_BUCKET_TYPE = "bucketType"; 24 | public static final String KEY_LIFECYCLE_RULES = "lifecycleRules"; 25 | public static final String KEY_FILE_ID = "fileId"; 26 | public static final String KEY_FILE_NAME = "fileName"; 27 | public static final String KEY_FILE_NAME_PREFIX = "fileNamePrefix"; 28 | public static final String KEY_VALID_DURATION_INSECONDS = "validDurationInSeconds"; 29 | public static final String KEY_CONTENT_TYPE = "contentType"; 30 | public static final String KEY_FILE_INFO = "fileInfo"; 31 | public static final String KEY_MAX_FILE_COUNT = "maxFileCount"; 32 | public static final String KEY_START_FILE_ID = "startFileId"; 33 | public static final String KEY_START_FILE_NAME = "startFileName"; 34 | public static final String KEY_PART_SHA1_ARRAY = "partSha1Array"; 35 | public static final String KEY_START_PART_NUMBER = "startPartNumber"; 36 | public static final String KEY_MAX_PART_COUNT = "maxPartCount"; 37 | public static final String KEY_PREFIX = "prefix"; 38 | public static final String KEY_DELIMITER = "delimiter"; 39 | public static final String REQUEST_PROPERTY_CONTENT_TYPE = "Content-Type"; 40 | public static final String REQUEST_PROPERTY_AUTHORIZATION = "Authorization"; 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2HideFileRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | import static org.junit.Assert.*; 3 | 4 | import org.apache.http.impl.client.HttpClients; 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import synapticloop.b2.helper.B2TestHelper; 10 | import synapticloop.b2.response.B2BucketResponse; 11 | import synapticloop.b2.response.B2FileResponse; 12 | import synapticloop.b2.response.B2HideFileResponse; 13 | import synapticloop.b2.response.B2ListFilesResponse; 14 | 15 | 16 | public class B2HideFileRequestTest { 17 | 18 | private B2BucketResponse randomPrivateBucket = null; 19 | private B2FileResponse b2FileResponseWithPath = null; 20 | private B2HideFileResponse b2HideFileResponse = null; 21 | 22 | @Before 23 | public void setup() { 24 | } 25 | 26 | @Test 27 | public void testHideFileWithPath() throws Exception { 28 | randomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 29 | String bucketId = randomPrivateBucket.getBucketId(); 30 | b2FileResponseWithPath = B2TestHelper.uploadTemporaryFileToBucket(bucketId); 31 | 32 | B2ListFilesResponse b2ListFilesResponse = new B2ListFileNamesRequest(HttpClients.createDefault(), 33 | B2TestHelper.getB2AuthorizeAccountResponse(), bucketId).getResponse(); 34 | 35 | assertEquals(1, b2ListFilesResponse.getFiles().size()); 36 | 37 | b2HideFileResponse = new B2HideFileRequest(HttpClients.createDefault(), 38 | B2TestHelper.getB2AuthorizeAccountResponse(), 39 | bucketId, 40 | b2FileResponseWithPath.getFileName()).getResponse(); 41 | 42 | assertEquals("hide", b2HideFileResponse.getAction().toString()); 43 | 44 | // we now have two versions... 45 | b2ListFilesResponse = new B2ListFileNamesRequest(HttpClients.createDefault(), 46 | B2TestHelper.getB2AuthorizeAccountResponse(), 47 | bucketId).getResponse(); 48 | 49 | assertEquals(2, b2ListFilesResponse.getFiles().size()); 50 | 51 | } 52 | 53 | @After 54 | public void tearDown() throws Exception { 55 | B2TestHelper.deleteFile(b2HideFileResponse.getFileName(), b2HideFileResponse.getFileId()); 56 | B2TestHelper.deleteFile(b2FileResponseWithPath.getFileName(), b2FileResponseWithPath.getFileId()); 57 | B2TestHelper.deleteBucket(randomPrivateBucket.getBucketId()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2ListBucketsResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import org.json.JSONArray; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import synapticloop.b2.exception.B2ApiException; 27 | 28 | public final class B2ListBucketsResponse extends BaseB2Response { 29 | private static final Logger LOGGER = LoggerFactory.getLogger(B2ListBucketsResponse.class); 30 | 31 | private final List buckets; 32 | 33 | /** 34 | * Instantiate a list bucket response with the JSON response as a string from 35 | * the API call. This response is then parsed into the relevant fields. 36 | * 37 | * @param json The response (in JSON format) 38 | * 39 | * @throws B2ApiException if there was an error parsing the response 40 | */ 41 | public B2ListBucketsResponse(final String json) throws B2ApiException { 42 | super(json); 43 | 44 | buckets = new ArrayList<>(); 45 | JSONArray optJSONArray = this.readObjects(B2ResponseProperties.KEY_BUCKETS); 46 | for(int i = 0; i < optJSONArray.length(); i++) { 47 | buckets.add(new B2BucketResponse(optJSONArray.optJSONObject(i))); 48 | } 49 | 50 | this.warnOnMissedKeys(); 51 | } 52 | 53 | /** 54 | * Return a list of all of the buckets 55 | * 56 | * @return the bucket list (but not the film version :)) 57 | */ 58 | public List getBuckets() { 59 | return buckets; 60 | } 61 | 62 | @Override 63 | protected Logger getLogger() { return LOGGER; } 64 | 65 | @Override 66 | public String toString() { 67 | final StringBuilder sb = new StringBuilder("B2ListBucketsResponse{"); 68 | sb.append("buckets=").append(buckets); 69 | sb.append('}'); 70 | return sb.toString(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2DeleteFileVersionResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import synapticloop.b2.exception.B2ApiException; 23 | 24 | public class B2DeleteFileVersionResponse extends BaseB2Response { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(B2DeleteFileVersionResponse.class); 26 | 27 | private final String fileId; 28 | private final String fileName; 29 | 30 | /** 31 | * Instantiate a delete file version response with the JSON response as a string from 32 | * the API call. This response is then parsed into the relevant fields. 33 | * 34 | * @param json The response (in JSON format) 35 | * 36 | * @throws B2ApiException if there was an error parsing the response 37 | */ 38 | public B2DeleteFileVersionResponse(String json) throws B2ApiException { 39 | super(json); 40 | 41 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 42 | this.fileName = this.readString(B2ResponseProperties.KEY_FILE_NAME); 43 | 44 | this.warnOnMissedKeys(); 45 | } 46 | 47 | /** 48 | * Get the fileId that uniquely identifies this file 49 | * 50 | * @return the fileId 51 | */ 52 | public String getFileId() { return this.fileId; } 53 | 54 | /** 55 | * Get the name of the file as stored in the backblaze bucket 56 | * 57 | * @return the name of the file as stored in the backblaze bucket 58 | */ 59 | public String getFileName() { return this.fileName; } 60 | 61 | @Override 62 | protected Logger getLogger() { return LOGGER; } 63 | 64 | @Override 65 | public String toString() { 66 | final StringBuilder sb = new StringBuilder("B2DeleteFileVersionResponse{"); 67 | sb.append("fileId='").append(fileId).append('\''); 68 | sb.append(", fileName='").append(fileName).append('\''); 69 | sb.append('}'); 70 | return sb.toString(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/util/URLEncoder.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.util; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.UnsupportedEncodingException; 20 | import java.util.StringTokenizer; 21 | 22 | public class URLEncoder { 23 | private static final String UTF_8 = "UTF-8"; 24 | 25 | /** 26 | * UTF-8 url encoding wrapper method which does not encode slashes for requests. 27 | * See https://www.backblaze.com/b2/docs/string_encoding.html 28 | * for usage why it will not be encoded. 29 | * 30 | * If there was an unsupported encoding exception, return the un-encoded url 31 | * 32 | * @param url the URL to encode 33 | * 34 | * @return the encoded URL 35 | */ 36 | public static String encode(String url) { 37 | try { 38 | final StringBuilder b = new StringBuilder(); 39 | final StringTokenizer t = new StringTokenizer(url, "/"); 40 | if (!t.hasMoreTokens()) { 41 | return url; 42 | } 43 | while (t.hasMoreTokens()) { 44 | b.append(java.net.URLEncoder.encode(t.nextToken(), UTF_8)); 45 | if (t.hasMoreTokens()) { 46 | b.append('/'); 47 | } 48 | } 49 | if (url.endsWith("/")) { 50 | b.append('/'); 51 | } 52 | // Becuase URLEncoder uses application/x-www-form-urlencoded we have to replace these 53 | // for proper URI percented encoding. 54 | return b.toString() 55 | .replace("+", "%20") 56 | .replace("*", "%2A"); 57 | } catch (UnsupportedEncodingException ex) { 58 | return url; 59 | } 60 | } 61 | 62 | /** 63 | * UTF-8 url decoding wrapper method. If there was an unsupported encoding 64 | * exception, return the encoded url 65 | * 66 | * @param url the URL to decode 67 | * 68 | * @return the decoded URL 69 | */ 70 | 71 | public static String decode(String url) { 72 | try { 73 | return java.net.URLDecoder.decode(url, UTF_8); 74 | } catch (UnsupportedEncodingException ex) { 75 | return url; 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2ListBucketsRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2ListBucketsResponse; 27 | 28 | /** 29 | *

Lists buckets associated with an account, in alphabetical order by bucket ID.

30 | * 31 | * 32 | * This is the interaction class for the b2_list_buckets api calls, this was 33 | * generated from the backblaze api documentation - which can be found here: 34 | * http://www.backblaze.com/b2/docs/b2_list_buckets.html 35 | * 36 | * @author synapticloop 37 | */ 38 | public class B2ListBucketsRequest extends BaseB2Request { 39 | private static final String B2_LIST_BUCKETS = BASE_API_VERSION + "b2_list_buckets"; 40 | 41 | /** 42 | * Create a List buckets request 43 | * 44 | * @param client the HTTP client to use 45 | * @param b2AuthorizeAccountResponse the authorize account response 46 | */ 47 | public B2ListBucketsRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse) { 48 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_LIST_BUCKETS); 49 | 50 | this.addProperty(B2RequestProperties.KEY_ACCOUNT_ID, b2AuthorizeAccountResponse.getAccountId()); 51 | } 52 | 53 | /** 54 | * Return the list buckets response 55 | * 56 | * @return the list buckets response 57 | * 58 | * @throws B2ApiException if something went wrong 59 | * @throws IOException if there was an error communicating with the API service 60 | */ 61 | public B2ListBucketsResponse getResponse() throws B2ApiException, IOException { 62 | return new B2ListBucketsResponse(EntityUtils.toString(executePost().getEntity())); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/util/ChecksumHelper.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.util; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.BufferedInputStream; 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileNotFoundException; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.security.MessageDigest; 26 | import java.security.NoSuchAlgorithmException; 27 | 28 | import javax.xml.bind.annotation.adapters.HexBinaryAdapter; 29 | 30 | import org.apache.commons.io.IOUtils; 31 | 32 | public class ChecksumHelper { 33 | /** 34 | * Calculate and return the sha1 sum of a file 35 | * 36 | * @param file the file to calculate the sha1 sum on 37 | * 38 | * @return the sha1 of the file 39 | * 40 | * @throws IOException if something went wrong with the calculation 41 | */ 42 | public static String calculateSha1(File file) throws IOException { 43 | try { 44 | return calculateSha1(new FileInputStream(file)); 45 | } 46 | catch(FileNotFoundException e) { 47 | throw new IOException(e); 48 | } 49 | } 50 | 51 | /** 52 | * Calculate and return the sha1 sum of an input stream 53 | * 54 | * @param in the input stream to calculate the sha1 sum of 55 | * 56 | * @return the sha1 sum 57 | * 58 | * @throws IOException if there was an error calculating the sha1 sum 59 | */ 60 | public static String calculateSha1(InputStream in) throws IOException { 61 | 62 | MessageDigest messageDigest; 63 | InputStream inputStream = null; 64 | try { 65 | messageDigest = MessageDigest.getInstance("SHA-1"); 66 | inputStream = new BufferedInputStream(in); 67 | byte[] buffer = new byte[8192]; 68 | int len = inputStream.read(buffer); 69 | 70 | while (len != -1) { 71 | messageDigest.update(buffer, 0, len); 72 | len = inputStream.read(buffer); 73 | } 74 | 75 | return(new HexBinaryAdapter().marshal(messageDigest.digest())); 76 | } catch (NoSuchAlgorithmException ex) { 77 | throw new IOException(ex); 78 | } finally { 79 | IOUtils.closeQuietly(inputStream); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2GetDownloadAuthorizationResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2017 Synapticloop. 5 | * Copyright (c) 2017 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import synapticloop.b2.exception.B2ApiException; 24 | 25 | public class B2GetDownloadAuthorizationResponse extends BaseB2Response { 26 | private static final Logger LOGGER = LoggerFactory.getLogger(B2AuthorizeAccountResponse.class); 27 | 28 | private final String bucketId; 29 | private final String fileNamePrefix; 30 | private final String authorizationToken; 31 | 32 | public B2GetDownloadAuthorizationResponse(String json) throws B2ApiException { 33 | super(json); 34 | 35 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 36 | this.fileNamePrefix = this.readString(B2ResponseProperties.KEY_FILE_NAME); 37 | this.authorizationToken = this.readString(B2ResponseProperties.KEY_AUTHORIZATION_TOKEN); 38 | 39 | this.warnOnMissedKeys(); 40 | } 41 | 42 | /** 43 | * @return The identifier for the bucket. 44 | */ 45 | public String getBucketId() { return bucketId; } 46 | 47 | /** 48 | * @return The prefix for files the authorization token will allow b2_download_file_by_name to access. 49 | */ 50 | public String getFileNamePrefix() { return fileNamePrefix; } 51 | 52 | /** 53 | * @return The authorization token that can be passed in the Authorization header or as an Authorization 54 | * parameter to b2_download_file_by_name to access files beginning with the file name prefix. 55 | */ 56 | public String getAuthorizationToken() { return authorizationToken; } 57 | 58 | @Override 59 | protected Logger getLogger() { 60 | return LOGGER; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | final StringBuilder sb = new StringBuilder("B2GetDownloadAuthorizationResponse{"); 66 | sb.append("bucketId='").append(bucketId).append('\''); 67 | sb.append(", fileNamePrefix='").append(fileNamePrefix).append('\''); 68 | sb.append(", authorizationToken='").append(authorizationToken).append('\''); 69 | sb.append('}'); 70 | return sb.toString(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/io/HttpMethodReleaseInputStream.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.io; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import org.apache.commons.io.input.CountingInputStream; 20 | import org.apache.http.HttpConnection; 21 | import org.apache.http.HttpResponse; 22 | import org.apache.http.client.methods.CloseableHttpResponse; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import java.io.IOException; 27 | 28 | public class HttpMethodReleaseInputStream extends CountingInputStream { 29 | private static final Logger LOGGER = LoggerFactory.getLogger(HttpMethodReleaseInputStream.class); 30 | 31 | private HttpResponse response; 32 | 33 | /** 34 | * Create a HTTP method release input Stream 35 | * 36 | * @param response The HTTP response to read from 37 | * 38 | * @throws IOException If there is a problem reading from the response 39 | * @throws NullPointerException If the response has no message entity 40 | */ 41 | public HttpMethodReleaseInputStream(final HttpResponse response) throws IOException { 42 | super(response.getEntity().getContent()); 43 | this.response = response; 44 | } 45 | 46 | /** 47 | * This will force close the connection if the content has not been fully consumed 48 | * 49 | * @throws IOException if an I/O error occurs 50 | * @see CloseableHttpResponse#close() 51 | * @see HttpConnection#shutdown() 52 | */ 53 | @Override 54 | public void close() throws IOException { 55 | if(response instanceof CloseableHttpResponse) { 56 | long read = this.getByteCount(); 57 | if(read == response.getEntity().getContentLength()) { 58 | // Fully consumed 59 | super.close(); 60 | } else { 61 | LOGGER.warn("Abort connection for response '{}'", response); 62 | // Close an HTTP response as quickly as possible, avoiding consuming 63 | // response data unnecessarily though at the expense of making underlying 64 | // connections unavailable for reuse. 65 | // The response proxy will force close the connection. 66 | ((CloseableHttpResponse) response).close(); 67 | } 68 | } else { 69 | // Consume and close 70 | super.close(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2GetDownloadAuthorizationRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2017 Synapticloop. 5 | * Copyright (c) 2017 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import java.io.IOException; 21 | 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | import org.apache.http.util.EntityUtils; 24 | 25 | import synapticloop.b2.exception.B2ApiException; 26 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 27 | import synapticloop.b2.response.B2GetDownloadAuthorizationResponse; 28 | 29 | public class B2GetDownloadAuthorizationRequest extends BaseB2Request { 30 | private static final String B2_GET_DOWNLOAD_AUTHORIZATION = BASE_API_VERSION + "b2_get_download_authorization"; 31 | 32 | /** 33 | * @param client The http client to use 34 | * @param b2AuthorizeAccountResponse the authorize account response 35 | * @param bucketId The identifier for the bucket. 36 | * @param fileNamePrefix The file name prefix of files the download authorization token will allow b2_download_file_by_name to access. 37 | * @param validDurationInSeconds The number of seconds before the authorization token will expire. 38 | * The maximum value is 604800 which is one week in seconds. 39 | */ 40 | public B2GetDownloadAuthorizationRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 41 | String bucketId, String fileNamePrefix, Integer validDurationInSeconds) { 42 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_GET_DOWNLOAD_AUTHORIZATION); 43 | 44 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 45 | this.addProperty(B2RequestProperties.KEY_FILE_NAME_PREFIX, fileNamePrefix); 46 | this.addProperty(B2RequestProperties.KEY_VALID_DURATION_INSECONDS, validDurationInSeconds); 47 | } 48 | 49 | public B2GetDownloadAuthorizationResponse getResponse() throws B2ApiException, IOException { 50 | return new B2GetDownloadAuthorizationResponse(EntityUtils.toString(executePost().getEntity())); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2FinishLargeFileRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import java.io.IOException; 21 | 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | import org.apache.http.util.EntityUtils; 24 | import org.json.JSONArray; 25 | 26 | import synapticloop.b2.exception.B2ApiException; 27 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 28 | import synapticloop.b2.response.B2FinishLargeFileResponse; 29 | 30 | public class B2FinishLargeFileRequest extends BaseB2Request { 31 | private static final String B2_FINISH_LARGE_FILE = BASE_API_VERSION + "b2_finish_large_file"; 32 | 33 | /** 34 | * @param client The http client to use 35 | * @param b2AuthorizeAccountResponse the authorize account response 36 | * @param fileId The ID of the file, as returned by {@link B2StartLargeFileRequest}, 37 | * @param partSha1Array A JSON array of hex SHA1 checksums of the parts of the large file. This is a double-check 38 | * that the right parts were uploaded in the right order, and that none were missed. 39 | * Note that the part numbers start at 1, and the SHA1 of the part 1 is the first string 40 | * in the array, at index 0. 41 | */ 42 | public B2FinishLargeFileRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 43 | String fileId, String[] partSha1Array) { 44 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_FINISH_LARGE_FILE); 45 | 46 | this.addProperty(B2RequestProperties.KEY_FILE_ID, fileId); 47 | 48 | JSONArray checksums = new JSONArray(); 49 | for (String part : partSha1Array) { 50 | checksums.put(part); 51 | } 52 | this.addProperty(B2RequestProperties.KEY_PART_SHA1_ARRAY, checksums); 53 | } 54 | 55 | public B2FinishLargeFileResponse getResponse() throws B2ApiException, IOException { 56 | return new B2FinishLargeFileResponse(EntityUtils.toString(executePost().getEntity())); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2ResponseProperties.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | public final class B2ResponseProperties { 20 | public static final String KEY_ABSOLUTE_MINIMUM_PART_SIZE = "absoluteMinimumPartSize"; 21 | public static final String KEY_ACCOUNT_ID = "accountId"; 22 | public static final String KEY_ACTION = "action"; 23 | public static final String KEY_API_URL = "apiUrl"; 24 | public static final String KEY_AUTHORIZATION_TOKEN = "authorizationToken"; 25 | public static final String KEY_BUCKET_ID = "bucketId"; 26 | public static final String KEY_BUCKET_INFO = "bucketInfo"; 27 | public static final String KEY_BUCKET_NAME = "bucketName"; 28 | public static final String KEY_BUCKET_TYPE = "bucketType"; 29 | public static final String KEY_BUCKETS = "buckets"; 30 | public static final String KEY_CONTENT_LENGTH = "contentLength"; 31 | public static final String KEY_CONTENT_SHA1 = "contentSha1"; 32 | public static final String KEY_CONTENT_TYPE = "contentType"; 33 | public static final String KEY_DOWNLOAD_URL = "downloadUrl"; 34 | public static final String KEY_FILE_ID = "fileId"; 35 | public static final String KEY_FILE_INFO = "fileInfo"; 36 | public static final String KEY_FILE_NAME = "fileName"; 37 | public static final String KEY_FILE_NAME_PREFIX = "fileNamePrefix"; 38 | public static final String KEY_FILES = "files"; 39 | public static final String KEY_LIFECYCLE_RULES = "lifecycleRules"; 40 | public static final String KEY_MINIMUM_PART_SIZE = "minimumPartSize"; 41 | public static final String KEY_NEXT_FILE_ID = "nextFileId"; 42 | public static final String KEY_NEXT_FILE_NAME = "nextFileName"; 43 | public static final String KEY_NEXT_PART_NUMBER = "nextPartNumber"; 44 | public static final String KEY_PART_NUMBER = "partNumber"; 45 | public static final String KEY_PARTS = "parts"; 46 | public static final String KEY_RECOMMENDED_PART_SIZE = "recommendedPartSize"; 47 | public static final String KEY_REVISION = "revision"; 48 | public static final String KEY_SIZE = "size"; 49 | public static final String KEY_UPLOAD_TIMESTAMP = "uploadTimestamp"; 50 | public static final String KEY_UPLOAD_URL = "uploadUrl"; 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2HideFileRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2HideFileResponse; 27 | 28 | /** 29 | *

Hides a file so that downloading by name will not find the file, but previous versions of the file are still stored. See File Versions about what it means to hide a file.

30 | * 31 | * 32 | * This is the interaction class for the b2_hide_file api calls, this was 33 | * generated from the backblaze api documentation - which can be found here: 34 | * http://www.backblaze.com/b2/docs/b2_hide_file.html 35 | * 36 | * @author synapticloop 37 | */ 38 | public class B2HideFileRequest extends BaseB2Request { 39 | private static final String B2_HIDE_FILE = BASE_API_VERSION + "b2_hide_file"; 40 | 41 | /** 42 | * Create a hide file request 43 | * 44 | * @param client the http client to use 45 | * @param b2AuthorizeAccountResponse the authorize account response 46 | * @param bucketId the id of the bucket to use 47 | * @param fileName the name and path of the file 48 | */ 49 | public B2HideFileRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketId, String fileName) { 50 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_HIDE_FILE); 51 | 52 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 53 | this.addProperty(B2RequestProperties.KEY_FILE_NAME, fileName); 54 | } 55 | 56 | /** 57 | * Return the hide file response 58 | * 59 | * @return the hide file response 60 | * 61 | * @throws B2ApiException if something went wrong 62 | * @throws IOException if there was an error communicating with the API service 63 | */ 64 | public B2HideFileResponse getResponse() throws B2ApiException, IOException { 65 | return new B2HideFileResponse(EntityUtils.toString(executePost().getEntity())); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2GetFileInfoRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2FileResponse; 27 | 28 | /** 29 | *

Gets information about one file stored in B2.

30 | * 31 | * 32 | * This is the interaction class for the b2_get_file_info api calls, this was 33 | * generated from the backblaze api documentation - which can be found here: 34 | * http://www.backblaze.com/b2/docs/b2_get_file_info.html 35 | * 36 | * @author synapticloop 37 | */ 38 | public class B2GetFileInfoRequest extends BaseB2Request { 39 | private static final String B2_GET_FILE_INFO = BASE_API_VERSION + "b2_get_file_info"; 40 | 41 | /** 42 | * Create a new get file info request object 43 | * 44 | * @param client Shared HTTP client instance 45 | * @param b2AuthorizeAccountResponse the authorize account response 46 | * @param fileId The ID of the file, as returned by b2_upload_file, b2_list_file_names, or b2_list_file_versions. 47 | * 48 | * {@link B2UploadFileRequest} 49 | * {@link B2ListFileNamesRequest} 50 | * {@link B2ListFileVersionsRequest} 51 | */ 52 | public B2GetFileInfoRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String fileId) { 53 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_GET_FILE_INFO); 54 | 55 | this.addProperty(B2RequestProperties.KEY_FILE_ID, fileId); 56 | } 57 | 58 | /** 59 | * Execute the call and retrieve the response for the get file info 60 | * 61 | * @return The details for the file information 62 | * 63 | * @throws B2ApiException if there was an error with the call 64 | * @throws IOException if there was an error communicating with the API service 65 | */ 66 | public B2FileResponse getResponse() throws B2ApiException, IOException { 67 | return new B2FileResponse(EntityUtils.toString(executePost().getEntity())); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2DeleteBucketRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2BucketResponse; 27 | 28 | /** 29 | *

Deletes the bucket specified. Only buckets that contain no version of any files can be deleted.

30 | * 31 | * This is the interaction class for the b2_delete_bucket api 32 | * calls, this was generated from the backblaze api documentation - which can 33 | * be found here: 34 | * 35 | * http://www.backblaze.com/b2/docs/b2_delete_bucket.html 36 | * 37 | * @author synapticloop 38 | */ 39 | public class B2DeleteBucketRequest extends BaseB2Request { 40 | private static final String B2_DELETE_BUCKET = BASE_API_VERSION + "b2_delete_bucket"; 41 | 42 | /** 43 | * Instantiate a new delete bucket request 44 | * 45 | * @param client Shared HTTP client instance 46 | * @param b2AuthorizeAccountResponse the authorize account response 47 | * @param bucketId The id of the bucket to delete 48 | */ 49 | public B2DeleteBucketRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketId) { 50 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_DELETE_BUCKET); 51 | 52 | this.addProperty(B2RequestProperties.KEY_ACCOUNT_ID, b2AuthorizeAccountResponse.getAccountId()); 53 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 54 | } 55 | 56 | /** 57 | * return the deleted bucket response 58 | * 59 | * @return The deleted bucket response 60 | * 61 | * @throws B2ApiException if there was an error with the call, or if you are 62 | * trying to delete a bucket which is not empty 63 | * @throws IOException if there was an error communicating with the API service 64 | */ 65 | public B2BucketResponse getResponse() throws B2ApiException, IOException { 66 | return new B2BucketResponse(EntityUtils.toString(executePost().getEntity())); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/docs/usage-002.md: -------------------------------------------------------------------------------- 1 | 2 | ``` 3 | 4 | see [B2ApiClient.java](https://github.com/synapticloop/backblaze-b2-java-api/blob/master/src/main/java/synapticloop/b2/B2ApiClient.java) for a complete list of relatively self-explanatory methods. 5 | 6 | ``` 7 | // create a new B2ApiClient 8 | B2ApiClient() 9 | 10 | // authenticate the client 11 | authenticate(String, String) 12 | 13 | // create a bucket 14 | createBucket(String, BucketType) 15 | 16 | // delete bucket 17 | deleteBucket(String) 18 | 19 | // delete a version of a file 20 | deleteFileVersion(String, String) 21 | 22 | // download the full file by id, returning a variety of objects 23 | downloadFileById(String) 24 | downloadFileByIdToFile(String, File) 25 | downloadFileByIdToStream(String) 26 | 27 | // download the full file by name, returning a variety of objects 28 | downloadFileByName(String, String) 29 | downloadFileByNameToFile(String, String, File) 30 | downloadFileByNameToStream(String, String) 31 | 32 | // download partial content of a file by id, returning a variety of objects 33 | downloadFileRangeById(String, long, long) 34 | downloadFileRangeByIdToFile(String, File, long, long) 35 | downloadFileRangeByIdToStream(String, long, long) 36 | 37 | // download partial content of a file by name, returning a variety of objects 38 | downloadFileRangeByName(String, String, long, long) 39 | downloadFileRangeByNameToFile(String, String, File, long, long) 40 | downloadFileRangeByNameToStream(String, String, long, long) 41 | 42 | // retrieve information on a file 43 | getFileInfo(String) 44 | 45 | // return the headers associated with a file 46 | headFileById(String) 47 | 48 | // list all of the buckets 49 | listBuckets() 50 | 51 | // list file names 52 | listFileNames(String) 53 | listFileNames(String, String, Integer) 54 | 55 | // list file versions 56 | listFileVersions(String) 57 | listFileVersions(String, String) 58 | listFileVersions(String, String, String, Integer) 59 | 60 | // update the bucket type (private or public) 61 | updateBucket(String, BucketType) 62 | 63 | // upload a file 64 | uploadFile(String, String, File) 65 | uploadFile(String, String, File, Map) 66 | uploadFile(String, String, File, String) 67 | uploadFile(String, String, File, String, Map) 68 | 69 | 70 | ``` 71 | 72 | 73 | ## Large File Support 74 | 75 | Large files can range in size from 100MB to 10TB. 76 | 77 | Each large file must consist of at least 2 parts, and all of the parts except the last one must be at least 100MB in size. The last part must contain at least one byte. 78 | 79 | ``` 80 | startLargeFileUpload(String bucketId, String fileName, String mimeType, Map fileInfo) 81 | getUploadPartUrl(String fileId) 82 | uploadLargeFilePart(String fileId, int partNumber, HttpEntity entity, String sha1Checksum) 83 | finishLargeFileUpload(String fileId, String[] partSha1Array) 84 | 85 | // you can list the parts that are not yet finished 86 | listUnfinishedLargeFiles(String bucketId, String startFileId, Integer maxFileCount) 87 | ``` 88 | 89 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2StartLargeFileRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Collections; 6 | import java.util.UUID; 7 | 8 | import org.apache.http.impl.client.CloseableHttpClient; 9 | import org.apache.http.impl.client.HttpClients; 10 | import org.junit.Test; 11 | 12 | import synapticloop.b2.exception.B2ApiException; 13 | import synapticloop.b2.helper.B2TestHelper; 14 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 15 | import synapticloop.b2.response.B2BucketResponse; 16 | import synapticloop.b2.response.B2FileResponse; 17 | import synapticloop.b2.response.B2ListFilesResponse; 18 | import synapticloop.b2.response.B2ListPartsResponse; 19 | import synapticloop.b2.response.B2StartLargeFileResponse; 20 | 21 | public class B2StartLargeFileRequestTest { 22 | 23 | @Test 24 | public void getResponse() throws Exception { 25 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 26 | 27 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 28 | 29 | String privateBucketId = privateBucket.getBucketId(); 30 | final CloseableHttpClient client = HttpClients.createDefault(); 31 | 32 | B2StartLargeFileResponse b2StartLargeFileResponse = new B2StartLargeFileRequest(client, b2AuthorizeAccountResponse, 33 | privateBucketId, UUID.randomUUID().toString(), null, Collections.emptyMap()).getResponse(); 34 | assertNotNull(b2StartLargeFileResponse.getFileId()); 35 | 36 | final B2ListFilesResponse b2ListFilesResponse = new B2ListUnfinishedLargeFilesRequest(HttpClients.createDefault(), 37 | b2AuthorizeAccountResponse, privateBucketId).getResponse(); 38 | assertNull(b2ListFilesResponse.getNextFileId()); 39 | assertEquals(1, b2ListFilesResponse.getFiles().size()); 40 | 41 | final B2GetUploadPartUrlRequest b2GetUploadPartUrlRequest = new B2GetUploadPartUrlRequest(client, 42 | b2AuthorizeAccountResponse, b2StartLargeFileResponse.getFileId()); 43 | assertNotNull(b2GetUploadPartUrlRequest.getResponse().getUploadUrl()); 44 | 45 | final B2ListPartsResponse b2ListPartsResponse = new B2ListPartsRequest(client, b2AuthorizeAccountResponse, 46 | b2StartLargeFileResponse.getFileId()).getResponse(); 47 | assertTrue(b2ListPartsResponse.getFiles().isEmpty()); 48 | 49 | try { 50 | new B2FinishLargeFileRequest(client, b2AuthorizeAccountResponse, 51 | b2StartLargeFileResponse.getFileId(), new String[0]).getResponse(); 52 | fail(); 53 | } 54 | catch(B2ApiException e) { 55 | assertEquals(400, e.getStatus()); 56 | assertEquals("large files must have at least 2 parts", e.getMessage()); 57 | } 58 | 59 | final B2FileResponse b2FileResponse = new B2CancelLargeFileRequest(client, b2AuthorizeAccountResponse, 60 | b2StartLargeFileResponse.getFileId()).getResponse(); 61 | assertEquals(b2StartLargeFileResponse.getFileId(), b2FileResponse.getFileId()); 62 | 63 | B2TestHelper.deleteBucket(privateBucketId); 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2GetUploadUrlResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import synapticloop.b2.exception.B2ApiException; 23 | 24 | public class B2GetUploadUrlResponse extends BaseB2Response { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(B2GetUploadUrlResponse.class); 26 | 27 | private final String bucketId; 28 | private final String uploadUrl; 29 | private final String authorizationToken; 30 | 31 | /** 32 | * Instantiate a get upload URL response with the JSON response as a string from 33 | * the API call. This response is then parsed into the relevant fields. 34 | * 35 | * @param json The response (in JSON format) 36 | * 37 | * @throws B2ApiException if there was an error parsing the response 38 | */ 39 | public B2GetUploadUrlResponse(String json) throws B2ApiException { 40 | super(json); 41 | 42 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 43 | this.uploadUrl = this.readString(B2ResponseProperties.KEY_UPLOAD_URL); 44 | this.authorizationToken = this.readString(B2ResponseProperties.KEY_AUTHORIZATION_TOKEN); 45 | 46 | this.warnOnMissedKeys(); 47 | } 48 | 49 | /** 50 | * Get the bucket id 51 | * 52 | * @return the id of the bucket 53 | */ 54 | public String getBucketId() { return this.bucketId; } 55 | 56 | /** 57 | * Get the URL to be used for uploading this file 58 | * 59 | * @return the URL to be used to upload this file 60 | */ 61 | public String getUploadUrl() { return this.uploadUrl; } 62 | 63 | /** 64 | * Get the authorization token to be used with the file upload 65 | * 66 | * @return the authorization token to be used with the file upload 67 | */ 68 | public String getAuthorizationToken() { return this.authorizationToken; } 69 | 70 | @Override 71 | protected Logger getLogger() { return LOGGER; } 72 | 73 | @Override 74 | public String toString() { 75 | final StringBuilder sb = new StringBuilder("B2GetUploadUrlResponse{"); 76 | sb.append("bucketId='").append(bucketId).append('\''); 77 | sb.append(", uploadUrl='").append(uploadUrl).append('\''); 78 | sb.append(", authorizationToken='").append(authorizationToken).append('\''); 79 | sb.append('}'); 80 | return sb.toString(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2UploadPartRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | 21 | import java.io.IOException; 22 | 23 | import org.apache.http.HttpEntity; 24 | import org.apache.http.HttpHeaders; 25 | import org.apache.http.impl.client.CloseableHttpClient; 26 | import org.apache.http.util.EntityUtils; 27 | 28 | import synapticloop.b2.exception.B2ApiException; 29 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 30 | import synapticloop.b2.response.B2GetUploadPartUrlResponse; 31 | import synapticloop.b2.response.B2ResponseHeaders; 32 | import synapticloop.b2.response.B2UploadPartResponse; 33 | 34 | public class B2UploadPartRequest extends BaseB2Request { 35 | private final HttpEntity entity; 36 | 37 | /** 38 | * @param client Shared HTTP client instance 39 | * @param b2AuthorizeAccountResponse The authorize account response 40 | * @param b2GetUploadUrlResponse An upload authorization token, from b2_start_large_file 41 | * @param partNumber A number from 1 to 10000. The parts uploaded for one file must have contiguous numbers, starting with 1. 42 | * @param entity the http entity to upload 43 | * @param sha1Checksum The SHA1 checksum of the this part of the file. B2 will check this when the part is 44 | * uploaded, to make sure that the data arrived correctly. 45 | */ 46 | public B2UploadPartRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 47 | B2GetUploadPartUrlResponse b2GetUploadUrlResponse, 48 | int partNumber, HttpEntity entity, String sha1Checksum) { 49 | super(client, b2AuthorizeAccountResponse, b2GetUploadUrlResponse.getUploadUrl()); 50 | this.entity = entity; 51 | 52 | this.addHeader(B2ResponseHeaders.HEADER_X_BZ_PART_NUMBER, String.valueOf(partNumber)); 53 | this.addHeader(B2ResponseHeaders.HEADER_X_BZ_CONTENT_SHA1, sha1Checksum); 54 | 55 | // Override generic authorization header 56 | this.addHeader(HttpHeaders.AUTHORIZATION, b2GetUploadUrlResponse.getAuthorizationToken()); 57 | } 58 | 59 | public B2UploadPartResponse getResponse() throws B2ApiException, IOException { 60 | return new B2UploadPartResponse(EntityUtils.toString(executePost(entity).getEntity())); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2GetUploadUrlRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2GetUploadUrlResponse; 27 | 28 | /** 29 | *

Gets an URL to use for uploading files.

30 | * 31 | *

When you upload a file to B2, you must call b2_get_upload_url first to get the URL for uploading directly to the place where the file will be stored.

32 | *

An uploadUrl and upload authorizationToken are valid for 24 hours or until the endpoint rejects an upload

33 | * 34 | * 35 | * This is the interaction class for the b2_get_upload_url api calls, this was 36 | * generated from the backblaze api documentation - which can be found here: 37 | * http://www.backblaze.com/b2/docs/b2_get_upload_url.html 38 | * 39 | * @author synapticloop 40 | */ 41 | public class B2GetUploadUrlRequest extends BaseB2Request { 42 | private static final String B2_GET_UPLOAD_URL = BASE_API_VERSION + "b2_get_upload_url"; 43 | 44 | /** 45 | * Instantiate a get upload URL request 46 | * 47 | * @param client the HTTP client to use 48 | * @param b2AuthorizeAccountResponse the authorize account response 49 | * @param bucketId The ID of the bucket that you want to upload to. 50 | */ 51 | public B2GetUploadUrlRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketId) { 52 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_GET_UPLOAD_URL); 53 | 54 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 55 | } 56 | 57 | /** 58 | * Return the upload url response 59 | * 60 | * @return the upload url response 61 | * 62 | * @throws B2ApiException if something went wrong 63 | * @throws IOException if there was an error communicating with the API service 64 | */ 65 | public B2GetUploadUrlResponse getResponse() throws B2ApiException, IOException { 66 | return new B2GetUploadUrlResponse(EntityUtils.toString(executePost().getEntity())); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2GetUploadPartUrlResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import synapticloop.b2.exception.B2ApiException; 24 | 25 | public class B2GetUploadPartUrlResponse extends BaseB2Response { 26 | private static final Logger LOGGER = LoggerFactory.getLogger(B2GetUploadPartUrlResponse.class); 27 | 28 | private final String fileId; 29 | private final String uploadUrl; 30 | private final String authorizationToken; 31 | 32 | /** 33 | * Instantiate a get upload URL response with the JSON response as a string from 34 | * the API call. This response is then parsed into the relevant fields. 35 | * 36 | * @param json The response (in JSON format) 37 | * 38 | * @throws B2ApiException if there was an error parsing the response 39 | */ 40 | public B2GetUploadPartUrlResponse(String json) throws B2ApiException { 41 | super(json); 42 | 43 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 44 | this.uploadUrl = this.readString(B2ResponseProperties.KEY_UPLOAD_URL); 45 | this.authorizationToken = this.readString(B2ResponseProperties.KEY_AUTHORIZATION_TOKEN); 46 | 47 | this.warnOnMissedKeys(); 48 | } 49 | 50 | /** 51 | * Get the bucket id 52 | * 53 | * @return the id of the bucket 54 | */ 55 | public String getFileId() { return this.fileId; } 56 | 57 | /** 58 | * Get the URL to be used for uploading this file 59 | * 60 | * @return the URL to be used to upload this file 61 | */ 62 | public String getUploadUrl() { return this.uploadUrl; } 63 | 64 | /** 65 | * Get the authorization token to be used with the file upload 66 | * 67 | * @return the authorization token to be used with the file upload 68 | */ 69 | public String getAuthorizationToken() { return this.authorizationToken; } 70 | 71 | @Override 72 | protected Logger getLogger() { return LOGGER; } 73 | 74 | @Override 75 | public String toString() { 76 | final StringBuilder sb = new StringBuilder("B2GetUploadUrlResponse{"); 77 | sb.append("fileId='").append(fileId).append('\''); 78 | sb.append(", uploadUrl='").append(uploadUrl).append('\''); 79 | sb.append(", authorizationToken='").append(authorizationToken).append('\''); 80 | sb.append('}'); 81 | return sb.toString(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/DeleteTestBuckets.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.util.List; 20 | 21 | import synapticloop.b2.helper.B2TestHelper; 22 | import synapticloop.b2.response.B2BucketResponse; 23 | import synapticloop.b2.response.B2FileInfoResponse; 24 | 25 | /** 26 | * This is a utility class to delete all of the test buckets in the backblaze 27 | * service - this will delete all buckets that start with the prefix: 28 | * b2api-test- 29 | * 30 | * 31 | */ 32 | public class DeleteTestBuckets { 33 | 34 | public static void main(String[] args) throws Exception { 35 | String b2AccountId = System.getenv(B2TestHelper.B2_ACCOUNT_ID); 36 | String b2ApplicationKey = System.getenv(B2TestHelper.B2_APPLICATION_KEY); 37 | 38 | boolean isOK = true; 39 | 40 | if(null == b2AccountId) { 41 | System.err.println("Could not find the environment variable '" + B2TestHelper.B2_ACCOUNT_ID + "', cannot continue with tests, exiting..."); 42 | isOK = false; 43 | } 44 | 45 | if(null == b2ApplicationKey) { 46 | System.err.println("Could not find the environment variable '" + B2TestHelper.B2_APPLICATION_KEY + "', cannot continue with tests, exiting..."); 47 | isOK = false; 48 | } 49 | 50 | if(!isOK) { 51 | System.exit(-1); 52 | } 53 | 54 | B2ApiClient client = new B2ApiClient(); 55 | client.authenticate(b2AccountId, b2ApplicationKey); 56 | List listBuckets = client.listBuckets(); 57 | System.out.println("Found " + listBuckets.size() + " buckets."); 58 | for (B2BucketResponse b2BucketResponse : listBuckets) { 59 | if(b2BucketResponse.getBucketName().startsWith(B2TestHelper.B2_BUCKET_PREFIX)) { 60 | // go through and delete all of the files 61 | String bucketId = b2BucketResponse.getBucketId(); 62 | System.out.println("Deleting files in bucket '" + bucketId + "'."); 63 | List files = client.listFileVersions(bucketId).getFiles(); 64 | for (B2FileInfoResponse b2FileInfoResponse : files) { 65 | String fileName = b2FileInfoResponse.getFileName(); 66 | System.out.println("Deleting file version name: '" + fileName + "'."); 67 | client.deleteFileVersion(fileName, b2FileInfoResponse.getFileId()); 68 | } 69 | System.out.println("Deleting bucket '" + bucketId + "'."); 70 | client.deleteBucket(bucketId); 71 | } 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2GetUploadPartUrlRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | 20 | import java.io.IOException; 21 | 22 | /* 23 | * Copyright (c) 2016 iterate GmbH. 24 | * 25 | * All rights reserved. 26 | * 27 | * This code may contain contributions from other parties which, where 28 | * applicable, will be listed in the default build file for the project 29 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 30 | * 31 | * This source code and any derived binaries are covered by the terms and 32 | * conditions of the Licence agreement ("the Licence"). You may not use this 33 | * source code or any derived binaries except in compliance with the Licence. 34 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 35 | * this source code or binaries. 36 | */ 37 | 38 | import org.apache.http.impl.client.CloseableHttpClient; 39 | import org.apache.http.util.EntityUtils; 40 | 41 | import synapticloop.b2.exception.B2ApiException; 42 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 43 | import synapticloop.b2.response.B2GetUploadPartUrlResponse; 44 | 45 | public class B2GetUploadPartUrlRequest extends BaseB2Request { 46 | private static final String B2_GET_UPLOAD_URL = BASE_API_VERSION + "b2_get_upload_part_url"; 47 | 48 | /** 49 | * Instantiate a get upload URL request 50 | * 51 | * @param client the HTTP client to use 52 | * @param b2AuthorizeAccountResponse the authorize account response 53 | * @param fileId The ID of the large file whose parts you want to upload 54 | */ 55 | public B2GetUploadPartUrlRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 56 | String fileId) { 57 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_GET_UPLOAD_URL); 58 | 59 | this.addProperty(B2RequestProperties.KEY_FILE_ID, fileId); 60 | } 61 | 62 | /** 63 | * Return the upload url response 64 | * 65 | * @return the upload url response 66 | * 67 | * @throws B2ApiException if something went wrong 68 | * @throws IOException if there was an error communicating with the API service 69 | */ 70 | public B2GetUploadPartUrlResponse getResponse() throws B2ApiException, IOException { 71 | return new B2GetUploadPartUrlResponse(EntityUtils.toString(executePost().getEntity())); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2ListUnfinishedLargeFilesRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import java.io.IOException; 21 | 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | import org.apache.http.util.EntityUtils; 24 | 25 | import synapticloop.b2.exception.B2ApiException; 26 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 27 | import synapticloop.b2.response.B2ListFilesResponse; 28 | 29 | public class B2ListUnfinishedLargeFilesRequest extends BaseB2Request { 30 | private static final String B2_LIST_UNFINISHED_LARGE_FILES = BASE_API_VERSION + "b2_list_unfinished_large_files"; 31 | 32 | /** 33 | * @param client The http client to use 34 | * @param b2AuthorizeAccountResponse the authorize account response 35 | * @param bucketId The ID of the bucket 36 | */ 37 | public B2ListUnfinishedLargeFilesRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 38 | String bucketId) { 39 | this(client, b2AuthorizeAccountResponse, bucketId, null, null); 40 | } 41 | 42 | /** 43 | * @param client The http client to use 44 | * @param b2AuthorizeAccountResponse the authorize account response 45 | * @param bucketId The ID of the bucket 46 | * @param startFileId The first upload to return. If there is an upload with this ID, it will be returned in 47 | * the list. If not, the first upload after this the first one after this ID. 48 | * @param maxFileCount The maximum number of files to return 49 | */ 50 | public B2ListUnfinishedLargeFilesRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 51 | String bucketId, String startFileId, Integer maxFileCount) { 52 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_LIST_UNFINISHED_LARGE_FILES); 53 | 54 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 55 | if (null != startFileId) { 56 | this.addProperty(B2RequestProperties.KEY_START_FILE_ID, startFileId); 57 | } 58 | if (maxFileCount != null) { 59 | this.addProperty(B2RequestProperties.KEY_MAX_FILE_COUNT, maxFileCount); 60 | } 61 | } 62 | 63 | public B2ListFilesResponse getResponse() throws B2ApiException, IOException { 64 | return new B2ListFilesResponse(EntityUtils.toString(executePost().getEntity())); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2ListPartsRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import java.io.IOException; 21 | 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | import org.apache.http.util.EntityUtils; 24 | 25 | import synapticloop.b2.exception.B2ApiException; 26 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 27 | import synapticloop.b2.response.B2ListPartsResponse; 28 | 29 | public class B2ListPartsRequest extends BaseB2Request { 30 | private static final String B2_LIST_PARTS = BASE_API_VERSION + "b2_list_parts"; 31 | 32 | /** 33 | * @param client The http client to use 34 | * @param b2AuthorizeAccountResponse the authorize account response 35 | * @param fileId The ID of the file, as returned by {@link B2StartLargeFileRequest} 36 | */ 37 | public B2ListPartsRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 38 | String fileId) { 39 | this(client, b2AuthorizeAccountResponse, fileId, null, null); 40 | } 41 | 42 | /** 43 | * @param client The http client to use 44 | * @param b2AuthorizeAccountResponse the authorize account response 45 | * @param fileId The ID of the file, as returned by {@link B2StartLargeFileRequest} 46 | * @param startPartNumber The first part to return. If there is an part with this number, it will be 47 | * returned in the list. If not, the first upload after this the first one after this number. 48 | * @param maxPartCount The maximum number of parts to return from this call. The default value is 100, and the maximum allowed is 1000. 49 | */ 50 | public B2ListPartsRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 51 | String fileId, Integer startPartNumber, Integer maxPartCount) { 52 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_LIST_PARTS); 53 | 54 | this.addProperty(B2RequestProperties.KEY_FILE_ID, fileId); 55 | if (startPartNumber != null) { 56 | this.addProperty(B2RequestProperties.KEY_START_PART_NUMBER, startPartNumber); 57 | } 58 | if (startPartNumber != null) { 59 | this.addProperty(B2RequestProperties.KEY_MAX_PART_COUNT, maxPartCount); 60 | } 61 | } 62 | 63 | public B2ListPartsResponse getResponse() throws B2ApiException, IOException { 64 | return new B2ListPartsResponse(EntityUtils.toString(executePost().getEntity())); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2StartLargeFileResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | 21 | import java.util.Map; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import synapticloop.b2.exception.B2ApiException; 27 | 28 | public class B2StartLargeFileResponse extends BaseB2Response { 29 | private static final Logger LOGGER = LoggerFactory.getLogger(B2StartLargeFileResponse.class); 30 | 31 | private final String fileId; 32 | private final String fileName; 33 | private final String accountId; 34 | private final String bucketId; 35 | private final String contentType; 36 | private final String uploadTimestamp; 37 | 38 | private final Map fileInfo; 39 | 40 | public B2StartLargeFileResponse(String json) throws B2ApiException { 41 | super(json); 42 | 43 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 44 | this.fileName = this.readString(B2ResponseProperties.KEY_FILE_NAME); 45 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 46 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 47 | this.contentType = this.readString(B2ResponseProperties.KEY_CONTENT_TYPE); 48 | this.fileInfo = this.readMap(B2ResponseProperties.KEY_FILE_INFO); 49 | this.uploadTimestamp = this.readString(B2ResponseProperties.KEY_UPLOAD_TIMESTAMP); 50 | 51 | this.warnOnMissedKeys(); 52 | } 53 | 54 | public String getBucketId() { return this.bucketId; } 55 | 56 | public String getFileId() { return this.fileId; } 57 | 58 | public String getFileName() { return this.fileName; } 59 | 60 | public String getAccountId() { return this.accountId; } 61 | 62 | public String getContentType() { return this.contentType; } 63 | 64 | /** 65 | * Get the upload timestamp of the file 66 | * 67 | * @return the upload timestamp of the file 68 | */ 69 | public String getUploadTimestamp() { return this.uploadTimestamp; } 70 | 71 | public Map getFileInfo() { return this.fileInfo; } 72 | 73 | @Override 74 | protected Logger getLogger() { return LOGGER; } 75 | 76 | @Override 77 | public String toString() { 78 | final StringBuilder sb = new StringBuilder("B2StartLargeFileResponse{"); 79 | sb.append("fileId='").append(fileId).append('\''); 80 | sb.append(", fileName='").append(fileName).append('\''); 81 | sb.append(", bucketId='").append(bucketId).append('\''); 82 | sb.append(", contentType='").append(contentType).append('\''); 83 | sb.append(", fileInfo=").append(fileInfo); 84 | sb.append('}'); 85 | return sb.toString(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2DeleteFileVersionRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2DeleteFileVersionResponse; 27 | 28 | /** 29 | *

Deletes one version of a file from B2.

30 | * 31 | *

If the version you delete is the latest version, and there are older 32 | * versions, then the most recent older version will become the current 33 | * version, and be the one that you'll get when downloading by name. See 34 | * the File Versions page for more details.

35 | * 36 | * 37 | * This is the interaction class for the b2_delete_file_version api calls, this was 38 | * generated from the backblaze api documentation - which can be found here: 39 | * 40 | * http://www.backblaze.com/b2/docs/b2_delete_file_version.html 41 | * 42 | * @author synapticloop 43 | */ 44 | public class B2DeleteFileVersionRequest extends BaseB2Request { 45 | private static final String B2_DELETE_FILE_VERSION = BASE_API_VERSION + "b2_delete_file_version"; 46 | 47 | /** 48 | * Instantiate a delete file version request 49 | * 50 | * @param client Shared HTTP client instance 51 | * @param b2AuthorizeAccountResponse the authorize account response 52 | * @param fileName the name (and path) of the file to delete 53 | * @param fileId The ID of the file, as returned by {@link B2UploadFileRequest}, 54 | * {@link B2ListFileNamesRequest}, or {@link B2ListFileVersionsRequest}. 55 | */ 56 | public B2DeleteFileVersionRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String fileName, String fileId) { 57 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_DELETE_FILE_VERSION); 58 | 59 | this.addProperty(B2RequestProperties.KEY_FILE_NAME, fileName); 60 | this.addProperty(B2RequestProperties.KEY_FILE_ID, fileId); 61 | } 62 | 63 | /** 64 | * Return the response for the call 65 | * 66 | * @return the delete file version response 67 | * 68 | * @throws B2ApiException if there was an error with the call 69 | * @throws IOException if there was an error communicating with the API service 70 | */ 71 | public B2DeleteFileVersionResponse getResponse() throws B2ApiException, IOException { 72 | return new B2DeleteFileVersionResponse(EntityUtils.toString(executePost().getEntity())); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2AuthorizeAccountRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.commons.codec.binary.Base64; 22 | import org.apache.http.HttpHeaders; 23 | import org.apache.http.client.methods.CloseableHttpResponse; 24 | import org.apache.http.impl.client.CloseableHttpClient; 25 | import org.apache.http.util.EntityUtils; 26 | 27 | import synapticloop.b2.exception.B2ApiException; 28 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 29 | 30 | /** 31 | *

Used to log in to the B2 API. Returns an authorization token that can be 32 | * used for account-level operations, and a URL that should be used as the base 33 | * URL for subsequent API calls.

34 | * 35 | * An HTTP basic auth value constructed as follows: 36 | *
    37 | *
  • The B2 account id and B2 application key for the account are combined 38 | * into a string in the format "accountId:applicationKey".
  • 39 | *
  • The combined string is Base64 encoded.
  • 40 | *
  • "Basic " is put before the encoded string.
  • 41 | *
42 | * 43 | * This is the interaction class for the b2_authorize_account api 44 | * calls, this was generated from the backblaze api documentation - which can be 45 | * found here: 46 | * 47 | * http://www.backblaze.com/b2/docs/b2_authorize_account.html 48 | * 49 | * @author synapticloop 50 | */ 51 | public class B2AuthorizeAccountRequest extends BaseB2Request { 52 | private static final String B2_AUTHORIZE_ACCOUNT = BASE_API + "b2_authorize_account"; 53 | 54 | /** 55 | * Instantiate a new authorize account request 56 | * 57 | * @param client Shared HTTP client instance 58 | * @param accountId the account id 59 | * @param applicationKey the application key 60 | */ 61 | public B2AuthorizeAccountRequest(CloseableHttpClient client, String accountId, String applicationKey) { 62 | 63 | super(client, B2_AUTHORIZE_ACCOUNT); 64 | 65 | this.addHeader(HttpHeaders.AUTHORIZATION, String.format("Basic %s", Base64.encodeBase64String((String.format("%s:%s", accountId, applicationKey)).getBytes()))); 66 | } 67 | 68 | /** 69 | * Execute the call and return the authorize response 70 | * 71 | * @return the authorize response 72 | * 73 | * @throws B2ApiException if there was an error with the call 74 | * @throws IOException if there was an error communicating with the API service 75 | */ 76 | public B2AuthorizeAccountResponse getResponse() throws B2ApiException, IOException { 77 | final CloseableHttpResponse httpResponse = executeGet(); 78 | return new B2AuthorizeAccountResponse(EntityUtils.toString(httpResponse.getEntity())); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2UploadPartResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * Copyright (c) 2016 iterate GmbH. 6 | * 7 | * All rights reserved. 8 | * 9 | * This code may contain contributions from other parties which, where 10 | * applicable, will be listed in the default build file for the project 11 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 12 | * 13 | * This source code and any derived binaries are covered by the terms and 14 | * conditions of the Licence agreement ("the Licence"). You may not use this 15 | * source code or any derived binaries except in compliance with the Licence. 16 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 17 | * this source code or binaries. 18 | */ 19 | 20 | import org.json.JSONObject; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | 26 | public class B2UploadPartResponse extends BaseB2Response { 27 | private static final Logger LOGGER = LoggerFactory.getLogger(B2UploadPartResponse.class); 28 | 29 | private final String fileId; 30 | private final Integer partNumber; 31 | private final Long contentLength; 32 | private final String contentSha1; 33 | private final Long uploadTimestamp; 34 | 35 | public B2UploadPartResponse(String json) throws B2ApiException { 36 | super(json); 37 | 38 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 39 | this.partNumber = this.readInt(B2ResponseProperties.KEY_PART_NUMBER); 40 | this.contentLength = this.readLong(B2ResponseProperties.KEY_CONTENT_LENGTH); 41 | this.contentSha1 = this.readString(B2ResponseProperties.KEY_CONTENT_SHA1); 42 | this.uploadTimestamp = this.readLong(B2ResponseProperties.KEY_UPLOAD_TIMESTAMP); 43 | 44 | this.warnOnMissedKeys(); 45 | } 46 | 47 | public B2UploadPartResponse(final JSONObject response) throws B2ApiException { 48 | super(response); 49 | 50 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 51 | this.partNumber = this.readInt(B2ResponseProperties.KEY_PART_NUMBER); 52 | this.contentLength = this.readLong(B2ResponseProperties.KEY_CONTENT_LENGTH); 53 | this.contentSha1 = this.readString(B2ResponseProperties.KEY_CONTENT_SHA1); 54 | this.uploadTimestamp = this.readLong(B2ResponseProperties.KEY_UPLOAD_TIMESTAMP); 55 | 56 | this.warnOnMissedKeys(); 57 | } 58 | 59 | public String getFileId() { 60 | return fileId; 61 | } 62 | 63 | public Integer getPartNumber() { 64 | return partNumber; 65 | } 66 | 67 | public Long getContentLength() { 68 | return contentLength; 69 | } 70 | 71 | public String getContentSha1() { 72 | return contentSha1; 73 | } 74 | 75 | /** 76 | * Return the timestamp that the part was uploaded 77 | * 78 | * @return the timestamp for when the part was uploaded 79 | */ 80 | public Long getUploadTimestamp() { return this.uploadTimestamp; } 81 | 82 | @Override 83 | protected Logger getLogger() { return LOGGER; } 84 | 85 | @Override 86 | public String toString() { 87 | final StringBuilder sb = new StringBuilder("B2UploadPartResponse{"); 88 | sb.append("fileId='").append(fileId).append('\''); 89 | sb.append(", partNumber=").append(partNumber); 90 | sb.append(", contentLength=").append(contentLength); 91 | sb.append(", contentSha1='").append(contentSha1).append('\''); 92 | sb.append('}'); 93 | return sb.toString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2UpdateBucketRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | import org.json.JSONArray; 24 | 25 | import synapticloop.b2.BucketType; 26 | import synapticloop.b2.LifecycleRule; 27 | import synapticloop.b2.exception.B2ApiException; 28 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 29 | import synapticloop.b2.response.B2BucketResponse; 30 | 31 | /** 32 | *

Update an existing bucket.

33 | * 34 | *

Modifies the bucketType of an existing bucket. Can be used to allow everyone to download the contents of the bucket without providing any authorization, or to prevent anyone from downloading the contents of the bucket without providing a bucket auth token.

35 | * 36 | * 37 | * This is the interaction class for the b2_update_bucket api calls, this was 38 | * generated from the backblaze api documentation - which can be found here: 39 | * http://www.backblaze.com/b2/docs/b2_update_bucket.html 40 | * 41 | * @author synapticloop 42 | */ 43 | public class B2UpdateBucketRequest extends BaseB2Request { 44 | 45 | private static final String B2_UPDATE_BUCKET = BASE_API_VERSION + "b2_update_bucket"; 46 | 47 | /** 48 | * Create an update bucket request 49 | * 50 | * @param client The http client to use 51 | * @param b2AuthorizeAccountResponse the authorize account response 52 | * @param bucketId the id of the bucket to change 53 | * @param bucketType the type of bucket to change to 54 | */ 55 | public B2UpdateBucketRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketId, BucketType bucketType, LifecycleRule... lifecycleRules) { 56 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_UPDATE_BUCKET); 57 | 58 | this.addProperty(B2RequestProperties.KEY_ACCOUNT_ID, b2AuthorizeAccountResponse.getAccountId()); 59 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 60 | this.addProperty(B2RequestProperties.KEY_BUCKET_TYPE, bucketType.toString()); 61 | this.addProperty(B2RequestProperties.KEY_LIFECYCLE_RULES, new JSONArray(lifecycleRules)); 62 | } 63 | 64 | /** 65 | * Return the bucket response 66 | * 67 | * @return the bucket response 68 | * 69 | * @throws B2ApiException if something went wrong 70 | * @throws IOException if there was an error communicating with the API service 71 | */ 72 | public B2BucketResponse getResponse() throws B2ApiException, IOException { 73 | return new B2BucketResponse(EntityUtils.toString(executePost().getEntity())); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2DeleteFileVersionRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.io.FileWriter; 7 | 8 | import org.apache.http.impl.client.CloseableHttpClient; 9 | import org.apache.http.impl.client.HttpClients; 10 | import org.junit.Test; 11 | 12 | import synapticloop.b2.helper.B2TestHelper; 13 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 14 | import synapticloop.b2.response.B2BucketResponse; 15 | import synapticloop.b2.response.B2DeleteFileVersionResponse; 16 | import synapticloop.b2.response.B2DownloadFileResponse; 17 | import synapticloop.b2.response.B2FileResponse; 18 | import synapticloop.b2.response.B2GetUploadUrlResponse; 19 | import synapticloop.b2.util.ChecksumHelper; 20 | 21 | public class B2DeleteFileVersionRequestTest { 22 | 23 | @Test 24 | public void testDeleteFileVersion() throws Exception { 25 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 26 | B2BucketResponse b2BucketResponse = B2TestHelper.createRandomPrivateBucket(); 27 | B2FileResponse b2FileResponseIn = B2TestHelper.uploadTemporaryFileToBucket(b2BucketResponse.getBucketId()); 28 | 29 | B2DeleteFileVersionResponse b2DeleteFileVersionResponse = new B2DeleteFileVersionRequest(HttpClients.createDefault(), 30 | b2AuthorizeAccountResponse, b2FileResponseIn.getFileName(), b2FileResponseIn.getFileId()).getResponse(); 31 | 32 | assertEquals(b2FileResponseIn.getFileId(), b2DeleteFileVersionResponse.getFileId()); 33 | assertEquals(b2FileResponseIn.getFileName(), b2DeleteFileVersionResponse.getFileName()); 34 | 35 | B2TestHelper.deleteBucket(b2BucketResponse.getBucketId()); 36 | } 37 | 38 | @Test 39 | public void testDeleteFileVersionWithWhitespace() throws Exception { 40 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 41 | B2BucketResponse b2BucketResponse = B2TestHelper.createRandomPrivateBucket(); 42 | 43 | B2GetUploadUrlResponse b2GetUploadUrlResponse = B2TestHelper.getUploadUrl(b2BucketResponse.getBucketId()); 44 | File file; 45 | file = File.createTempFile("test/path/backblaze-api-test whitespace", ".txt"); 46 | FileWriter fileWriter = new FileWriter(file); 47 | fileWriter.write("hello whitespace!"); 48 | fileWriter.flush(); 49 | fileWriter.close(); 50 | file.deleteOnExit(); 51 | final CloseableHttpClient client = HttpClients.createDefault(); 52 | final B2FileResponse b2FileResponseIn = new B2UploadFileRequest(client, b2AuthorizeAccountResponse, 53 | b2GetUploadUrlResponse, file.getName(), file, ChecksumHelper.calculateSha1(file)).getResponse(); 54 | 55 | final B2DownloadFileResponse b2DownloadFileResponse = new B2DownloadFileByIdRequest(client, b2AuthorizeAccountResponse, b2FileResponseIn.getFileId()).getResponse(); 56 | assertEquals(b2FileResponseIn.getFileId(), b2DownloadFileResponse.getFileId()); 57 | assertNotNull(b2DownloadFileResponse.getContent()); 58 | 59 | B2DeleteFileVersionResponse b2DeleteFileVersionResponse = new B2DeleteFileVersionRequest(client, 60 | b2AuthorizeAccountResponse, b2FileResponseIn.getFileName(), b2FileResponseIn.getFileId()).getResponse(); 61 | 62 | assertEquals(b2FileResponseIn.getFileId(), b2DeleteFileVersionResponse.getFileId()); 63 | assertEquals(b2FileResponseIn.getFileName(), b2DeleteFileVersionResponse.getFileName()); 64 | 65 | B2TestHelper.deleteBucket(b2BucketResponse.getBucketId()); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2ListFilesResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import org.json.JSONArray; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import synapticloop.b2.exception.B2ApiException; 27 | 28 | public class B2ListFilesResponse extends BaseB2Response { 29 | private static final Logger LOGGER = LoggerFactory.getLogger(B2ListFilesResponse.class); 30 | 31 | private final List files; 32 | private final String nextFileName; 33 | private final String nextFileId; 34 | 35 | /** 36 | * Instantiate a list files response with the JSON response as a 37 | * string from the API call. This response is then parsed into the 38 | * relevant fields. 39 | * 40 | * @param json the response (in JSON format) 41 | * 42 | * @throws B2ApiException if there was an error parsing the response 43 | */ 44 | public B2ListFilesResponse(String json) throws B2ApiException { 45 | super(json); 46 | 47 | this.nextFileName = this.readString(B2ResponseProperties.KEY_NEXT_FILE_NAME); 48 | this.nextFileId = this.readString(B2ResponseProperties.KEY_NEXT_FILE_ID); 49 | 50 | JSONArray filesArray = this.readObjects(B2ResponseProperties.KEY_FILES); 51 | 52 | files = new ArrayList(); 53 | for(int i = 0; i < filesArray.length(); i ++) { 54 | files.add(new B2FileInfoResponse(filesArray.optJSONObject(i))); 55 | } 56 | 57 | this.warnOnMissedKeys(); 58 | } 59 | 60 | /** 61 | * get the next file name that is the next result to be returned after this 62 | * result set - or null if there are no more files 63 | * 64 | * @return the next file name to start the next iteration (or null if no next file) 65 | */ 66 | public String getNextFileName() { return this.nextFileName; } 67 | 68 | /** 69 | * get the next file id that is the next result to be returned after this 70 | * result set - or null if there are no more files 71 | * 72 | * @return the next file id to start the next iteration (or null if no next file id) 73 | */ 74 | public String getNextFileId() { return this.nextFileId; } 75 | 76 | /** 77 | * Return the list of files include file info 78 | * 79 | * @return the list of files for this request 80 | */ 81 | public List getFiles() { return this.files; } 82 | 83 | @Override 84 | protected Logger getLogger() { return LOGGER; } 85 | 86 | @Override 87 | public String toString() { 88 | final StringBuilder sb = new StringBuilder("B2ListFilesResponse{"); 89 | sb.append("files=").append(files); 90 | sb.append(", nextFileName='").append(nextFileName).append('\''); 91 | sb.append(", nextFileId='").append(nextFileId).append('\''); 92 | sb.append('}'); 93 | return sb.toString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2HeadFileByIdRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | 23 | import synapticloop.b2.exception.B2ApiException; 24 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 25 | import synapticloop.b2.response.B2DownloadFileResponse; 26 | 27 | /** 28 | *

Gets information on one file from B2.

29 | * 30 | *

NO file content is returned with this request 31 | * 32 | *

The response contains the following headers, which contain the same information they did when the file was uploaded:

33 | * 34 | *
    35 | *
  • Content-Length
  • 36 | *
  • Content-Type
  • 37 | *
  • X-Bz-File-Id
  • 38 | *
  • X-Bz-File-Name
  • 39 | *
  • X-Bz-Content-Sha1
  • 40 | *
  • X-Bz-Info-*
  • 41 | *
42 | * 43 | *

HEAD requests are also supported, and work just like a GET, except that the 44 | * body of the response is not included. All of the same headers, including 45 | * Content-Length are returned. See the B2HeadFileByIdRequest

46 | * 47 | *

If the bucket containing the file is set to require authorization, then you 48 | * must supply the bucket's auth token in the Authorzation header.

49 | * * 50 | * This is the interaction class for the b2_download_file_by_id 51 | * api calls, this was generated from the backblaze api documentation - which 52 | * can be found here: 53 | * 54 | * http://www.backblaze.com/b2/docs/b2_download_file_by_id.html 55 | * 56 | * @author synapticloop 57 | */ 58 | public class B2HeadFileByIdRequest extends BaseB2Request { 59 | private static final String B2_DOWNLOAD_FILE_BY_ID = BASE_API_VERSION + "b2_download_file_by_id"; 60 | 61 | /** 62 | * Create a head file by Id request which returns the information about the 63 | * file and any attached file information 64 | * 65 | * @param client The HTTPClient to use 66 | * @param b2AuthorizeAccountResponse the authorize account response 67 | * @param fileId the id of the file to request information for 68 | */ 69 | public B2HeadFileByIdRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String fileId) { 70 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getDownloadUrl() + B2_DOWNLOAD_FILE_BY_ID); 71 | this.addParameter(B2RequestProperties.KEY_FILE_ID, fileId); 72 | } 73 | 74 | /** 75 | * Return the response for the HEAD request 76 | * 77 | * @return the download file response - note that this does not contain any body content 78 | * 79 | * @throws B2ApiException if something went wrong 80 | * @throws IOException if there was an error communicating with the API service 81 | */ 82 | public B2DownloadFileResponse getResponse() throws B2ApiException, IOException { 83 | return new B2DownloadFileResponse(this.executeHead()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2UploadPartRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Collections; 6 | import java.util.UUID; 7 | 8 | import org.apache.http.entity.StringEntity; 9 | import org.apache.http.impl.client.CloseableHttpClient; 10 | import org.apache.http.impl.client.HttpClients; 11 | 12 | import synapticloop.b2.exception.B2ApiException; 13 | import synapticloop.b2.helper.B2TestHelper; 14 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 15 | import synapticloop.b2.response.B2BucketResponse; 16 | import synapticloop.b2.response.B2FileResponse; 17 | import synapticloop.b2.response.B2GetUploadPartUrlResponse; 18 | import synapticloop.b2.response.B2ListPartsResponse; 19 | import synapticloop.b2.response.B2StartLargeFileResponse; 20 | import synapticloop.b2.response.B2UploadPartResponse; 21 | 22 | public class B2UploadPartRequestTest { 23 | 24 | // this is expected until the large file support goes live 25 | public void getResponse() throws Exception { 26 | B2AuthorizeAccountResponse b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 27 | 28 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 29 | 30 | String privateBucketId = privateBucket.getBucketId(); 31 | final CloseableHttpClient client = HttpClients.createDefault(); 32 | 33 | B2StartLargeFileResponse b2StartLargeFileResponse = new B2StartLargeFileRequest(client, b2AuthorizeAccountResponse, 34 | privateBucketId, UUID.randomUUID().toString(), null, Collections.emptyMap()).getResponse(); 35 | assertNotNull(b2StartLargeFileResponse.getFileId()); 36 | 37 | final B2GetUploadPartUrlResponse b2GetUploadPartUrlResponse1 = new B2GetUploadPartUrlRequest(client, 38 | b2AuthorizeAccountResponse, b2StartLargeFileResponse.getFileId()).getResponse(); 39 | final B2UploadPartResponse b2UploadPartResponse1 = new B2UploadPartRequest(client, b2AuthorizeAccountResponse, b2GetUploadPartUrlResponse1, 1, 40 | new StringEntity(B2TestHelper.DUMMY_FILE_CONTENT), "430ce34d020724ed75a196dfc2ad67c77772d169").getResponse(); 41 | assertEquals("430ce34d020724ed75a196dfc2ad67c77772d169", b2UploadPartResponse1.getContentSha1()); 42 | 43 | final B2GetUploadPartUrlResponse b2GetUploadPartUrlResponse2 = new B2GetUploadPartUrlRequest(client, 44 | b2AuthorizeAccountResponse, b2StartLargeFileResponse.getFileId()).getResponse(); 45 | final B2UploadPartResponse b2UploadPartResponse2 = new B2UploadPartRequest(client, b2AuthorizeAccountResponse, b2GetUploadPartUrlResponse2, 2, 46 | new StringEntity(B2TestHelper.DUMMY_FILE_CONTENT), "430ce34d020724ed75a196dfc2ad67c77772d169").getResponse(); 47 | assertEquals("430ce34d020724ed75a196dfc2ad67c77772d169", b2UploadPartResponse2.getContentSha1()); 48 | 49 | final B2ListPartsResponse b2ListPartsResponse = new B2ListPartsRequest(client, b2AuthorizeAccountResponse, 50 | b2StartLargeFileResponse.getFileId()).getResponse(); 51 | assertEquals(2, b2ListPartsResponse.getFiles().size()); 52 | 53 | try { 54 | new B2FinishLargeFileRequest(client, b2AuthorizeAccountResponse, 55 | b2StartLargeFileResponse.getFileId(), new String[]{"430ce34d020724ed75a196dfc2ad67c77772d169", "430ce34d020724ed75a196dfc2ad67c77772d169"}).getResponse(); 56 | fail(); 57 | } catch (B2ApiException e) { 58 | assertEquals(400, e.getStatus()); 59 | assertEquals("Part number 1 is smaller than 100000000 bytes", e.getMessage()); 60 | } 61 | 62 | final B2FileResponse b2FileResponse = new B2CancelLargeFileRequest(client, b2AuthorizeAccountResponse, 63 | b2StartLargeFileResponse.getFileId()).getResponse(); 64 | assertEquals(b2StartLargeFileResponse.getFileId(), b2FileResponse.getFileId()); 65 | 66 | B2TestHelper.deleteBucket(privateBucketId); 67 | 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2CreateBucketRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.impl.client.CloseableHttpClient; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | import synapticloop.b2.BucketType; 25 | import synapticloop.b2.exception.B2ApiException; 26 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 27 | import synapticloop.b2.response.B2BucketResponse; 28 | 29 | /** 30 | *

Creates a new bucket. A bucket belongs to the account used to create it.

31 | * 32 | *

Buckets can be named. The name must be globally unique. No account can 33 | * use a bucket with the same name. Buckets are assigned a unique bucketId 34 | * which is used when uploading, downloading, or deleting files.

35 | * 36 | * This is the interaction class for the b2_create_bucket api 37 | * calls, this was generated from the backblaze api documentation - which can 38 | * be found here: 39 | * 40 | * http://www.backblaze.com/b2/docs/b2_create_bucket.html 41 | * 42 | * @author synapticloop 43 | */ 44 | public class B2CreateBucketRequest extends BaseB2Request { 45 | private static final String B2_CREATE_BUCKET = BASE_API_VERSION + "b2_create_bucket"; 46 | 47 | /** 48 | * Instantiate a new create bucket request 49 | * 50 | * @param client Shared HTTP client instance 51 | * @param b2AuthorizeAccountResponse the authorize account response 52 | * @param bucketName The name to give the new bucket. Bucket names must be 53 | * a minimum of 6 and a maximum of 50 characters long, and must be globally 54 | * unique; two different B2 accounts cannot have buckets with the same name. 55 | * Bucket names can consist of: letters, digits, and "-". Bucket names cannot 56 | * start with "b2-"; these are reserved for internal Backblaze use. 57 | * @param bucketType the type of bucket to create. Either "allPublic", meaning 58 | * that files in this bucket can be downloaded by anybody, or "allPrivate", 59 | */ 60 | public B2CreateBucketRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketName, BucketType bucketType) { 61 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_CREATE_BUCKET); 62 | 63 | this.addProperty(B2RequestProperties.KEY_ACCOUNT_ID, b2AuthorizeAccountResponse.getAccountId()); 64 | this.addProperty(B2RequestProperties.KEY_BUCKET_NAME, bucketName); 65 | this.addProperty(B2RequestProperties.KEY_BUCKET_TYPE, bucketType.toString()); 66 | } 67 | 68 | /** 69 | * Get the create bucket response 70 | * 71 | * @return the created bucket response 72 | * 73 | * @throws B2ApiException if there was an error with the call 74 | * @throws IOException if there was an error communicating with the API service 75 | */ 76 | public B2BucketResponse getResponse() throws B2ApiException, IOException { 77 | return new B2BucketResponse(EntityUtils.toString(executePost().getEntity())); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/exception/B2ApiException.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.exception; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import org.json.JSONException; 20 | import org.json.JSONObject; 21 | 22 | public class B2ApiException extends Exception { 23 | private static final long serialVersionUID = -7345341271403812967L; 24 | 25 | private String code; 26 | private String message; 27 | private int status; 28 | 29 | /** 30 | * Retry-After header value (in seconds) 31 | */ 32 | private Integer retry; 33 | 34 | private final String json; 35 | 36 | /** 37 | * Create a new B2Api Exception with a message and root cause. If the message 38 | * is in JSON (as returned by the backblaze B2 api) format, this message will 39 | * be parsed and the following information extracted: 40 | * 41 | *
    42 | *
  • status - The numeric HTTP status code. Always matches the status in the HTTP response.
  • 43 | *
  • code - A single-identifier code that identifies the error.
  • 44 | *
  • message - A human-readable message, in English, saying what went wrong.
  • 45 | *
46 | * 47 | * @param json The message of the exception 48 | * @param cause the root cause of the exception 49 | */ 50 | public B2ApiException(String json, Throwable cause) { 51 | super(json, cause); 52 | this.json = json; 53 | this.parse(json); 54 | } 55 | 56 | 57 | private void parse(String json) { 58 | if (null != json) { 59 | try { 60 | JSONObject jsonObject = new JSONObject(json); 61 | this.message = jsonObject.optString("message", null); 62 | this.status = jsonObject.optInt("status", -1); 63 | this.code = jsonObject.optString("code", null); 64 | 65 | } catch (JSONException ex) { 66 | // Ignore 67 | this.message = json; 68 | } 69 | } 70 | } 71 | 72 | /** 73 | * @param retry Value in seconds 74 | * 75 | * @return the exception with retry 76 | */ 77 | public B2ApiException withRetry(Integer retry) { 78 | this.retry = retry; 79 | return this; 80 | } 81 | 82 | /** 83 | * Return the backblaze error code 84 | * 85 | * @return the backblaze error code 86 | */ 87 | public String getCode() { 88 | return this.code; 89 | } 90 | 91 | /** 92 | * If the original message was in valid JSON format, return the 'message' 93 | * part, else the message for the exception. 94 | * 95 | * @return the message 96 | */ 97 | public String getMessage() { 98 | return this.message; 99 | } 100 | 101 | /** 102 | * Return the original message for the exception, which is a JSON formatted 103 | * string 104 | * 105 | * @return the original message text 106 | */ 107 | public String getJson() { 108 | return this.json; 109 | } 110 | 111 | /** 112 | * Return the HTTP status of the returned call, or null if the exception was 113 | * not generated through an HTTP call. 114 | * 115 | * @return the HTTP status code 116 | */ 117 | public int getStatus() { 118 | return this.status; 119 | } 120 | 121 | /** 122 | * Retry-After header value (in seconds) 123 | * 124 | * @return Value in seconds or null if not Retry-After header in response 125 | */ 126 | public Integer getRetry() { 127 | return retry; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2StartLargeFileRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.util.Map; 21 | 22 | /* 23 | * Copyright (c) 2016 iterate GmbH. 24 | * 25 | * All rights reserved. 26 | * 27 | * This code may contain contributions from other parties which, where 28 | * applicable, will be listed in the default build file for the project 29 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 30 | * 31 | * This source code and any derived binaries are covered by the terms and 32 | * conditions of the Licence agreement ("the Licence"). You may not use this 33 | * source code or any derived binaries except in compliance with the Licence. 34 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 35 | * this source code or binaries. 36 | */ 37 | 38 | import org.apache.http.impl.client.CloseableHttpClient; 39 | import org.apache.http.util.EntityUtils; 40 | import org.slf4j.Logger; 41 | import org.slf4j.LoggerFactory; 42 | 43 | import synapticloop.b2.exception.B2ApiException; 44 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 45 | import synapticloop.b2.response.B2StartLargeFileResponse; 46 | 47 | public class B2StartLargeFileRequest extends BaseB2Request { 48 | private static final Logger LOGGER = LoggerFactory.getLogger(B2StartLargeFileRequest.class); 49 | 50 | private static final String B2_START_LARGE_FILE = BASE_API_VERSION + "b2_start_large_file"; 51 | protected static final String CONTENT_TYPE_VALUE_B2_X_AUTO = "b2/x-auto"; 52 | 53 | /** 54 | * Create a new B2 Start large file request 55 | * 56 | * @param client the HTTP client to use 57 | * @param b2AuthorizeAccountResponse the authorise account response 58 | * @param bucketId the id of the bucket to upload to 59 | * @param fileName the name of the file 60 | * @param mimeType the mimeType (optional, will default to 'b2/x-auto' which 61 | * backblaze will attempt to determine automatically) 62 | * @param fileInfo the file info map which are passed through as key value 63 | * pairs in a jsonObject named 'fileInfo' 64 | * 65 | * @throws B2ApiException if something went wrong 66 | */ 67 | public B2StartLargeFileRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 68 | String bucketId, String fileName, 69 | String mimeType, Map fileInfo) throws B2ApiException { 70 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getApiUrl() + B2_START_LARGE_FILE); 71 | 72 | this.addProperty(B2RequestProperties.KEY_BUCKET_ID, bucketId); 73 | this.addProperty(B2RequestProperties.KEY_FILE_NAME, fileName); 74 | if(null == mimeType) { 75 | this.addProperty(B2RequestProperties.KEY_CONTENT_TYPE, CONTENT_TYPE_VALUE_B2_X_AUTO); 76 | } else { 77 | this.addProperty(B2RequestProperties.KEY_CONTENT_TYPE, mimeType); 78 | } 79 | if (null != fileInfo) { 80 | this.addProperty(B2RequestProperties.KEY_FILE_INFO, fileInfo); 81 | } 82 | } 83 | 84 | /** 85 | * Return the start large file response 86 | * 87 | * @return the start large file response 88 | * 89 | * @throws B2ApiException if something went wrong 90 | * @throws IOException if there was an error communicating with the API service 91 | */ 92 | public B2StartLargeFileResponse getResponse() throws B2ApiException, IOException { 93 | return new B2StartLargeFileResponse(EntityUtils.toString(executePost().getEntity())); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2HideFileResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | import java.util.Map; 4 | 5 | /* 6 | * Copyright (c) 2016 - 2017 Synapticloop. 7 | * 8 | * All rights reserved. 9 | * 10 | * This code may contain contributions from other parties which, where 11 | * applicable, will be listed in the default build file for the project 12 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 13 | * 14 | * This source code and any derived binaries are covered by the terms and 15 | * conditions of the Licence agreement ("the Licence"). You may not use this 16 | * source code or any derived binaries except in compliance with the Licence. 17 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 18 | * this source code or binaries. 19 | */ 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import synapticloop.b2.Action; 25 | import synapticloop.b2.exception.B2ApiException; 26 | 27 | public class B2HideFileResponse extends BaseB2Response { 28 | private static final Logger LOGGER = LoggerFactory.getLogger(B2HideFileResponse.class); 29 | 30 | private final String fileId; 31 | private final String fileName; 32 | private Action action; 33 | private final Integer size; 34 | private final Long uploadTimestamp; 35 | 36 | private final Long contentLength; 37 | private final String contentType; 38 | private final String contentSha1; 39 | private final Map fileInfo; 40 | 41 | /** 42 | * Instantiate a hide file response with the JSON response as a string from 43 | * the API call. This response is then parsed into the relevant fields. 44 | * 45 | * @param json The response (in JSON format) 46 | * 47 | * @throws B2ApiException if there was an error parsing the response 48 | */ 49 | public B2HideFileResponse(String json) throws B2ApiException { 50 | super(json); 51 | 52 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 53 | this.fileName = this.readString(B2ResponseProperties.KEY_FILE_NAME); 54 | 55 | final String action = this.readString(B2ResponseProperties.KEY_ACTION); 56 | if(null != action) { 57 | try { 58 | this.action = Action.valueOf(action); 59 | } 60 | catch(IllegalArgumentException e) { 61 | LOGGER.warn("Unknown action value " + action); 62 | this.action = null; 63 | } 64 | } else { 65 | this.action = null; 66 | } 67 | 68 | this.size = this.readInt(B2ResponseProperties.KEY_SIZE); 69 | this.uploadTimestamp = this.readLong(B2ResponseProperties.KEY_UPLOAD_TIMESTAMP); 70 | this.contentLength = this.readLong(B2ResponseProperties.KEY_CONTENT_LENGTH); 71 | this.contentType =this.readString(B2ResponseProperties.KEY_CONTENT_TYPE); 72 | this.contentSha1 =this.readString(B2ResponseProperties.KEY_CONTENT_SHA1); 73 | this.fileInfo = this.readMap(B2ResponseProperties.KEY_FILE_INFO); 74 | 75 | this.warnOnMissedKeys(); 76 | } 77 | 78 | public String getFileId() { return this.fileId; } 79 | 80 | public String getFileName() { return this.fileName; } 81 | 82 | public Action getAction() { return this.action; } 83 | 84 | public Integer getSize() { return this.size; } 85 | 86 | public Long getUploadTimestamp() { return this.uploadTimestamp; } 87 | 88 | @Override 89 | protected Logger getLogger() { return LOGGER; } 90 | 91 | @Override 92 | public String toString() { 93 | final StringBuilder sb = new StringBuilder("B2HideFileResponse{"); 94 | sb.append("fileId='").append(fileId).append('\''); 95 | sb.append(", fileName='").append(fileName).append('\''); 96 | sb.append(", action=").append(action); 97 | sb.append(", size=").append(size); 98 | sb.append('}'); 99 | return sb.toString(); 100 | } 101 | 102 | /** 103 | * Get the content length of the downloaded file 104 | * 105 | * @return the length of the content 106 | */ 107 | public Long getContentLength() { return this.contentLength; } 108 | 109 | /** 110 | * Get the content type of the downloaded file 111 | * 112 | * @return the content type of the downloaded file 113 | */ 114 | public String getContentType() { return this.contentType; } 115 | 116 | /** 117 | * Get the SHA1 of the returned content 118 | * 119 | * @return the SHA1 of the returned content 120 | */ 121 | public String getContentSha1() { return this.contentSha1; } 122 | 123 | /** 124 | * Get the file info for the file, this will be returned in the map as 125 | * key(tag), value (super-secret-tag) 126 | * 127 | * @return The map of the file info 128 | */ 129 | public Map getFileInfo() { return this.fileInfo; } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2FinishLargeFileResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.util.Map; 20 | 21 | /* 22 | * Copyright (c) 2016 iterate GmbH. 23 | * 24 | * All rights reserved. 25 | * 26 | * This code may contain contributions from other parties which, where 27 | * applicable, will be listed in the default build file for the project 28 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 29 | * 30 | * This source code and any derived binaries are covered by the terms and 31 | * conditions of the Licence agreement ("the Licence"). You may not use this 32 | * source code or any derived binaries except in compliance with the Licence. 33 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 34 | * this source code or binaries. 35 | */ 36 | 37 | import org.slf4j.Logger; 38 | import org.slf4j.LoggerFactory; 39 | 40 | import synapticloop.b2.Action; 41 | import synapticloop.b2.exception.B2ApiException; 42 | 43 | public class B2FinishLargeFileResponse extends BaseB2Response { 44 | private static final Logger LOGGER = LoggerFactory.getLogger(B2FinishLargeFileResponse.class); 45 | 46 | private final String fileId; 47 | private final String fileName; 48 | private final String accountId; 49 | private final String bucketId; 50 | private final Long contentLength; 51 | private final String contentSha1; 52 | private final String contentType; 53 | 54 | private final Map fileInfo; 55 | private Action action; 56 | 57 | public B2FinishLargeFileResponse(final String json) throws B2ApiException { 58 | super(json); 59 | 60 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 61 | this.fileName = this.readString(B2ResponseProperties.KEY_FILE_NAME); 62 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 63 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 64 | this.contentLength = this.readLong(B2ResponseProperties.KEY_CONTENT_LENGTH); 65 | this.contentType = this.readString(B2ResponseProperties.KEY_CONTENT_TYPE); 66 | this.contentSha1 = this.readString(B2ResponseProperties.KEY_CONTENT_SHA1); 67 | this.fileInfo = this.readMap(B2ResponseProperties.KEY_FILE_INFO); 68 | String action = this.readString(B2ResponseProperties.KEY_ACTION); 69 | if(null != action) { 70 | try { 71 | this.action = Action.valueOf(action); 72 | } 73 | catch(IllegalArgumentException e) { 74 | LOGGER.warn("Unknown action value " + action); 75 | } 76 | } 77 | 78 | this.warnOnMissedKeys(); 79 | } 80 | 81 | public String getFileId() { 82 | return fileId; 83 | } 84 | 85 | public String getFileName() { 86 | return fileName; 87 | } 88 | 89 | public String getAccountId() { 90 | return accountId; 91 | } 92 | 93 | public String getBucketId() { 94 | return bucketId; 95 | } 96 | 97 | public Long getContentLength() { 98 | return contentLength; 99 | } 100 | 101 | /** 102 | * Large files do not have a SHA1 checksum. The value will always be "none". 103 | * @return "none" 104 | */ 105 | public String getContentSha1() { 106 | return contentSha1; 107 | } 108 | 109 | public String getContentType() { 110 | return contentType; 111 | } 112 | 113 | public Map getFileInfo() { 114 | return fileInfo; 115 | } 116 | 117 | public Action getAction() { 118 | return action; 119 | } 120 | 121 | @Override 122 | protected Logger getLogger() { return LOGGER; } 123 | 124 | @Override 125 | public String toString() { 126 | final StringBuilder sb = new StringBuilder("B2FinishLargeFileResponse{"); 127 | sb.append("fileId='").append(fileId).append('\''); 128 | sb.append(", fileName='").append(fileName).append('\''); 129 | sb.append(", contentLength=").append(contentLength); 130 | sb.append(", contentSha1='").append(contentSha1).append('\''); 131 | sb.append(", contentType='").append(contentType).append('\''); 132 | sb.append(", fileInfo=").append(fileInfo); 133 | sb.append(", action=").append(action); 134 | sb.append('}'); 135 | return sb.toString(); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2DownloadFileByNameRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.HttpHeaders; 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2DownloadFileResponse; 27 | import synapticloop.b2.util.URLEncoder; 28 | 29 | /** 30 | *

Downloads one file by providing the name of the bucket and the name of the file.

31 | * 32 | *

The base URL to use comes from the b2_authorize_account call, and looks something like https://f345.backblaze.com. The "f" in the URL stands for "file", and the number is the cluster number that your account is in. To this base, you add your bucket name, a "/", and then the name of the file. The file name may itself include more "/" characters.

33 | *

If you have a bucket named "photos", and a file called "cute/kitten.jpg", then the URL for downloading that file would be: https://f345.backblaze.com/file/photos/cute/kitten.jpg.

34 | * 35 | * 36 | * This is the interaction class for the b2_download_file_by_name api calls, this was 37 | * generated from the backblaze api documentation - which can be found here: 38 | * http://www.backblaze.com/b2/docs/b2_download_file_by_name.html 39 | * 40 | * @author synapticloop 41 | */ 42 | public class B2DownloadFileByNameRequest extends BaseB2Request { 43 | 44 | /** 45 | * Create a download file by name request 46 | * 47 | * @param client The http client to use 48 | * @param b2AuthorizeAccountResponse the authorize account response 49 | * @param bucketName the name of the bucket 50 | * @param fileName the name and path of the file 51 | */ 52 | public B2DownloadFileByNameRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketName, String fileName) { 53 | this(client, b2AuthorizeAccountResponse, bucketName, fileName, -1, -1); 54 | } 55 | 56 | /** 57 | * Create a download file by name request with a specified range 58 | * 59 | * A standard byte-range request, which will return just part of the stored file. 60 | * 61 | * The value "bytes=0-99" selects bytes 0 through 99 (inclusive) of the file, 62 | * so it will return the first 100 bytes. Valid byte ranges will cause the 63 | * response to contain a Content-Range header that specifies which bytes 64 | * are returned. Invalid byte ranges will just return the whole file. 65 | * 66 | * Note that the SHA1 checksum returned is still the checksum for the entire 67 | * file, so it cannot be used on the byte range. 68 | * 69 | * @param client The http client to use 70 | * @param b2AuthorizeAccountResponse the authorize account response 71 | * @param bucketName the name of the bucket 72 | * @param fileName the name and path of the file 73 | * @param rangeStart the range start of the partial file contents. -1 to read from start of file 74 | * @param rangeEnd the range end of the partial file contents. -1 to read from start of file 75 | */ 76 | public B2DownloadFileByNameRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String bucketName, String fileName, long rangeStart, long rangeEnd) { 77 | super(client, 78 | b2AuthorizeAccountResponse, 79 | b2AuthorizeAccountResponse.getDownloadUrl() + "/file/" + URLEncoder.encode(bucketName) + "/" + URLEncoder.encode(fileName)); 80 | if (rangeStart > -1) { 81 | if (rangeEnd > -1) { 82 | this.addHeader(HttpHeaders.RANGE, String.format("bytes=%d-%d", rangeStart, rangeEnd)); 83 | } else { 84 | this.addHeader(HttpHeaders.RANGE, String.format("bytes=%d-", rangeStart)); 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * Execute the request and return the response 91 | * 92 | * @return The download file response 93 | * 94 | * @throws B2ApiException If there was an error with the call 95 | * @throws IOException if there was an error communicating with the API service 96 | */ 97 | public B2DownloadFileResponse getResponse() throws B2ApiException, IOException { 98 | return new B2DownloadFileResponse(executeGet()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2DownloadFileRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.io.FileWriter; 7 | import java.nio.charset.Charset; 8 | 9 | import org.apache.commons.io.IOUtils; 10 | import org.apache.http.impl.client.HttpClients; 11 | import org.junit.Test; 12 | 13 | import synapticloop.b2.helper.B2TestHelper; 14 | import synapticloop.b2.response.B2BucketResponse; 15 | import synapticloop.b2.response.B2DeleteFileVersionResponse; 16 | import synapticloop.b2.response.B2DownloadFileResponse; 17 | import synapticloop.b2.response.B2FileResponse; 18 | import synapticloop.b2.response.B2GetUploadUrlResponse; 19 | import synapticloop.b2.util.ChecksumHelper; 20 | 21 | public class B2DownloadFileRequestTest { 22 | private B2BucketResponse randomPrivateBucket = null; 23 | private B2FileResponse b2FileResponse = null; 24 | 25 | @Test 26 | public void testDownloadByFilePath() throws Exception { 27 | randomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 28 | B2GetUploadUrlResponse b2GetUploadUrlResponse = B2TestHelper.getUploadUrl(randomPrivateBucket.getBucketId()); 29 | File file = File.createTempFile("backblaze-api-test", ".txt"); 30 | FileWriter fileWriter = new FileWriter(file); 31 | fileWriter.write("hello world!"); 32 | fileWriter.flush(); 33 | fileWriter.close(); 34 | 35 | String testFileName = "some/file/path/" + file.getName(); 36 | B2FileResponse b2UploadFileResponse = new B2UploadFileRequest(HttpClients.createDefault(), 37 | B2TestHelper.getB2AuthorizeAccountResponse(), 38 | b2GetUploadUrlResponse, 39 | testFileName, file, ChecksumHelper.calculateSha1(file)).getResponse(); 40 | 41 | String fileName = b2UploadFileResponse.getFileName(); 42 | String fileId = b2UploadFileResponse.getFileId(); 43 | 44 | B2DownloadFileResponse b2DownloadFileResponse = new B2DownloadFileByNameRequest(HttpClients.createDefault(), 45 | B2TestHelper.getB2AuthorizeAccountResponse(), 46 | randomPrivateBucket.getBucketName(), 47 | testFileName).getResponse(); 48 | assertEquals(fileName, b2DownloadFileResponse.getFileName()); 49 | // now we need to delete the file as well to clean up after ourselves 50 | 51 | B2DeleteFileVersionResponse b2DeleteFileVersionResponse = new B2DeleteFileVersionRequest(HttpClients.createDefault(), 52 | B2TestHelper.getB2AuthorizeAccountResponse(), 53 | testFileName, 54 | fileId).getResponse(); 55 | 56 | assertEquals(fileName, b2DeleteFileVersionResponse.getFileName()); 57 | assertEquals(fileId, b2DeleteFileVersionResponse.getFileId()); 58 | 59 | B2TestHelper.deleteBucket(randomPrivateBucket.getBucketId()); 60 | } 61 | 62 | @Test 63 | public void testDownloadFileBy() throws Exception { 64 | randomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 65 | b2FileResponse = B2TestHelper.uploadTemporaryFileToBucket(randomPrivateBucket.getBucketId()); 66 | 67 | B2DownloadFileResponse b2DownloadFileResponse = new B2DownloadFileByNameRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), randomPrivateBucket.getBucketName(), b2FileResponse.getFileName()).getResponse(); 68 | assertEquals(B2TestHelper.DUMMY_FILE_CONTENT, IOUtils.toString(b2DownloadFileResponse.getContent(), Charset.defaultCharset())); 69 | 70 | b2DownloadFileResponse = new B2DownloadFileByIdRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), b2FileResponse.getFileId()).getResponse(); 71 | assertEquals(B2TestHelper.DUMMY_FILE_CONTENT, IOUtils.toString(b2DownloadFileResponse.getContent(), Charset.defaultCharset())); 72 | 73 | B2TestHelper.deleteFile(b2FileResponse.getFileName(), b2FileResponse.getFileId()); 74 | B2TestHelper.deleteBucket(randomPrivateBucket.getBucketId()); 75 | } 76 | 77 | @Test 78 | public void testDownloadFileByRange() throws Exception { 79 | randomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 80 | b2FileResponse = B2TestHelper.uploadTemporaryFileToBucket(randomPrivateBucket.getBucketId()); 81 | 82 | B2DownloadFileResponse b2DownloadFileResponse = new B2DownloadFileByNameRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), 83 | randomPrivateBucket.getBucketName(), 84 | b2FileResponse.getFileName(), 85 | 0, 86 | 5).getResponse(); 87 | 88 | assertEquals(B2TestHelper.DUMMY_FILE_CONTENT.substring(0, 6), IOUtils.toString(b2DownloadFileResponse.getContent(), Charset.defaultCharset())); 89 | 90 | b2DownloadFileResponse = new B2DownloadFileByIdRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), 91 | b2FileResponse.getFileId(), 92 | 0, 93 | 5).getResponse(); 94 | 95 | assertEquals(B2TestHelper.DUMMY_FILE_CONTENT.substring(0, 6), IOUtils.toString(b2DownloadFileResponse.getContent(), Charset.defaultCharset())); 96 | 97 | B2TestHelper.deleteFile(b2FileResponse.getFileName(), b2FileResponse.getFileId()); 98 | B2TestHelper.deleteBucket(randomPrivateBucket.getBucketId()); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/response/B2ListFilesResponseTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class B2ListFilesResponseTest { 8 | 9 | @Test 10 | public void testGetFiles() throws Exception { 11 | final String json = "{\n" + 12 | " \"files\": [\n" + 13 | " {\n" + 14 | " \"action\": \"upload\",\n" + 15 | " \"contentSha1\": \"e73f8339c3e731e3fd9b0bec46222bd0016f1afa\",\n" + 16 | " \"contentType\": \"image/jpeg\",\n" + 17 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f112de56cdcbb09e8_d20160120_m172133_c000_v0001010_t0006\",\n" + 18 | " \"fileInfo\": {\n" + 19 | " \"src_last_modified_millis\": \"0\"\n" + 20 | " },\n" + 21 | " \"fileName\": \"IMG_5066.jpg\",\n" + 22 | " \"size\": 180903,\n" + 23 | " \"uploadTimestamp\": 1453310493000\n" + 24 | " },\n" + 25 | " {\n" + 26 | " \"action\": \"upload\",\n" + 27 | " \"contentSha1\": \"89d2b373a7b26dbec209fe2db5c0ca6557cb1a8d\",\n" + 28 | " \"contentType\": \"video/mp4\",\n" + 29 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f1092070825b2ec14_d20151219_m191222_c000_v0001014_t0038\",\n" + 30 | " \"fileInfo\": {},\n" + 31 | " \"fileName\": \"adele/BBC.Music.Presents.Adele.at.the.BBC.2015.HDTV.x264-NoGRP.mp4\",\n" + 32 | " \"size\": 536107168,\n" + 33 | " \"uploadTimestamp\": 1450552342000\n" + 34 | " },\n" + 35 | " {\n" + 36 | " \"action\": \"upload\",\n" + 37 | " \"contentSha1\": \"7201a995b6841a84fe23086b33d50e49a627fabe\",\n" + 38 | " \"contentType\": \"application/octet-stream\",\n" + 39 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f109c8fe9ff88885f_d20160106_m005102_c000_v0001014_t0041\",\n" + 40 | " \"fileInfo\": {},\n" + 41 | " \"fileName\": \"b2sync.tar.gz\",\n" + 42 | " \"size\": 1515462,\n" + 43 | " \"uploadTimestamp\": 1452041462000\n" + 44 | " },\n" + 45 | " {\n" + 46 | " \"action\": \"upload\",\n" + 47 | " \"contentSha1\": \"0a9d332d09376d28cf04726e146aeedc546b09cf\",\n" + 48 | " \"contentType\": \"image/png\",\n" + 49 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f10695c6a45107f47_d20151227_m200935_c000_v0001014_t0026\",\n" + 50 | " \"fileInfo\": {},\n" + 51 | " \"fileName\": \"logo/selligy-icon-square_360.png\",\n" + 52 | " \"size\": 7583,\n" + 53 | " \"uploadTimestamp\": 1451246975000\n" + 54 | " },\n" + 55 | " {\n" + 56 | " \"action\": \"upload\",\n" + 57 | " \"contentSha1\": \"f2cf229c6657ca2b17afb9af22090c92cf9a7d2f\",\n" + 58 | " \"contentType\": \"application/octet-stream\",\n" + 59 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f1189dc406f02d4d9_d20160104_m040533_c000_v0001014_t0004\",\n" + 60 | " \"fileInfo\": {},\n" + 61 | " \"fileName\": \"uploads-large.tar.gz\",\n" + 62 | " \"size\": 236324399,\n" + 63 | " \"uploadTimestamp\": 1451880333000\n" + 64 | " },\n" + 65 | " {\n" + 66 | " \"action\": \"upload\",\n" + 67 | " \"contentSha1\": \"7d9133df91610fd610d817b316db01c68b988dfd\",\n" + 68 | " \"contentType\": \"application/octet-stream\",\n" + 69 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f1189dc406f02d4d7_d20160104_m040413_c000_v0001014_t0004\",\n" + 70 | " \"fileInfo\": {},\n" + 71 | " \"fileName\": \"uploads-small.tar.gz\",\n" + 72 | " \"size\": 1216666,\n" + 73 | " \"uploadTimestamp\": 1451880253000\n" + 74 | " },\n" + 75 | " {\n" + 76 | " \"action\": \"upload\",\n" + 77 | " \"contentSha1\": \"07ecb3b3f48025118b314f5c7e169b0ca96bc3f1\",\n" + 78 | " \"contentType\": \"application/octet-stream\",\n" + 79 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f1189dc406f02d4d8_d20160104_m040432_c000_v0001014_t0004\",\n" + 80 | " \"fileInfo\": {},\n" + 81 | " \"fileName\": \"uploads-smallmedium.tar.gz\",\n" + 82 | " \"size\": 40941493,\n" + 83 | " \"uploadTimestamp\": 1451880272000\n" + 84 | " },\n" + 85 | " {\n" + 86 | " \"action\": \"upload\",\n" + 87 | " \"contentSha1\": \"b63f91f826e87887f4ce5c28ee6988cab8a0f3f4\",\n" + 88 | " \"contentType\": \"application/octet-stream\",\n" + 89 | " \"fileId\": \"4_z181632c04c2ddde855010b15_f1189dc406f02d4db_d20160104_m043616_c000_v0001014_t0004\",\n" + 90 | " \"fileInfo\": {},\n" + 91 | " \"fileName\": \"uploads-tiny.tar.gz\",\n" + 92 | " \"size\": 1130,\n" + 93 | " \"uploadTimestamp\": 1451882176000\n" + 94 | " }\n" + 95 | " ],\n" + 96 | " \"nextFileId\": null,\n" + 97 | " \"nextFileName\": null\n" + 98 | "}"; 99 | final B2ListFilesResponse response = new B2ListFilesResponse(json); 100 | assertNotNull(response); 101 | assertNotNull(response.getFiles()); 102 | assertFalse(response.getFiles().isEmpty()); 103 | assertEquals(8, response.getFiles().size()); 104 | assertNull(response.getNextFileId()); 105 | assertNull(response.getNextFileName()); 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/request/B2DownloadFileByIdRequest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.apache.http.HttpHeaders; 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | 24 | import synapticloop.b2.exception.B2ApiException; 25 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 26 | import synapticloop.b2.response.B2DownloadFileResponse; 27 | 28 | /** 29 | *

Downloads one file from B2.

30 | * 31 | *

The response contains the following headers, which contain the same information they did when the file was uploaded:

32 | * 33 | *
    34 | *
  • Content-Length
  • 35 | *
  • Content-Type
  • 36 | *
  • X-Bz-File-Id
  • 37 | *
  • X-Bz-File-Name
  • 38 | *
  • X-Bz-Content-Sha1
  • 39 | *
  • X-Bz-Info-*
  • 40 | *
41 | * 42 | *

HEAD requests are also supported, and work just like a GET, except that the 43 | * body of the response is not included. All of the same headers, including 44 | * Content-Length are returned. See the B2HeadFileByIdRequest

45 | * 46 | *

If the bucket containing the file is set to require authorization, then you 47 | * must supply the bucket's auth token in the Authorzation header.

48 | * 49 | *

Because errors can happen in network transmission, you should check the 50 | * SHA1 of the data you receive against the SHA1 returned in the 51 | * X-Bz-Content-Sha1 header.

52 | * 53 | * This is the interaction class for the b2_download_file_by_id api calls, this was 54 | * generated from the backblaze api documentation - which can be found here: 55 | * http://www.backblaze.com/b2/docs/b2_download_file_by_id.html 56 | * 57 | * @author synapticloop 58 | */ 59 | public class B2DownloadFileByIdRequest extends BaseB2Request { 60 | private static final String B2_DOWNLOAD_FILE_BY_ID = BASE_API_VERSION + "b2_download_file_by_id"; 61 | 62 | /** 63 | * Create a download file by ID request to download the complete file 64 | * 65 | * @param client Shared HTTP client instance 66 | * @param b2AuthorizeAccountResponse The authorize account response 67 | * @param fileId the unique id of the file 68 | */ 69 | public B2DownloadFileByIdRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, String fileId) { 70 | this(client, b2AuthorizeAccountResponse, fileId, -1, -1); 71 | } 72 | 73 | /** 74 | *

Create a download file by ID request to download the range of bytes 75 | * between rangeStart and rangeEnd (inclusive) 76 | *

77 | *

78 | * A standard byte-range request, which will return just part of the stored file. 79 | *

80 | *

81 | * The value "bytes=0-99" selects bytes 0 through 99 (inclusive) of the file, 82 | * so it will return the first 100 bytes. Valid byte ranges will cause the 83 | * response to contain a Content-Range header that specifies which bytes are 84 | * returned. Invalid byte ranges will just return the whole file. 85 | *

86 | *

87 | * Note that the SHA1 checksum returned is still the checksum for the entire 88 | * file, so it cannot be used on the byte range. 89 | *

90 | * 91 | * @param client Shared HTTP client instance 92 | * @param b2AuthorizeAccountResponse The authorize account response 93 | * @param fileId the unique id of the file 94 | * @param rangeStart the start of the range. -1 to read from start of file 95 | * @param rangeEnd the end of the range. -1 to read until EOF 96 | */ 97 | public B2DownloadFileByIdRequest(CloseableHttpClient client, B2AuthorizeAccountResponse b2AuthorizeAccountResponse, 98 | String fileId, long rangeStart, long rangeEnd) { 99 | 100 | super(client, b2AuthorizeAccountResponse, b2AuthorizeAccountResponse.getDownloadUrl() + B2_DOWNLOAD_FILE_BY_ID); 101 | this.addParameter(B2RequestProperties.KEY_FILE_ID, fileId); 102 | if (rangeStart > -1) { 103 | if (rangeEnd > -1) { 104 | this.addHeader(HttpHeaders.RANGE, String.format("bytes=%d-%d", rangeStart, rangeEnd)); 105 | } else { 106 | this.addHeader(HttpHeaders.RANGE, String.format("bytes=%d-", rangeStart)); 107 | } 108 | } 109 | } 110 | 111 | /** 112 | * Execute the request and return the response 113 | * 114 | * @return The download file response 115 | * 116 | * @throws B2ApiException If there was an error with the call 117 | * @throws IOException if there was an error communicating with the API service 118 | */ 119 | public B2DownloadFileResponse getResponse() throws B2ApiException, IOException { 120 | return new B2DownloadFileResponse(executeGet()); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2UploadAndDeleteFileRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.io.FileWriter; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import org.apache.http.impl.client.HttpClients; 11 | import org.junit.Test; 12 | 13 | import synapticloop.b2.exception.B2ApiException; 14 | import synapticloop.b2.helper.B2TestHelper; 15 | import synapticloop.b2.response.B2BucketResponse; 16 | import synapticloop.b2.response.B2DeleteFileVersionResponse; 17 | import synapticloop.b2.response.B2FileResponse; 18 | import synapticloop.b2.response.B2GetUploadUrlResponse; 19 | import synapticloop.b2.util.ChecksumHelper; 20 | 21 | 22 | public class B2UploadAndDeleteFileRequestTest { 23 | 24 | @Test 25 | public void testFileUpload() throws Exception { 26 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 27 | B2GetUploadUrlResponse b2GetUploadUrlResponse = B2TestHelper.getUploadUrl(privateBucket.getBucketId()); 28 | File file = File.createTempFile("backblaze-api-test", ".txt"); 29 | FileWriter fileWriter = new FileWriter(file); 30 | fileWriter.write("hello world!"); 31 | fileWriter.flush(); 32 | fileWriter.close(); 33 | B2FileResponse b2UploadFileResponse = new B2UploadFileRequest(HttpClients.createDefault(), 34 | B2TestHelper.getB2AuthorizeAccountResponse(), b2GetUploadUrlResponse, file.getName(), file, 35 | ChecksumHelper.calculateSha1(file)).getResponse(); 36 | 37 | String fileName = b2UploadFileResponse.getFileName(); 38 | String fileId = b2UploadFileResponse.getFileId(); 39 | 40 | // now we need to delete the file as well to clean up after ourselves 41 | 42 | B2DeleteFileVersionResponse b2DeleteFileVersionResponse = new B2DeleteFileVersionRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), fileName, fileId).getResponse(); 43 | assertEquals(fileName, b2DeleteFileVersionResponse.getFileName()); 44 | assertEquals(fileId, b2DeleteFileVersionResponse.getFileId()); 45 | 46 | B2TestHelper.deleteBucket(privateBucket.getBucketId()); 47 | } 48 | 49 | @Test 50 | public void testFileUploadFailureTestMode() throws Exception { 51 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 52 | B2GetUploadUrlResponse b2GetUploadUrlResponse = B2TestHelper.getUploadUrl(privateBucket.getBucketId()); 53 | File file = File.createTempFile("backblaze-api-test", ".txt"); 54 | FileWriter fileWriter = new FileWriter(file); 55 | fileWriter.write("hello world!"); 56 | fileWriter.flush(); 57 | fileWriter.close(); 58 | while (true) { 59 | try { 60 | final B2UploadFileRequest request = new B2UploadFileRequest(HttpClients.createDefault(), 61 | B2TestHelper.getB2AuthorizeAccountResponse(), b2GetUploadUrlResponse, file.getName(), file, 62 | ChecksumHelper.calculateSha1(file)); 63 | request.addHeader("X-Bz-Test-Mode", "fail_some_uploads"); 64 | B2FileResponse b2UploadFileResponse = request.getResponse(); 65 | 66 | String fileName = b2UploadFileResponse.getFileName(); 67 | String fileId = b2UploadFileResponse.getFileId(); 68 | 69 | // now we need to delete the file as well to clean up after ourselves 70 | 71 | B2DeleteFileVersionResponse b2DeleteFileVersionResponse = new B2DeleteFileVersionRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), fileName, fileId).getResponse(); 72 | assertEquals(fileName, b2DeleteFileVersionResponse.getFileName()); 73 | assertEquals(fileId, b2DeleteFileVersionResponse.getFileId()); 74 | } catch (B2ApiException e) { 75 | assertEquals(503, e.getStatus()); 76 | break; 77 | } 78 | } 79 | 80 | B2TestHelper.deleteBucket(privateBucket.getBucketId()); 81 | } 82 | @Test 83 | public void testFileUploadWithInfo() throws Exception { 84 | B2BucketResponse privateBucket = B2TestHelper.createRandomPrivateBucket(); 85 | B2GetUploadUrlResponse b2GetUploadUrlResponse = B2TestHelper.getUploadUrl(privateBucket.getBucketId()); 86 | Map fileInfo = new HashMap(); 87 | fileInfo.put("hello", "world"); 88 | 89 | File file = File.createTempFile("backblaze-api-test", ".txt"); 90 | FileWriter fileWriter = new FileWriter(file); 91 | fileWriter.write("hello world!"); 92 | fileWriter.flush(); 93 | fileWriter.close(); 94 | 95 | B2FileResponse b2UploadFileResponse = new B2UploadFileRequest(HttpClients.createDefault(), 96 | B2TestHelper.getB2AuthorizeAccountResponse(), b2GetUploadUrlResponse, file.getName(), file, 97 | ChecksumHelper.calculateSha1(file), fileInfo).getResponse(); 98 | 99 | String fileName = b2UploadFileResponse.getFileName(); 100 | String fileId = b2UploadFileResponse.getFileId(); 101 | 102 | // try and get the info for the file 103 | B2FileResponse b2FileInfoResponse = new B2GetFileInfoRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), b2UploadFileResponse.getFileId()).getResponse(); 104 | assertEquals("world", b2FileInfoResponse.getFileInfo().get("hello")); 105 | 106 | // now we need to delete the file as well to clean up after ourselves 107 | 108 | B2DeleteFileVersionResponse b2DeleteFileVersionResponse = new B2DeleteFileVersionRequest(HttpClients.createDefault(), B2TestHelper.getB2AuthorizeAccountResponse(), fileName, fileId).getResponse(); 109 | assertEquals(fileName, b2DeleteFileVersionResponse.getFileName()); 110 | assertEquals(fileId, b2DeleteFileVersionResponse.getFileId()); 111 | 112 | B2TestHelper.deleteBucket(privateBucket.getBucketId()); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2AuthorizeAccountResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import synapticloop.b2.exception.B2ApiException; 23 | 24 | public class B2AuthorizeAccountResponse extends BaseB2Response { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(B2AuthorizeAccountResponse.class); 26 | 27 | private final String accountId; 28 | private final String apiUrl; 29 | private final String authorizationToken; 30 | private final String downloadUrl; 31 | private final int minimumPartSize; 32 | private final int recommendedPartSize; 33 | @Deprecated private final int absoluteMinimumPartSize; 34 | 35 | /** 36 | * Instantiate an authorize account response with the JSON response as a 37 | * string from the API call. This response is then parsed into the 38 | * relevant fields. 39 | * 40 | * @param json the response (in JSON format) 41 | * 42 | * @throws B2ApiException if there was an error parsing the response 43 | */ 44 | public B2AuthorizeAccountResponse(String json) throws B2ApiException { 45 | super(json); 46 | 47 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 48 | this.apiUrl = this.readString(B2ResponseProperties.KEY_API_URL); 49 | this.authorizationToken = this.readString(B2ResponseProperties.KEY_AUTHORIZATION_TOKEN); 50 | this.downloadUrl = this.readString(B2ResponseProperties.KEY_DOWNLOAD_URL); 51 | this.minimumPartSize = this.readInt(B2ResponseProperties.KEY_MINIMUM_PART_SIZE); 52 | this.recommendedPartSize = this.readInt(B2ResponseProperties.KEY_RECOMMENDED_PART_SIZE); 53 | this.absoluteMinimumPartSize = this.readInt(B2ResponseProperties.KEY_ABSOLUTE_MINIMUM_PART_SIZE); 54 | 55 | this.warnOnMissedKeys(); 56 | } 57 | 58 | /** 59 | * Return the account ID used to authorize this account 60 | * 61 | * @return the account ID 62 | */ 63 | public String getAccountId() { return this.accountId; } 64 | 65 | /** 66 | * The API URL to be used for all subsequent calls to the API 67 | * 68 | * @return the api url to use for all subsequent calls 69 | */ 70 | public String getApiUrl() { return this.apiUrl; } 71 | 72 | /** 73 | * Get authorization token to use with all calls, other than b2_authorize_account, 74 | * that need an Authorization header. This authorization token is valid for at 75 | * most 24 hours. 76 | * 77 | * @return the authorization token to be used for all subsequent calls 78 | */ 79 | public String getAuthorizationToken() { return this.authorizationToken; } 80 | 81 | /** 82 | * Return the url to be used for downloading files 83 | * 84 | * @return the URL to be used for downloading files 85 | */ 86 | public String getDownloadUrl() { return this.downloadUrl; } 87 | 88 | /** 89 | * The minimum size for each part of a large file (except the last one). This 90 | * will always be 100,000,000, but we recommend that you write your code to 91 | * get the number here, rather than use a hard-coded constant. 92 | * 93 | * @return the minimum part size for downloads 94 | */ 95 | public int getMinimumPartSize() {return this.minimumPartSize; } 96 | 97 | /** 98 | * The recommended size for each part of a large file. We recommend using 99 | * this part size for optimal upload performance. 100 | * 101 | * @return the recommended part size for optimal upload performance 102 | */ 103 | public int getRecommendedPartSize() { return recommendedPartSize; } 104 | 105 | /** 106 | * The smallest possible size of a part of a large file (except the last one). 107 | * This is smaller than the recommendedPartSize. If you use it, you may find 108 | * that it takes longer overall to upload a large file. 109 | * 110 | * This field will always have the same value as recommendedPartSize. 111 | * Use recommendedPartSize/code> instead. 112 | * 113 | * {@link B2AuthorizeAccountResponse#getRecommendedPartSize()} 114 | * 115 | * @return the absolute minimum part size for downloads 116 | */ 117 | @Deprecated 118 | public int getAbsoluteMinimumPartSize() { return absoluteMinimumPartSize; } 119 | 120 | @Override 121 | protected Logger getLogger() { return LOGGER; } 122 | 123 | @Override 124 | public String toString() { 125 | StringBuilder stringBuilder = new StringBuilder(); 126 | stringBuilder.append("B2AuthorizeAccountResponse [accountId="); 127 | stringBuilder.append(this.accountId); 128 | stringBuilder.append(", apiUrl="); 129 | stringBuilder.append(this.apiUrl); 130 | stringBuilder.append(", authorizationToken="); 131 | stringBuilder.append(this.authorizationToken); 132 | stringBuilder.append(", downloadUrl="); 133 | stringBuilder.append(this.downloadUrl); 134 | stringBuilder.append(", minimumPartSize="); 135 | stringBuilder.append(this.minimumPartSize); 136 | stringBuilder.append("]"); 137 | return stringBuilder.toString(); 138 | } 139 | 140 | 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2BucketResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.json.JSONArray; 8 | 9 | /* 10 | * Copyright (c) 2016 - 2017 Synapticloop. 11 | * 12 | * All rights reserved. 13 | * 14 | * This code may contain contributions from other parties which, where 15 | * applicable, will be listed in the default build file for the project 16 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 17 | * 18 | * This source code and any derived binaries are covered by the terms and 19 | * conditions of the Licence agreement ("the Licence"). You may not use this 20 | * source code or any derived binaries except in compliance with the Licence. 21 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 22 | * this source code or binaries. 23 | */ 24 | 25 | import org.json.JSONObject; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import synapticloop.b2.BucketType; 30 | import synapticloop.b2.LifecycleRule; 31 | import synapticloop.b2.exception.B2ApiException; 32 | 33 | public class B2BucketResponse extends BaseB2Response { 34 | private static final Logger LOGGER = LoggerFactory.getLogger(B2BucketResponse.class); 35 | 36 | private final String bucketId; 37 | private final String accountId; 38 | private final String bucketName; 39 | private final String bucketType; 40 | private final Long revision; 41 | private final Map bucketInfo; 42 | private final List lifecycleRules = new ArrayList(); 43 | 44 | /** 45 | * Instantiate a bucket response with the JSON response as a string from 46 | * the API call. This response is then parsed into the relevant fields. 47 | * 48 | * @param json The response (in JSON format) 49 | * 50 | * @throws B2ApiException if there was an error parsing the response 51 | */ 52 | public B2BucketResponse(String json) throws B2ApiException { 53 | super(json); 54 | 55 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 56 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 57 | this.bucketName = this.readString(B2ResponseProperties.KEY_BUCKET_NAME); 58 | this.bucketType = this.readString(B2ResponseProperties.KEY_BUCKET_TYPE); 59 | this.revision = this.readLong(B2ResponseProperties.KEY_REVISION); 60 | this.bucketInfo = this.readMap(B2ResponseProperties.KEY_BUCKET_INFO); 61 | 62 | JSONArray lifecycleObjects = this.readObjects(B2ResponseProperties.KEY_LIFECYCLE_RULES); 63 | for (Object object : lifecycleObjects) { 64 | lifecycleRules.add(new LifecycleRule((JSONObject)object)); 65 | } 66 | 67 | this.warnOnMissedKeys(); 68 | } 69 | 70 | /** 71 | * Instantiate a bucket response with the JSON response as a string from 72 | * the API call. This response is then parsed into the relevant fields. 73 | * 74 | * @param response The pre-parsed jsonObject 75 | * 76 | * @throws B2ApiException if there was an error parsing the response 77 | */ 78 | public B2BucketResponse(final JSONObject response) throws B2ApiException { 79 | super(response); 80 | 81 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 82 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 83 | this.bucketName = this.readString(B2ResponseProperties.KEY_BUCKET_NAME); 84 | this.bucketType = this.readString(B2ResponseProperties.KEY_BUCKET_TYPE); 85 | this.revision = this.readLong(B2ResponseProperties.KEY_REVISION); 86 | this.bucketInfo = this.readMap(B2ResponseProperties.KEY_BUCKET_INFO); 87 | 88 | JSONArray lifecycleObjects = this.readObjects(B2ResponseProperties.KEY_LIFECYCLE_RULES); 89 | for (Object object : lifecycleObjects) { 90 | lifecycleRules.add(new LifecycleRule((JSONObject)object)); 91 | } 92 | 93 | this.warnOnMissedKeys(); 94 | } 95 | 96 | /** 97 | * Get the bucket id 98 | * 99 | * @return the id of the bucket 100 | */ 101 | public String getBucketId() { return this.bucketId; } 102 | 103 | /** 104 | * Get the account id 105 | * 106 | * @return the id of the account 107 | */ 108 | public String getAccountId() { return this.accountId; } 109 | 110 | /** 111 | * Get the name of the bucket 112 | * 113 | * @return the name of the bucket 114 | */ 115 | public String getBucketName() { return this.bucketName; } 116 | 117 | /** 118 | * Get the type of the bucket, one of 'allPrivate' or 'allPublic' 119 | * 120 | * @return The bucket type 121 | */ 122 | public BucketType getBucketType() { 123 | try { 124 | return BucketType.valueOf(this.bucketType); 125 | } 126 | catch(IllegalArgumentException e) { 127 | return null; 128 | } 129 | } 130 | 131 | /** 132 | * Get the map of the bucket info for the bucket that was operated on, or an 133 | * empty map if not set. 134 | * 135 | * @return the map of the file info for the file that was operated on 136 | */ 137 | public Map getBucketInfo() { return this.bucketInfo; } 138 | 139 | /** 140 | * Get the revision number for the bucket 141 | * 142 | * @return the revision number for the bucket 143 | */ 144 | public long getRevision() { return this.revision; } 145 | 146 | /** 147 | * Return the list of all of the lifecycle rules that apply to this bucket 148 | * 149 | * @return the list of all lifecycle rules 150 | */ 151 | public List getLifecycleRules() { return lifecycleRules; } 152 | 153 | @Override 154 | protected Logger getLogger() { return LOGGER; } 155 | 156 | @Override 157 | public String toString() { 158 | final StringBuilder sb = new StringBuilder("B2BucketResponse{"); 159 | sb.append("bucketId='").append(bucketId).append('\''); 160 | sb.append(", accountId='").append(accountId).append('\''); 161 | sb.append(", bucketName='").append(bucketName).append('\''); 162 | sb.append(", bucketType='").append(bucketType).append('\''); 163 | sb.append('}'); 164 | return sb.toString(); 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2FileInfoResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.util.Map; 20 | 21 | import org.json.JSONObject; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import synapticloop.b2.Action; 26 | import synapticloop.b2.exception.B2ApiException; 27 | 28 | public class B2FileInfoResponse extends BaseB2Response { 29 | private static final Logger LOGGER = LoggerFactory.getLogger(B2FileInfoResponse.class); 30 | 31 | private final String fileId; 32 | private final String fileName; 33 | private final String contentType; 34 | private final String contentSha1; 35 | private final Long contentLength; 36 | private final String accountId; 37 | private final String bucketId; 38 | 39 | private final Map fileInfo; 40 | private Action action; 41 | private final Long size; 42 | private final Long uploadTimestamp; 43 | 44 | /** 45 | * Instantiate a file info response with the JSON response as a string from 46 | * the API call. This response is then parsed into the relevant fields. 47 | * 48 | * @param response The pre-parsed response as a JSON object 49 | * 50 | * @throws B2ApiException if there was an error parsing the response 51 | */ 52 | public B2FileInfoResponse(final JSONObject response) throws B2ApiException { 53 | super(response); 54 | 55 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 56 | this.fileName = this.readString(B2ResponseProperties.KEY_FILE_NAME); 57 | this.contentLength = this.readLong(B2ResponseProperties.KEY_CONTENT_LENGTH); 58 | this.contentType = this.readString(B2ResponseProperties.KEY_CONTENT_TYPE); 59 | this.contentSha1 = this.readString(B2ResponseProperties.KEY_CONTENT_SHA1); 60 | this.fileInfo = this.readMap(B2ResponseProperties.KEY_FILE_INFO); 61 | String action = this.readString(B2ResponseProperties.KEY_ACTION); 62 | if(null != action) { 63 | try { 64 | this.action = Action.valueOf(action); 65 | } 66 | catch(IllegalArgumentException e) { 67 | LOGGER.warn("Unknown action value " + action); 68 | } 69 | } 70 | 71 | this.size = this.readLong(B2ResponseProperties.KEY_SIZE); 72 | this.uploadTimestamp = this.readLong(B2ResponseProperties.KEY_UPLOAD_TIMESTAMP); 73 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 74 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 75 | 76 | this.warnOnMissedKeys(); 77 | } 78 | 79 | /** 80 | * Get the fileId that uniquely identifies this file 81 | * 82 | * @return the fileId 83 | */ 84 | public String getFileId() { return this.fileId; } 85 | 86 | /** 87 | * Get the name of the file as stored in the backblaze bucket 88 | * 89 | * @return the name of the file as stored in the backblaze bucket 90 | */ 91 | public String getFileName() { return this.fileName; } 92 | 93 | /** 94 | * Get the content length for this file 95 | * 96 | * @return the length of content for this file 97 | */ 98 | public Long getContentLength() { return this.contentLength; } 99 | 100 | /** 101 | * @return the MIME type of the file 102 | */ 103 | public String getContentType() { return contentType; } 104 | 105 | /** 106 | * Get the sha1 hash of the content - this can be used to verify the 107 | * integrity of the downloaded file 108 | * 109 | * @return the sha1 has of the content 110 | */ 111 | public String getContentSha1() { return this.contentSha1; } 112 | 113 | /** 114 | * Get the file info for the downloaded file - which is a map of key value 115 | * pairs with both the key and value being strings 116 | * 117 | * @return the file info map of key:value strings 118 | */ 119 | 120 | public Map getFileInfo() { return this.fileInfo; } 121 | 122 | /** 123 | * The action that was performed, this will be one of of 'hide', or 'upload' 124 | * 125 | * @return The action that was performed 126 | */ 127 | public Action getAction() { return this.action; } 128 | 129 | /** 130 | * @return The number of bytes in the file. 131 | */ 132 | public long getSize() { return this.size; } 133 | 134 | /** 135 | * Return the timestamp that the file was uploaded 136 | * 137 | * @return the timestamp for when the file was uploaded 138 | */ 139 | public Long getUploadTimestamp() { return this.uploadTimestamp; } 140 | 141 | /** 142 | * Return the account ID used to authorize this account 143 | * 144 | * @return the account ID 145 | */ 146 | public String getAccountId() { return this.accountId; } 147 | 148 | /** 149 | * Return the bucket ID that this file belongs in 150 | * 151 | * @return the bucket ID 152 | */ 153 | public String getBucketId() { return this.bucketId; } 154 | 155 | @Override 156 | protected Logger getLogger() { return LOGGER; } 157 | 158 | @Override 159 | public String toString() { 160 | return "B2FileInfoResponse " + 161 | "[fileId=" + this.fileId + 162 | ", fileName=" + this.fileName + 163 | ", contentType=" + this.contentType + 164 | ", contentSha1=" + this.contentSha1 + 165 | ", contentLength=" + this.contentLength + 166 | ", accountId=" + this.accountId + 167 | ", bucketId=" + this.bucketId + 168 | ", fileInfo=" + this.fileInfo + 169 | ", action=" + this.action + 170 | ", size=" + this.size + 171 | ", uploadTimestamp=" + this.uploadTimestamp + 172 | "]"; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/synapticloop/b2/response/B2FileResponse.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.response; 2 | 3 | /* 4 | * Copyright (c) 2016 - 2017 Synapticloop. 5 | * 6 | * All rights reserved. 7 | * 8 | * This code may contain contributions from other parties which, where 9 | * applicable, will be listed in the default build file for the project 10 | * ~and/or~ in a file named CONTRIBUTORS.txt in the root of the project. 11 | * 12 | * This source code and any derived binaries are covered by the terms and 13 | * conditions of the Licence agreement ("the Licence"). You may not use this 14 | * source code or any derived binaries except in compliance with the Licence. 15 | * A copy of the Licence is available in the file named LICENSE.txt shipped with 16 | * this source code or binaries. 17 | */ 18 | 19 | import java.util.Map; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import synapticloop.b2.Action; 25 | import synapticloop.b2.exception.B2ApiException; 26 | 27 | public class B2FileResponse extends BaseB2Response { 28 | private static final Logger LOGGER = LoggerFactory.getLogger(B2FileResponse.class); 29 | 30 | private final String fileId; 31 | private final String fileName; 32 | private final String accountId; 33 | private final String bucketId; 34 | private final Long contentLength; 35 | private final String contentSha1; 36 | private final String contentType; 37 | private final Map fileInfo; 38 | private Action action; 39 | private final Long uploadTimestamp; 40 | 41 | /** 42 | * Instantiate a file response with the JSON response as a string from 43 | * the API call. This response is then parsed into the relevant fields. 44 | * 45 | * @param json The response (in JSON format) 46 | * 47 | * @throws B2ApiException if there was an error parsing the response 48 | */ 49 | public B2FileResponse(String json) throws B2ApiException { 50 | super(json); 51 | 52 | this.fileId = this.readString(B2ResponseProperties.KEY_FILE_ID); 53 | this.fileName = this.readString(B2ResponseProperties.KEY_FILE_NAME); 54 | this.accountId = this.readString(B2ResponseProperties.KEY_ACCOUNT_ID); 55 | this.bucketId = this.readString(B2ResponseProperties.KEY_BUCKET_ID); 56 | this.contentLength = this.readLong(B2ResponseProperties.KEY_CONTENT_LENGTH); 57 | this.contentSha1 = this.readString(B2ResponseProperties.KEY_CONTENT_SHA1); 58 | this.contentType = this.readString(B2ResponseProperties.KEY_CONTENT_TYPE); 59 | this.fileInfo = this.readMap(B2ResponseProperties.KEY_FILE_INFO); 60 | this.uploadTimestamp = this.readLong(B2ResponseProperties.KEY_UPLOAD_TIMESTAMP); 61 | 62 | String action = this.readString(B2ResponseProperties.KEY_ACTION); 63 | if(null != action) { 64 | try { 65 | this.action = Action.valueOf(action); 66 | } 67 | catch(IllegalArgumentException e) { 68 | LOGGER.warn("Unknown action value " + action); 69 | } 70 | } 71 | 72 | this.warnOnMissedKeys(); 73 | } 74 | 75 | /** 76 | * Get the id of the file that was operated on 77 | * 78 | * @return the id of the file that was operated on 79 | */ 80 | public String getFileId() { return this.fileId; } 81 | 82 | /** 83 | * Get the name of the file that was operated on 84 | * 85 | * @return the name of the file that was operated on 86 | */ 87 | public String getFileName() { return this.fileName; } 88 | 89 | /** 90 | * Get the id of the account that was operated on 91 | * 92 | * @return the id of the account that was operated on 93 | */ 94 | public String getAccountId() { return this.accountId; } 95 | 96 | /** 97 | * Get the id of the bucket that was operated on 98 | * 99 | * @return the id of the bucket that was operated on 100 | */ 101 | public String getBucketId() { return this.bucketId; } 102 | 103 | /** 104 | * Get content length of the file that was operated on, or null if not returned 105 | * in the response 106 | * 107 | * @return the content length of the file that was operated on 108 | */ 109 | public long getContentLength() { return this.contentLength; } 110 | 111 | /** 112 | * Get content SHA1 of the file that was operated on, or null if not returned 113 | * in the response 114 | * 115 | * @return the content SHA1 of the file that was operated on 116 | */ 117 | public String getContentSha1() { return this.contentSha1; } 118 | 119 | /** 120 | * Get content type of the file that was operated on, or null if not returned 121 | * in the response 122 | * 123 | * @return the content type of the file that was operated on 124 | */ 125 | public String getContentType() { return this.contentType; } 126 | 127 | /** 128 | * Get the map of the file info for the file that was operated on, or an empty 129 | * map if not set. 130 | * 131 | * @return the map of the file info for the file that was operated on 132 | */ 133 | public Map getFileInfo() { return this.fileInfo; } 134 | 135 | /** 136 | * Return the upload timestamp for this file 137 | * 138 | * @return the upload timestamp fot this file 139 | */ 140 | public Long getUploadTimestamp() { return this.uploadTimestamp; } 141 | 142 | @Override 143 | protected Logger getLogger() { return LOGGER; } 144 | 145 | @Override 146 | public String toString() { 147 | final StringBuilder sb = new StringBuilder("B2FileResponse{"); 148 | sb.append("fileId='").append(fileId).append('\''); 149 | sb.append(", fileName='").append(fileName).append('\''); 150 | sb.append(", accountId='").append(accountId).append('\''); 151 | sb.append(", bucketId='").append(bucketId).append('\''); 152 | sb.append(", contentLength=").append(contentLength); 153 | sb.append(", contentSha1='").append(contentSha1).append('\''); 154 | sb.append(", contentType='").append(contentType).append('\''); 155 | sb.append(", fileInfo=").append(fileInfo); 156 | sb.append('}'); 157 | return sb.toString(); 158 | } 159 | 160 | /** 161 | * Get the action that was performed on the 162 | * 163 | * @return the action that was performed 164 | */ 165 | public Action getAction() { 166 | return action; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/test/java/synapticloop/b2/request/B2ListFileVersionsRequestTest.java: -------------------------------------------------------------------------------- 1 | package synapticloop.b2.request; 2 | 3 | import org.apache.http.impl.client.CloseableHttpClient; 4 | import org.apache.http.impl.client.HttpClients; 5 | import org.junit.AfterClass; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import java.util.List; 10 | 11 | import synapticloop.b2.exception.B2ApiException; 12 | import synapticloop.b2.helper.B2TestHelper; 13 | import synapticloop.b2.response.B2AuthorizeAccountResponse; 14 | import synapticloop.b2.response.B2BucketResponse; 15 | import synapticloop.b2.response.B2FileInfoResponse; 16 | import synapticloop.b2.response.B2FileResponse; 17 | import synapticloop.b2.response.B2ListFilesResponse; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | public class B2ListFileVersionsRequestTest { 22 | private static B2AuthorizeAccountResponse b2AuthorizeAccountResponse = null; 23 | private static B2FileResponse tempFileOne = null; 24 | private static B2FileResponse tempFileTwo = null; 25 | private static B2FileResponse tempFileThree = null; 26 | private static B2FileResponse tempFileFour = null; 27 | private static String bucketId = null; 28 | 29 | @BeforeClass 30 | public static void setupBeforeClass() throws Exception { 31 | b2AuthorizeAccountResponse = B2TestHelper.getB2AuthorizeAccountResponse(); 32 | B2BucketResponse randomPrivateBucket = B2TestHelper.createRandomPrivateBucket(); 33 | bucketId = randomPrivateBucket.getBucketId(); 34 | tempFileOne = B2TestHelper.uploadTemporaryFileToBucket(bucketId); 35 | tempFileTwo = B2TestHelper.uploadTemporaryFileToBucket(bucketId); 36 | tempFileThree = B2TestHelper.uploadTemporaryFileToBucket(bucketId); 37 | tempFileFour = B2TestHelper.uploadTemporaryFileToBucket(bucketId); 38 | } 39 | 40 | @Test 41 | public void listFileVersions() throws Exception { 42 | B2ListFilesResponse b2ListFileVersionsResponse = new B2ListFileVersionsRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, bucketId, 1000).getResponse(); 43 | List files = b2ListFileVersionsResponse.getFiles(); 44 | assertEquals(4, files.size()); 45 | } 46 | 47 | @Test 48 | public void listFileVersionByName() throws Exception { 49 | B2ListFilesResponse b2ListFileVersionsResponse = new B2ListFileVersionsRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, bucketId, 1, tempFileOne.getFileName(), null, null, null).getResponse(); 50 | List files = b2ListFileVersionsResponse.getFiles(); 51 | assertEquals(1, files.size()); 52 | 53 | B2FileInfoResponse b2FileInfoResponse = files.get(0); 54 | assertEquals(b2FileInfoResponse.getFileName(), tempFileOne.getFileName()); 55 | } 56 | 57 | @Test 58 | public void listFileVersionByNameAndId() throws Exception { 59 | B2ListFilesResponse b2ListFileVersionsResponse = new B2ListFileVersionsRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, bucketId, 1, tempFileTwo.getFileName(), tempFileTwo.getFileId(), null, null).getResponse(); 60 | List files = b2ListFileVersionsResponse.getFiles(); 61 | assertEquals(1, files.size()); 62 | 63 | B2FileInfoResponse b2FileInfoResponse = files.get(0); 64 | assertEquals(b2FileInfoResponse.getFileId(), tempFileTwo.getFileId()); 65 | } 66 | 67 | @Test(expected = B2ApiException.class) 68 | public void listFileVersionIncorrect() throws Exception { 69 | B2ListFilesResponse b2ListFileVersionsResponse = new B2ListFileVersionsRequest(HttpClients.createDefault(), b2AuthorizeAccountResponse, bucketId, 1, null, tempFileTwo.getFileId(), null, null).getResponse(); 70 | List files = b2ListFileVersionsResponse.getFiles(); 71 | assertEquals(1, files.size()); 72 | 73 | B2FileInfoResponse b2FileInfoResponse = files.get(0); 74 | assertEquals(b2FileInfoResponse.getFileId(), tempFileTwo.getFileId()); 75 | 76 | } 77 | 78 | @Test 79 | public void listFiles() throws Exception { 80 | CloseableHttpClient client = HttpClients.createDefault(); 81 | B2ListFilesResponse b2ListFileVersionsResponse = new B2ListFileVersionsRequest(client, b2AuthorizeAccountResponse, bucketId, 1, tempFileOne.getFileName(), null, null, null).getResponse(); 82 | assertEquals(1, b2ListFileVersionsResponse.getFiles().size()); 83 | 84 | b2ListFileVersionsResponse = new B2ListFileVersionsRequest(client, b2AuthorizeAccountResponse, bucketId, 1, b2ListFileVersionsResponse.getNextFileName(), null, null, null).getResponse(); 85 | assertEquals(1, b2ListFileVersionsResponse.getFiles().size()); 86 | 87 | b2ListFileVersionsResponse = new B2ListFileVersionsRequest(client, b2AuthorizeAccountResponse, bucketId, 1, b2ListFileVersionsResponse.getNextFileName(), null, null, null).getResponse(); 88 | assertEquals(1, b2ListFileVersionsResponse.getFiles().size()); 89 | 90 | b2ListFileVersionsResponse = new B2ListFileVersionsRequest(client, b2AuthorizeAccountResponse, bucketId, 1, b2ListFileVersionsResponse.getNextFileName(), null, null, null).getResponse(); 91 | assertEquals(1, b2ListFileVersionsResponse.getFiles().size()); 92 | } 93 | 94 | @AfterClass 95 | public static void tearDownAfterClass() throws Exception { 96 | CloseableHttpClient client = HttpClients.createDefault(); 97 | new B2DeleteFileVersionRequest(client, b2AuthorizeAccountResponse, tempFileOne.getFileName(), tempFileOne.getFileId()).getResponse(); 98 | new B2DeleteFileVersionRequest(client, b2AuthorizeAccountResponse, tempFileTwo.getFileName(), tempFileTwo.getFileId()).getResponse(); 99 | new B2DeleteFileVersionRequest(client, b2AuthorizeAccountResponse, tempFileThree.getFileName(), tempFileThree.getFileId()).getResponse(); 100 | new B2DeleteFileVersionRequest(client, b2AuthorizeAccountResponse, tempFileFour.getFileName(), tempFileFour.getFileId()).getResponse(); 101 | B2TestHelper.deleteBucket(bucketId); 102 | } 103 | } 104 | --------------------------------------------------------------------------------