# Storage Queue Service SDK Migration Guide from 8.x to 12.x In this section, we list the main changes you need to be aware of when converting your Storage Queue SDK library from Version 8 to Version 12. For more info of the motivation behind this major change, please refer to [this guide](https://github.com/Azure/azure-storage-java/blob/master/V12%20Upgrade%20Story.md). ## Prerequisites Java Development Kit (JDK) with version 8 or above ## Converting Core Classes Our core synchronous classes have been replaced, as well as new asynchronous counterparts added. | Core V8 classes | Equivalent V12 Class | NEW Asynchronous clients | |---:|---:|---:| | CloudStorageAccount | QueueServiceClientBuilder | QueueServiceClientBuilder | | CloudQueueClient | QueueServiceClient | QueueServiceAsyncClient | | CloudQueue & CloudQueueMessage | QueueClient | QueueAsyncClient | ## Updated Maven dependency Dependency for Queue service: ```xml com.azure azure-storage-queue 12.0.0 ``` ## Build Client In V8, core classes were built from `CloudStorageAccount` which authenticated with connection string. ```java CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); CloudQueue cloudQueue = storageAccount.createCloudQueueClient().getQueueReference(""); ``` In V12, we have moved to a builder pattern. To replicate the above V8 snippet: ```java // To get the QueueClient, we can use builder to initialize. final QueueClient queueClient = new QueueClientBuilder() .endpoint("https://" + "" + ".queue.core.windows.net") .queueName("") .credential(new StorageSharedKeyCredential("", "")) .buildClient(); ``` ## Generate SAS token SAS token generation has moved from helper classes to the core clients themselves. See section [SAS Token](#sastoken) to learn how to use them as a credential. Not all fields being set in these samples are necessary. At minimum, only an expiry time and permission set are necessary to create a SAS. In V8, to generate the SAS token, you needed to use `SharedAccessSignatureHelper` to fluently build out all it's options. You also needed to provide `ServiceClient` which includes `SharedKeyCredential` to sign the token with. ```java // Build the client CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); CloudQueue cloudQueue = storageAccount.createCloudQueueClient().getQueueReference(""); // Initialize the properties String identifier = "identifier"; EnumSet permissions = EnumSet.of( SharedAccessQueuePermissions.READ, SharedAccessQueuePermissions.UPDATE, SharedAccessQueuePermissions.ADD, SharedAccessQueuePermissions.PROCESSMESSAGES); IPRange ipR = new IPRange("0.0.0.0", "255.255.255.255"); Calendar calendar = Calendar.getInstance(); Date startDate = calendar.getTime(); calendar.add(Calendar.DAY_OF_YEAR, 1); Date expiryDate = calendar.getTime(); SharedAccessQueuePolicy policy = new SharedAccessQueuePolicy(); policy.setPermissions(permissions); policy.setSharedAccessStartTime(startDate); policy.setSharedAccessExpiryTime(expiryDate); // Build the token String sasToken = cloudQueue.generateSharedAccessSignature(policy, identifier, ipR, SharedAccessProtocols.HTTPS_ONLY); ``` In V12, SAS tokens are generated off the client to the resource you wish to generate the SAS for. The resource path handled automatically because of this, and the `SharedKeyCredential` authenticating the client is also used automatically to sign the SAS. See [building a client](#buildclient) for how to get an authenticated client. ```java // specify token properties String identifier = "identifier"; QueueSasPermission permissions = new QueueSasPermission() .setReadPermission(true) .setAddPermission(true) .setProcessPermission(true) .setUpdatePermission(true); OffsetDateTime startTime = OffsetDateTime.now().minusDays(1); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); SasIpRange ipRange = new SasIpRange() .setIpMax("0.0.0.0") .setIpMax("255.255.255.255"); SasProtocol sasProtocol = SasProtocol.HTTPS_HTTP; String version = ShareServiceVersion.V2019_02_02.getVersion(); // build the token QueueServiceSasSignatureValues sasSignatureValues = new QueueServiceSasSignatureValues(); sasSignatureValues.setVersion(version) .setProtocol(sasProtocol) .setStartTime(startTime) .setExpiryTime(expiryTime) .setPermissions(permissions) .setSasIpRange(ipRange) .setIdentifier(identifier); QueueServiceSasQueryParameters sasQueryParameters = sasSignatureValues.generateSasQueryParameters(new StorageSharedKeyCredential("", ""); ``` In V12, our builders accept connection strings, no calls to `endpoint()` or `credential()` required. However, connection strings generally only point at the account, so you WILL need to specify queue name as necessary. ```java QueueServiceClient client = new QueueServiceClientBuilder() .connectionString("${connection-string}") .buildClient(); ``` ### Shared key credential Shared key credentials can be used directly to authenticate your client. You need to fetch the `${accountName}` and `${accountKey}` from Azure Portal. Learn More from [README](https://github.com/Azure/azure-sdk-for-java/blob/azure-storage-queue_12.0.0/sdk/storage/azure-storage-queue/README.md) In V8, you used the credential to build the `CloudStorageAccount`. ```java // Initialize the credentials StorageCredentialsAccountAndKey credential = new StorageCredentialsAccountAndKey("${accountName}", "${accountKey}"); // CloudStorageAccount take the credential. CloudStorageAccount storageAccount = new CloudStorageAccount(credential); ``` Since the builder in V12 manages pipeline generation, you can just hand the `StorageSharedKeyCredential` to the builder. ```java // Initialize the credentials StorageSharedKeyCredential credential = new StorageSharedKeyCredential("${accountName}", "${accountKey}"); // How service object take in the credentials. QueueServiceClient client = new QueueServiceClientBuilder() .endpoint("https://" + "" + ".queue.core.windows.net") .credential(credential) .buildClient(); ``` ### SASToken A URL with a SAS token looks like the following: `https://${accountName}.queue.core.windows.net/?${sasToken}`. Refer the [documentation](https://github.com/Azure/azure-sdk-for-java/blob/azure-storage-queue_12.0.0/sdk/storage/azure-storage-queue/README.md) for more info. See section [Generate SAS token](#generate-sas-token) for how to generate the token programmatically. In V8, you had to sasToken string, which can paste from portal or generate from session above . ```java // Here is how the blob object take in the sas token generated in above section [Generate SAS token](#generate-sas-token). StorageCredentialsSharedAccessSignature credential = new StorageCredentialsSharedAccessSignature("sasToken"); CloudStorageAccount storageAccount = new CloudStorageAccount(credential); ``` In V12, SAS tokens can be managed just like any other credential. ```java // How service object take in the credentials. QueueServiceClient client = new QueueServiceClientBuilder() .endpoint("https://${accountName}.queue.core.windows.net") .sasToken("${sasToken}") .buildClient(); ``` However, if you already have the full URL with SAS token attached, you can use that too: ```java QueueServiceClient client = new QueueServiceClientBuilder() .endpoint("https://${accountName}.queue.core.windows.net/?${sasToken}") .buildClient(); ``` ## Minimum Overload APIs and Maxmum Overload APIs: In V8, we only provide many APIs overloads with the same return type. ```java public QueueServiceProperties getProperties() ``` In V12, we provide at least one minimum and one maximum for most of the operations. Minimum overload returns someType of `T` directly. Maximum overload returns response of someType `Response` which includes the information of the headers, the request, status code, and the type value. Minimum overload in async: ```java public QueueServiceProperties getProperties() ``` Maximum overload in async: ```java public Response getPropertiesWithResponse(Duration timeout, Context context) ``` Listing or Paging API returned `ResultSegment` in V8 which provided the continuation token and result list in `ResultSegment`. List all queues V8: ```java private CloudQueueClient queueClient; private List retrieveQueuesForCurrentPage(ResultContinuation pageToken, List results) throws Exception { if (pageToken == null) { return results; } ResultSegment resultsNextPage = queueClient.listQueuesSegmented(null, QueueListingDetails.NONE, null, pageToken, null, null); results.addAll(resultsNextPage.getResults()); retrieveQueuesForCurrentPage(resultsNextPage.getContinuationToken(), resultsNextPage.getResults()); return results; } public void run() throws Exception{ // Build CloudQueueClient CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); queueClient = new CloudQueueClient(storageAccount.getQueueStorageUri(), storageAccount.getCredentials()); // Initialize empty queue list ResultSegment results = queueClient.listQueuesSegmented(); // Start from first page retrieveQueuesForCurrentPage(results.getContinuationToken(), results.getResults()); } ``` V12 provides two pagination classes: `PagedIterable` for sync and `PageFlux` for async. These allow you to consume listing operations by individual item or by response pages. The latter is needed to access general information in each HTTP response. List all queues using sync API V12, by page: ```java private QueueServiceClient queueServiceClient; private List retrieveBlobs(String pageToken, List results) { if (pageToken == null) { return results; } queueServiceClient.listQueues().streamByPage(pageToken).forEach( response -> { results.addAll((Collection) response.getValue()); retrieveBlobs(response.getContinuationToken(), results); } ); return results; } public void run() { // Build queueServiceClient queueServiceClient = new QueueServiceClientBuilder().credential(new StorageSharedKeyCredential("", "")).buildClient(); // Initialize empty queue list List results = new ArrayList<>(); // Start from first page queueServiceClient.listQueues() .streamByPage() .forEach(response -> { results.addAll((Collection) response.getValue()); if (response.getContinuationToken() != null) { results.addAll((Collection) retrieveBlobs(response.getContinuationToken(), results)); } }); } ```