com.backblaze.b2.sample.B2Sample Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of b2-sdk-samples Show documentation
Show all versions of b2-sdk-samples Show documentation
Samples for B2 SDK for Java.
The newest version!
/*
* Copyright 2017, Backblaze Inc. All Rights Reserved.
* License https://www.backblaze.com/using_b2_code.html
*/
package com.backblaze.b2.sample;
import com.backblaze.b2.client.B2Sdk;
import com.backblaze.b2.client.B2StorageClient;
import com.backblaze.b2.client.B2StorageClientFactory;
import com.backblaze.b2.client.contentHandlers.B2ContentFileWriter;
import com.backblaze.b2.client.contentHandlers.B2ContentMemoryWriter;
import com.backblaze.b2.client.contentSources.B2ByteArrayContentSource;
import com.backblaze.b2.client.contentSources.B2ContentSource;
import com.backblaze.b2.client.contentSources.B2ContentTypes;
import com.backblaze.b2.client.contentSources.B2FileContentSource;
import com.backblaze.b2.client.exceptions.B2Exception;
import com.backblaze.b2.client.structures.B2AccountAuthorization;
import com.backblaze.b2.client.structures.B2ApplicationKey;
import com.backblaze.b2.client.structures.B2Bucket;
import com.backblaze.b2.client.structures.B2BucketTypes;
import com.backblaze.b2.client.structures.B2Capabilities;
import com.backblaze.b2.client.structures.B2CreateKeyRequest;
import com.backblaze.b2.client.structures.B2CreatedApplicationKey;
import com.backblaze.b2.client.structures.B2DeleteKeyRequest;
import com.backblaze.b2.client.structures.B2DownloadAuthorization;
import com.backblaze.b2.client.structures.B2DownloadByNameRequest;
import com.backblaze.b2.client.structures.B2FileVersion;
import com.backblaze.b2.client.structures.B2GetDownloadAuthorizationRequest;
import com.backblaze.b2.client.structures.B2LifecycleRule;
import com.backblaze.b2.client.structures.B2ListFileVersionsRequest;
import com.backblaze.b2.client.structures.B2Part;
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadListener;
import com.backblaze.b2.util.B2ByteRange;
import com.backblaze.b2.util.B2ExecutorUtils;
import com.backblaze.b2.util.B2Preconditions;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.Deflater;
import static com.backblaze.b2.util.B2ExecutorUtils.createThreadFactory;
public class B2Sample {
private static final String USER_AGENT = "B2Sample";
public static void main(String[] args) throws B2Exception {
PrintWriter writer = new PrintWriter(System.out, true);
final ExecutorService executor = Executors.newFixedThreadPool(10, createThreadFactory("B2Sample-executor-%02d"));
try (final B2StorageClient client = B2StorageClientFactory.createDefaultFactory().create(USER_AGENT)) {
mainGuts(writer, client, executor);
} finally {
B2ExecutorUtils.shutdownAndAwaitTermination(executor, 10, 10);
}
}
private static void mainGuts(PrintWriter writer,
B2StorageClient client,
ExecutorService executor) throws B2Exception {
writer.println("Running with " + B2Sdk.getName() + " version " + B2Sdk.getVersion());
final String bucketName = "sample-" + client.getAccountId();
final B2UploadListener uploadListener = (progress) -> {
final double percent = (100. * (progress.getBytesSoFar() / (double) progress.getLength()));
writer.println(String.format(" progress(%3.2f, %s)", percent, progress.toString()));
};
bigHeader(writer, "create application key");
final String applicationKeyId;
{
final Set capabilities = new HashSet<>();
capabilities.add(B2Capabilities.LIST_BUCKETS);
capabilities.add(B2Capabilities.READ_FILES);
final B2CreatedApplicationKey applicationKey =
client.createKey(
B2CreateKeyRequest.builder(capabilities, "testKey").build()
);
applicationKeyId = applicationKey.getApplicationKeyId();
writer.println("key id: " + applicationKey.getApplicationKeyId() + " key: " + applicationKey.getApplicationKey());
}
bigHeader(writer, "list application keys");
for (B2ApplicationKey key : client.applicationKeys()) {
writer.println("key id: " + key.getApplicationKeyId() + " capabilities: " + key.getCapabilities());
}
bigHeader(writer, "delete application key");
{
client.deleteKey(B2DeleteKeyRequest.builder(applicationKeyId).build());
}
bigHeader(writer, "cleanup existing bucket, if any");
deleteBucketIfAny(writer, client, bucketName);
bigHeader(writer, "Create Bucket");
final B2Bucket bucket = client.createBucket(bucketName, B2BucketTypes.ALL_PRIVATE);
final String bucketId = bucket.getBucketId();
// list buckets.
bigHeader(writer, "List Buckets");
for (B2Bucket scan : client.buckets()) {
writer.println(" " + scan);
}
// create a file on disk that we can upload.
final File fileOnDisk = new File("/tmp/B2Sample-uploadMe.txt");
writeToFile(fileOnDisk, "hello world!\n".getBytes());
// upload a file from the disk.
bigHeader(writer, "Upload file from disk");
final B2FileVersion file1;
{
try {
final B2ContentSource source = B2FileContentSource.build(fileOnDisk);
final String fileName = "demo/file.txt";
B2UploadFileRequest request = B2UploadFileRequest
.builder(bucketId, fileName, B2ContentTypes.B2_AUTO, source)
.setCustomField("color", "blue")
.setListener(uploadListener)
.build();
file1 = client.uploadSmallFile(request);
writer.println("uploaded " + file1);
} finally {
//noinspection ResultOfMethodCallIgnored
fileOnDisk.delete();
}
}
// upload a file from memory.
bigHeader(writer, "Upload file from memory");
final B2FileVersion file2;
{
final B2ContentSource source = B2ByteArrayContentSource.build("this came from memory!".getBytes());
final String fileName = "demo/memory.txt";
B2UploadFileRequest request = B2UploadFileRequest
.builder(bucketId, fileName, B2ContentTypes.B2_AUTO, source)
.setCustomField("color", "red")
.build();
file2 = client.uploadSmallFile(request);
writer.println("uploaded " + file2);
}
// create the an array with enough bytes for a large file
bigHeader(writer, "create large file in memory");
final byte[] largeFileBytes = makeLargeFileBytes();
// uploading a large file is about the same.
bigHeader(writer, "Upload large (10MB) file");
final B2FileVersion file3;
{
final File largeFileOnDisk = new File("/tmp/B2Sample-uploadMeLarge.txt");
writeToFile(largeFileOnDisk, largeFileBytes);
final String fileName = "demo/large/superLarge.txt";
final B2ContentSource source = B2FileContentSource.builder(largeFileOnDisk).build();
B2UploadFileRequest request = B2UploadFileRequest
.builder(bucketId, fileName, B2ContentTypes.APPLICATION_OCTET, source)
.setCustomField("color", "green")
.setListener(uploadListener)
.build();
file3 = client.uploadLargeFile(request, executor);
writer.println("uploaded " + file3);
}
// list the parts of unfinished large files. (XXX: needs to be a partially uploaded one!)
bigHeader(writer, "list parts of any unfinished large files");
for (B2FileVersion largeFileVersion : client.unfinishedLargeFiles(bucketId)) {
System.out.println("====== unfinished large: " + largeFileVersion.getFileId() + " ======");
for (B2Part part : client.parts(file3.getFileId())) {
System.out.println(" " + part);
}
}
// upload a huge file but use the small file API.
bigHeader(writer, "Upload huge (2GB+) file using small file API");
final File largeFileOnDisk;
try {
final String fileName = "demo/large/huge2GBfile.txt";
largeFileOnDisk = B2Sample.makeHugeFile(fileName);
final B2ContentSource source = B2FileContentSource.builder(largeFileOnDisk).build();
B2UploadFileRequest request = B2UploadFileRequest
.builder(bucketId, fileName, B2ContentTypes.APPLICATION_OCTET, source)
.setCustomField("color", "green")
.setListener(uploadListener)
.build();
B2FileVersion file4 = client.uploadSmallFile(request);
writer.println("uploaded " + file4);
} catch (IOException e) {
writer.println("test failed: "+e.getMessage());
}
// upload some more files here so the folder structure is interesting.
// XXX...
// list all file versions
// the listBlahBuilders will have setters to control depth, delimiter, page size, total count, etc.
// the object returned (and used only for iteration below) has a method to grab a "resumePoint"
// which can be given to a builder later to resume where we left off. (one for resumeWithCurrent?
// and one for resumeWithNext? always resumeWithNext and you can save it from before calling next?)
bigHeader(writer, "list file versions");
for (B2FileVersion version : client.fileVersions(bucketId)) {
writer.println("fileVersion: " + version);
}
// list all file names
bigHeader(writer, "list file names");
for (B2FileVersion version : client.fileNames(bucketId)) {
writer.println("fileName: " + version);
}
// list file versions in a given directory
bigHeader(writer, "list file versions in a single directory");
{
final B2ListFileVersionsRequest request = B2ListFileVersionsRequest
.builder(bucketId)
.setWithinFolder("demo/large/")
.build();
for (B2FileVersion version : client.fileVersions(request)) {
writer.println("fileNameWithinFolder: " + version);
}
}
// XXX: start a large file, so there's something to list and cancel below!
// list unfinished large files. and cancel them.
bigHeader(writer, "list and cancel unfinished large files");
for (B2FileVersion largeFileVersion : client.unfinishedLargeFiles(bucketId)) {
client.cancelLargeFile(largeFileVersion.getFileId());
}
// downloadById b2 file into memory.
bigHeader(writer, "Download b2 file and print it");
{
B2ContentMemoryWriter sink = B2ContentMemoryWriter.build();
client.downloadById(file1.getFileId(), sink);
writer.println("read from file [" + new String(sink.getBytes()) + "]");
}
// we provide a helpful handler implementation for saving to a file.
// this is an example of using it with a download_by_name & a range.
bigHeader(writer, "download b2 file to disk");
{
final B2DownloadByNameRequest request = B2DownloadByNameRequest
.builder(bucketName, file1.getFileName())
.setRange(B2ByteRange.between(1, 4))
.build();
final B2ContentFileWriter handler = B2ContentFileWriter
.builder(new File("/tmp/saveToThisLocalFile.txt"))
.setVerifySha1ByRereadingFromDestination(true)
.build();
client.downloadByName(request, handler);
writer.println("headers: " + handler.getHeadersOrNull());
}
// make sure that we can downloadById the whole large file.
// this is more of a test than a sample.
bigHeader(writer, "downloadById the large file.");
{
final B2ContentMemoryWriter handler = B2ContentMemoryWriter.build();
client.downloadById(file3.getFileId(), handler);
B2Preconditions.checkState(Arrays.equals(largeFileBytes, handler.getBytes()));
}
bigHeader(writer, "Upload/Download a deflated file from memory");
{
// upload a deflated file from memory and set b2-content-encoding for fileInfo
final String originalPizza = "original pizza";
final Deflater deflater = new Deflater();
deflater.setInput(originalPizza.getBytes(StandardCharsets.UTF_8));
deflater.finish();
final byte[] buffer = new byte[512]; // 512 big enough for the compressed content
final int compressedLength = deflater.deflate(buffer);
final String compressedContent = new String(buffer, 0, compressedLength);
final B2ContentSource source = B2ByteArrayContentSource.build(compressedContent.getBytes());
final String deflatedFileName = "demo/deflatedPizza.txt";
final B2UploadFileRequest request = B2UploadFileRequest
.builder(bucketId, deflatedFileName, B2ContentTypes.B2_AUTO, source)
.setCustomField("b2-content-encoding", "deflate") // set b2-content-encoding
.build();
final B2FileVersion deflatedFile = client.uploadSmallFile(request);
writer.println("uploaded " + deflatedFile);
final B2ContentMemoryWriter sink = B2ContentMemoryWriter.build();
// call downloadById with enableContentCompression as false (by default), good for having deflate for content-encoding
client.downloadById(deflatedFile.getFileId(), sink);
writer.println("read from file [" + new String(sink.getBytes()) + "]");
if (!Arrays.equals(compressedContent.getBytes(), sink.getBytes())) {
writer.println("Failed: downloaded file content is NOT the same as the original test failed: ");
}
}
// delete file versions
client.deleteFileVersion(file1);
// get a download authorization.
{
final B2GetDownloadAuthorizationRequest request = B2GetDownloadAuthorizationRequest
.builder(bucketId, "dem", 3600)
.build();
B2DownloadAuthorization auth = client.getDownloadAuthorization(request);
writer.println("downloadAuth: " + auth);
}
// get file info.
B2FileVersion file2again = client.getFileInfo(file2.getFileId());
writer.println("file2Again: " + file2again);
// get file info by name.
B2FileVersion file2ByName = client.getFileInfoByName(bucket.getBucketName(), file2.getFileName());
writer.println("file2ByName: " + file2ByName);
if (!file2again.equals(file2ByName)) {
throw new RuntimeException("file!");
}
// hide file
client.hideFile(bucketId, file2.getFileName());
// update the bucket
{
final List lifecycleRules = new ArrayList<>();
final Map bucketInfo = new TreeMap<>();
final B2UpdateBucketRequest request = B2UpdateBucketRequest
.builder(bucket)
.setBucketType(B2BucketTypes.ALL_PUBLIC)
.setLifecycleRules(lifecycleRules)
.setBucketInfo(bucketInfo)
.build();
B2Bucket bucketAgain = client.updateBucket(request);
writer.println("bucketAgain: " + bucketAgain);
}
// delete all files with a given filename
{
final String fileNameToDelete = file1.getFileName();
B2ListFileVersionsRequest request = B2ListFileVersionsRequest
.builder(bucketId)
.setStartFileName(fileNameToDelete)
.setPrefix(fileNameToDelete)
.build();
for (B2FileVersion version : client.fileVersions(request)) {
if (version.getFileName().equals(fileNameToDelete)) {
client.deleteFileVersion(version);
} else {
break;
}
}
}
// delete all files, so we can delete the bucket.
for (B2FileVersion version : client.fileVersions(bucketId)) {
client.deleteFileVersion(version);
}
// delete the bucket
client.deleteBucket(bucketId);
// exercise account authorization.
bigHeader(writer, "exercise getAccountAuthorization() & invalidateAccountAuthorization().");
{
// do an explicit getAccountAuthorization.
// you should rarely need to do this.
// we're just doing it here to exercise it.
final B2AccountAuthorization auth = client.getAccountAuthorization();
final B2AccountAuthorization auth2 = client.getAccountAuthorization();
client.invalidateAccountAuthorization();
final B2AccountAuthorization auth3 = client.getAccountAuthorization();
writer.println("auth = " + auth);
writer.println("auth3 = " + auth3);
B2Preconditions.checkState(auth == auth2, "same object because it's cached.");
B2Preconditions.checkState(auth != auth3, "different object because we cleared the cache.");
}
}
private static void deleteBucketIfAny(PrintWriter writer,
B2StorageClient client,
String bucketName) throws B2Exception {
for (B2Bucket bucket : client.buckets()) {
if (bucketName.equals(bucket.getBucketName())) {
final String bucketId = bucket.getBucketId();
deleteAllFilesInBucket(writer, client, bucketId);
client.deleteBucket(bucketId);
writer.println("deleted bucket " + bucketName + " (" + bucketId + ")");
}
}
}
private static void deleteAllFilesInBucket(PrintWriter writer,
B2StorageClient client,
String bucketId) throws B2Exception {
int numDeleted = 0;
for (B2FileVersion version : client.fileVersions(bucketId)) {
client.deleteFileVersion(version);
numDeleted++;
writer.println(" deleted " + version);
}
writer.println("deleted " + numDeleted + " files");
}
private static void writeToFile(File file,
byte[] bytes) throws B2Exception {
try (FileOutputStream out = new FileOutputStream(file)) {
out.write(bytes);
} catch (IOException e) {
throw new RuntimeException("couldn't write file '" + file + "': " + e.getMessage(), e);
}
}
/**
* @return a new byte[] containing enough bytes to count as a large file in dev and staging.
* XXX: this isn't enough bytes to be a large file in production. :(
*/
private static byte[] makeLargeFileBytes() {
final int MB = 1000 * 1000;
final byte[] bytes = new byte[10 * MB];
int iByte = 0;
for (int iPart = 0; iPart < 2; iPart++) {
final int baseByte = (iPart == 0) ? 0 : 128;
for (int iByteInPart = 0; iByteInPart < MB; iByteInPart++) {
bytes[iByte] = (byte) (baseByte + (iByteInPart % 128));
iByte++;
}
}
return bytes;
}
/**
* Create a file large enough to be considered a large file in production;
* @return File too big to be completely loaded into a byte array
*/
private static File makeHugeFile(String fileNamePrefix) throws IOException {
final long fileSize = (long)Integer.MAX_VALUE + 1000*1000;
final byte[] bytes = {0xD, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF};
final File tempFile = File.createTempFile(fileNamePrefix, ".tmp");
final RandomAccessFile randomAccessFile= new RandomAccessFile(tempFile, "rw");
// write bytes at end to size the file
long seekTo = fileSize - bytes.length;
randomAccessFile.seek(seekTo);
randomAccessFile.write(bytes);
randomAccessFile.close();
tempFile.deleteOnExit();
return tempFile;
}
private static void bigHeader(PrintWriter writer,
String title) {
writer.println("########################################################################");
writer.println("#");
writer.println("# " + title);
writer.println("#");
writer.println("########################################################################");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy