Use Java to Create an Application
    • Dark
      Light

    Use Java to Create an Application

    • Dark
      Light

    Article Summary

    The following procedures demonstrate how to create an application using Java.

    Install the AWS SDK

    You must have Java Development Kit 8 or later and Apache Maven. You do not need to install the AWS SDK for Java 2.x because Maven will take care of this later.

    Configure AWS (Java)

    Follow this procedure to create a named profile to access Backblaze B2 Cloud Storage; this allows you to easily access Backblaze B2 and alternative Amazon Simple Storage Service (Amazon S3)-compatible cloud object stores. You can also configure your default profile, set environment variables, or use any other configuration mechanism that is supported by Java.

    If you don't have the CLI, you can create a new AWS profile by creating or editing the AWS configuration files.

    You can find the AWS credentials file at the following locations:

    • ~/.aws/credentials on Linux, macOS, or Unix
    • C:\Users\USERNAME\.aws\credentials on Windows

    You can find the AWS configuration file at the following locations:

    • ~/.aws/config on Linux, macOS, or Unix
    • C:\Users\USERNAME\.aws\config on Windows
    1. Create the .aws directory and credentials file. Add the following section to the credentials file, substituting your key_id and application_key:
      [b2tutorial]
      aws_access_key_id = <your_key_id>
      aws_secret_access_key = <your_application_key>
    2. Create the configuration file and add the following section:
      [b2tutorial]
      output = json
      s3 =
          signature_version = s3v4

    List Existing Buckets (Java)

    The simplest Amazon S3 action is List Buckets. It requires no parameters and returns a list of all of the buckets within the account.

    1. Create a new Maven project using the following command:
      mvn -B archetype:generate \                                       
      -DarchetypeGroupId=org.apache.maven.archetypes \
      -DarchetypeArtifactId=maven-archetype-quickstart \
      -DgroupId=com.example.b2client \
      -DartifactId=b2client
    2. To configure the project with a dependency for the AWS SDK and specify Java 8 as the compiler version, please update the contents of the pom.xml file located inside of the b2client directory with the following code:
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
       <modelVersion>4.0.0</modelVersion>
        <groupId>com.example.b2client</groupId>
        <artifactId>b2client</artifactId>
        <packaging>jar</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>b2client</name>
        <url>http://maven.apache.org</url>
        <dependencies>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
          </dependency>
          <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.16.60</version>
          </dependency>
          <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.36</version>
          </dependency>
        </dependencies>
             <build>
               <plugins>
                 <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-compiler-plugin</artifactId>
                   <version>3.8.1</version>
                   <configuration>
                     <source>8</source>
                     <target>8</target>
                   </configuration>
                 </plugin>
               </plugins>
             </build>
      </project>
    3. Replace the contents of the generated App.java file with the following code:
      package com.example.b2client;
      import java.net.URI;
      import java.nio.file.Path;
      import java.nio.file.Paths;
      import java.util.List;
      import java.util.regex.Matcher;
      import java.util.regex.Pattern;
      
      import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
      import software.amazon.awssdk.regions.Region;
      import software.amazon.awssdk.services.s3.S3Client;
      import software.amazon.awssdk.services.s3.model.*;
      
      public class App
      {
          // Change this to the endpoint from your bucket details, prefixed with "https://"
          private static String ENDPOINT_URL = "https://<your endpoint>";
      
         public static void main( String[] args )
                 throws Exception
          {
              // Extract the region from the endpoint URL
              Matcher matcher = Pattern.compile("https://s3\\.([a-z0-9-]+)\\.backblazeb2\\.com").matcher(ENDPOINT_URL);
              if (!matcher.find()) {
                  System.err.println("Can't find a region in the endpoint URL: " + ENDPOINT_URL);
              }
              String region = matcher.group(1);
      
              // Create a client. The try-with-resources pattern ensures the client is cleaned up when we're done with it
             try (S3Client b2 = S3Client.builder()
                     .region(Region.of(region))
                      .credentialsProvider(ProfileCredentialsProvider.create("b2tutorial"))
                      .endpointOverride(new URI(ENDPOINT_URL)).build()) {
      
                  // Get the list of buckets
                 List<Bucket> buckets = b2.listBuckets().buckets();
      
                 // Iterate through list, printing each bucket's name
                  System.out.println("Buckets in account:");
                  for (Bucket bucket : buckets) {
                      System.out.println(bucket.name());
                  }
              }
          }
      }
      A warning may appear that indicates some of the imports are unused. They are all included so that you do not have to add more later.
    4. Edit the value of the ENDPOINT_URL string constant to match your endpoint, for example:
      private static String ENDPOINT_URL = "https://s3.us-west-004.backblazeb2.com";
      The AWS SDK for Java 2.x requires a region when creating an Amazon S3 client, so the application extracts the region substring from the endpoint URL with a regular expression. This means you do not have to define a separate string constant for the region for the region to match the endpoint.
      The app builds an S3Client instance with the region, profile, and endpoint, and invokes the client's listBuckets() method, calling buckets() on the response to obtain a List of Bucket objects. Finally, the app iterates through the list, printing each bucket's name.
    5. Compile and run the following sample:
      mvn package exec:java -Dexec.mainClass="com.example.b2client.App" -DskipTests --quiet

    The first time you build the project, Maven downloads the project dependencies, so it might take a minute or two to complete. An output similar to the following example is returned:

    Buckets in account:
    my-unique-bucket-name

    Create a Private Bucket (Java)

    You already created a public bucket in the Backblaze web UI. Use this procedure to use the Amazon S3 'Create Bucket' action to create a private bucket programmatically.

    1. Add the following code at the bottom of the main() method in App.java, and replace the bucket name with a unique name:
      String bucketName = "another-unique-bucket-name";
                  try {
                      System.out.println("\nTrying to create bucket: " + bucketName);
                      CreateBucketResponse createBucketResponse = b2.createBucket(CreateBucketRequest
                              .builder()
                              .bucket(bucketName)
                              .acl(BucketCannedACL.PRIVATE)
                              .build());
                      System.out.println("Success! Response is: " + createBucketResponse.toString());
                  } catch (BucketAlreadyOwnedByYouException e) {
                      System.out.println("You already created " + bucketName + ". \nCarrying on...");
                  } catch (BucketAlreadyExistsException e) {
                      System.out.println(bucketName + " already exists in another account. \nExiting.");
                      System.exit(1);
      The app builds a CreateBucketRequest instance with the bucket name and the private canned ACL, passing it to the client's createBucket() method and displaying the response from Backblaze B2.
      The app may already exist, in which case createBucket() throws an exception. The exception's class indicates whether the bucket is owned by your account. If so, then the app carries on to the next step; otherwise, the app exits with an error.
    2. Compile and run the following code again:
      mvn package exec:java -Dexec.mainClass="com.example.b2client.App" -DskipTests --quiet
      An output similar to the following example is returned:
      Buckets in account:
      my-unique-bucket-name
      
      Trying to create bucket: another-unique-bucket-name
      Success! Response is: CreateBucketResponse(Location=/another-unique-bucket-name)
      another-unique-bucket-name created
      If the bucket already exists in another account, the following message is returned:
      Buckets in account:
      my-unique-bucket-name
      
      Trying to create bucket: tester
      tester already exists in another account. 
      Exiting.
    3. After the bucket is created, run the following code again:
      mvn package exec:java -Dexec.mainClass="com.example.b2client.App" -DskipTests --quiet
      The following output is returned that indicates that the exception was handled:
      Buckets in account:
      another-unique-bucket-name
      my-unique-bucket-name
      
      Trying to create bucket: another-unique-bucket-name
      You already created another-unique-bucket-name. 
      Carrying on...

    Upload a File to a Bucket (Java)

    In this final section of the tutorial, you will upload a file to the private bucket using theAmazon S3 'Put Object' action.

    1. To upload a single file to your private bucket in Backblaze B2, add the following code after the last section that you pasted into App.java, and replace the path with the path of your file to upload:
      // The key in B2 is set to the file name.
      Path pathToFile = Paths.get("./myimage.png");
      PutObjectResponse putObjectResponse = b2.putObject(PutObjectRequest.builder()
              .bucket(bucketName)
              .key(pathToFile.getFileName().toString())
              .build(),
              pathToFile);
      System.out.println("Success! Response is: " + putObjectResponse.toString());
      This section of code builds a PutObjectRequest that specifies the same bucket name as before and sets the key to the file name from the path you specify. The request is passed to the putObject method with the path to your file.
    2. Use the following code to build and run the app again:
      mvn package exec:java -Dexec.mainClass="com.example.b2client.App" -DskipTests --quiet
      An output similar to the following example is returned:
      Buckets in account:
      another-unique-bucket-name
      my-unique-bucket-name
      
      Trying to create bucket: another-unique-bucket-name
      You already created another-unique-bucket-name. 
      Carrying on...
      Success! Response is: PutObjectResponse(ETag="af8b4f7279198443eea8d67b85bb794c", VersionId=4_z838d18a1bf8627788b280413_f115e5462aef0ba24_d20220725_m200812_c004_v0402006_t0051_u01658779692638)

    Etag and VersionId Output (Java)

    The Etag value (represented in Boto3 as e_tag) identifies a specific version of the file's content. Etag is a standard HTTP header that is included when clients download files from Backblaze B2. Etag enables caches to be more efficient and save bandwidth because a web server does not need to resend a full response if the content was not changed. VersionId (version_id) identifies a specific version of the file within Backblaze B2. If a file is uploaded to an existing key in a bucket, a new version of the file is stored even if the file content is the same.

    To see the difference between ETag and VersionId, run the 'upload file' commands a second time and upload the same file content to the same bucket and key. The ETag is the same since the content hasn't changed, but a new VersionId is returned.

    An output similar to the following example is returned:

    Buckets in account:
    another-unique-bucket-name
    my-unique-bucket-name
    
    Trying to create bucket: another-unique-bucket-name
    You already created another-unique-bucket-name. 
    Carrying on…
    
    Uploading: ./myimage.png
    Success! Response is: PutObjectResponse(ETag="af8b4f7279198443eea8d67b85bb794c", VersionId=4_z838d18a1bf8627788b280413_f112be370c4d86f6a_d20220725_m205707_c004_v0402009_t0021_u01658782627043)

    Use the putObject method to upload a single file. To upload multiple files, your application must build a list of files to upload and iterate through it. Use the asynchronous programming features of the AWS SDK for Java 2.x to upload multiple files concurrently.

    Browse Files (Java)

    In the Backblaze web UI, navigate to your private bucket on the Browse Files page. Your file is displayed with a (2) next to the filename.

    If you click the (2), and click one of the file versions, you will see that the Fguid matches the VersionId that was returned when the file was created.

    There is also no File Info for this file. The Backblaze web UI set the src_last_modified_millis attribute for the file that you uploaded earlier, but you did not specify one when you uploaded the file.

    Click one of the URLs to open it in the browser. You cannot access the file because it is in a private bucket. The S3-Compatible API returns the following XML-formatted error for theAmazon S3 URL:

    <Error>
        <Code>UnauthorizedAccess</Code>
        <Message>bucket is not authorized: another-unique-bucket-name</Message>
    </Error>

    The Native API returns a similar, JSON-formatted error for the Native and Friendly URLs:

    {
      "code": "unauthorized",
      "message": "",
      "status": 401
    }

    Was this article helpful?