├── 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 |
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, MapGets 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 | ListDeletes 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 | *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 ListGets 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 | *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.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 | *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 | *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 | MaprecommendedPartSize.
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