# Storage File Share 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 File Share 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 | ShareServiceClientBuilder | ShareServiceClientBuilder | | CloudFileClient | ShareServiceClient | ShareServiceAsyncClient | | CloudFileShare | ShareClient | ShareAsyncClient | | CloudFileDirectory | ShareDirectoryClient | ShareDirectoryAsyncClient | | CloudFile | ShareFileClient | ShareFileAsyncClient | ## Updated Maven dependency Dependency for File Share service: ```xml com.azure azure-storage-file-share 12.0.0 ``` ## Build Client In V8, core classes were built from `CloudStorageAccount` which authenticated with connection string. ```java CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); CloudFileShare fileShare = storageAccount.createCloudFileClient().getShareReference(""); fileShare.create(); CloudFileDirectory cloudFileDirectory = fileShare.getRootDirectoryReference().getDirectoryReference(""); cloudFileDirectory.create(); CloudFile cloudFile = cloudFileDirectory.getFileReference(""); ``` In V12, we have moved to a builder pattern. To replicate the above V8 snippet: ```java // To get the ShareFileClient, we can use builder to initialize. final ShareFileClient fileClient = new ShareFileClientBuilder() .endpoint("https://" + "" + ".queue.core.windows.net") .shareName("") .resourcePath("") .credential(new StorageSharedKeyCredential("", "")) .buildFileClient(); ``` ## Credentials ### Connection string V8 `CloudStorageAccount` can take connection strings as credentials. ```java CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); ``` 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 share and path to resource as necessary. ```java ShareServiceClient client = new ShareServiceClientBuilder() .connectionString("${connection-string}") .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(""); CloudFileShare fileShare = storageAccount.createCloudFileClient().getShareReference(""); fileShare.create(); CloudFileDirectory cloudFileDirectory = fileShare.getRootDirectoryReference().getDirectoryReference(""); cloudFileDirectory.create(); CloudFile cloudFile = cloudFileDirectory.getFileReference(""); // Initialize the properties String identifier = "identifier"; EnumSet permissions = EnumSet.of( SharedAccessFilePermissions.READ, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.CREATE, SharedAccessFilePermissions.DELETE, SharedAccessFilePermissions.LIST); 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(); SharedAccessFileHeaders headers = new SharedAccessFileHeaders(); headers.setCacheControl("cache"); headers.setContentDisposition("dispoistion"); headers.setContentEncoding("encoding"); headers.setContentLanguage("language"); headers.setContentType("type"); SharedAccessFilePolicy policy = new SharedAccessFilePolicy(); policy.setPermissions(permissions); policy.setSharedAccessStartTime(startDate); policy.setSharedAccessExpiryTime(expiryDate); // Build the token String sasToken = cloudFile.generateSharedAccessSignature(policy, headers, 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"; ShareSasPermission permissions = new ShareSasPermission() .setReadPermission(true) .setCreatePermission(true) .setDeletePermission(true) .setWritePermission(true); // We can also choose ShareFileSasPermission based on the object level we want to grant access. 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 cacheControl = "cache"; String contentDisposition = "disposition"; String contentEncoding = "encoding"; String contentLanguage = "language"; String contentType = "type"; String version = ShareServiceVersion.V2019_02_02.getVersion(); // build the token ShareServiceSasSignatureValues sasSignatureValues = new ShareServiceSasSignatureValues(); sasSignatureValues.setVersion(version) .setProtocol(sasProtocol) .setStartTime(startTime) .setExpiryTime(expiryTime) .setPermissions(permissions) .setSasIpRange(ipRange) .setIdentifier(identifier) .setCacheControl(cacheControl) .setContentDisposition(contentDisposition) .setContentEncoding(contentEncoding) .setContentLanguage(contentLanguage) .setContentType(contentType); ShareServiceSasQueryParameters sasQueryParameters = sasSignatureValues.generateSasQueryParameters(new StorageSharedKeyCredential("", "" + ".file.core.windows.net") .credential(credential) .buildClient(); ``` ### SASToken A URL with a SAS token looks like the following: `https://${accountName}.file.core.windows.net/?${sasToken}`. Refer the [documentation](https://github.com/Azure/azure-sdk-for-java/tree/azure-storage-file-share_12.0.0/sdk/storage/azure-storage-file-share/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. ShareServiceClient client = new ShareServiceClientBuilder() .endpoint("https://${accountName}.file.core.windows.net") .sasToken("${sasToken}") .buildClient(); ``` However, if you already have the full URL with SAS token attached, you can use that too: ```java ShareServiceClient client = new ShareServiceClientBuilder() .endpoint("https://${accountName}.file.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 ShareProperties 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 ShareServiceProperties 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 blobs V8: ```java private CloudFileDirectory directory; private List retrieveFilesForCurrentPage(ResultContinuation pageToken, List results) throws Exception { if (pageToken == null) { return results; } ResultSegment resultsNextPage = directory.listFilesAndDirectoriesSegmented(null, null, pageToken, null, null); results.addAll(resultsNextPage.getResults()); retrieveFilesForCurrentPage(resultsNextPage.getContinuationToken(), resultsNextPage.getResults()); return results; } public void run() throws Exception{ // Build CloudFileDirectory CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); directory = new CloudFileDirectory(storageAccount.getBlobStorageUri()); // Initialize empty file list ResultSegment results = directory.listFilesAndDirectoriesSegmented(); // Start from first page retrieveFilesForCurrentPage(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 files using sync API V12, by page: ```java private ShareDirectoryClient directoryClient; private List retrieveFiles(String pageToken, List results) { if (pageToken == null) { return results; } directoryClient.listFilesAndDirectories().streamByPage(pageToken).forEach( response -> { results.addAll((Collection) response.getValue()); retrieveFiles(response.getContinuationToken(), results); } ); return results; } public void run() { // Build directoryClient directoryClient = new ShareFileClientBuilder().credential(new StorageSharedKeyCredential("", "")).buildDirectoryClient(); // Initialize empty file list List results = new ArrayList<>(); // Start from first page directoryClient.listFilesAndDirectories() .streamByPage() .forEach(response -> { results.addAll((Collection) response.getValue()); if (response.getContinuationToken() != null) { results.addAll((Collection) retrieveFiles(response.getContinuationToken(), results)); } }); } ``` ## `StorageFileInputStream` and `StorageFileOutputStream` In v8 and prior versions, there existed two classes: `FileInputStream` and `FileOutputStream`, which simplified uploads and downloads by providing streams developers were used to. With the inclusion of synchronous clients in V12, customers who may have already migrated from v8 to V10/V11 will find these familiar classes, but they will be brand new to those who started with V10/V11. Note that these classes do NOT give you access to the HTTP requests/responses. Give an InputStream to download file in V8. ```java CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); CloudFile file = new CloudFile(storageAccount.getFileStorageUri()); OutputStream fileOutputStream = file.openWriteExisting(); ``` Give an OutputStream to upload file in V8. ```java CloudStorageAccount storageAccount = CloudStorageAccount.parse(""); CloudFile file = new CloudFile(storageAccount.getFileStorageUri()); InputStream fileInputStream = file.openRead(); ``` Get an InputStream to download file in V12. ```java final ShareFileClient fileClient = new ShareFileClientBuilder() .endpoint("https://${accountName}.file.core.windows.net") .credential(new StorageSharedKeyCredential("", "")) .buildFileClient(); InputStream fileInputStream = fileClient.openInputStream(); // insert your method of choice to read from an InputStream ``` Get an OutputStream to upload file in V12. ```java final ShareFileClient fileClient = new ShareFileClientBuilder() .endpoint("https://${accountName}.file.core.windows.net") .credential(new StorageSharedKeyCredential("", "")) .buildFileClient(); OutputStream fileOutputStream = fileClient.getFileOutputStream(); // insert your method of choice to write to an OutputStream ```