/**
   * Returns a reference to a {@link CloudFileDirectory} object that represents a subdirectory in
   * this directory.
   *
   * @param itemName A <code>String</code> that represents the name of the subdirectory.
   * @return A {@link CloudFileDirectory} object that represents a reference to the specified
   *     directory.
   * @throws URISyntaxException If the resource URI is invalid.
   * @throws StorageException
   */
  public CloudFileDirectory getSubDirectoryReference(final String itemName)
      throws URISyntaxException, StorageException {
    Utility.assertNotNullOrEmpty("itemName", itemName);

    StorageUri subdirectoryUri = PathUtility.appendPathToUri(this.storageUri, itemName);
    return new CloudFileDirectory(subdirectoryUri, itemName, this.getShare());
  }
  /**
   * Returns a reference to a {@link CloudFile} object that represents a file in this directory.
   *
   * @param fileName A <code>String</code> that represents the name of the file.
   * @return A {@link CloudFile} object that represents a reference to the specified file.
   * @throws StorageException If a storage service error occurred.
   * @throws URISyntaxException If the resource URI is invalid.
   */
  public CloudFile getFileReference(final String fileName)
      throws URISyntaxException, StorageException {
    Utility.assertNotNullOrEmpty("fileName", fileName);

    StorageUri subdirectoryUri = PathUtility.appendPathToUri(this.storageUri, fileName);

    return new CloudFile(subdirectoryUri, this.fileServiceClient, this.getShare());
  }
 /**
  * Returns the share for this directory.
  *
  * @return A {@link CloudFileShare} that represents the share for this directory.
  * @throws StorageException If a storage service error occurred.
  * @throws URISyntaxException If the resource URI is invalid.
  */
 @Override
 public CloudFileShare getShare() throws StorageException, URISyntaxException {
   if (this.share == null) {
     this.share =
         this.fileServiceClient.getShareReference(
             PathUtility.getShareNameFromUri(
                 this.getUri(), this.fileServiceClient.isUsePathStyleUris()));
   }
   return this.share;
 }
  /**
   * Strips the query and verifies the URI is absolute.
   *
   * @param completeUri A {@link StorageUri} object which represents the complete URI.
   * @param existingClient A {@link CloudFileClient} object which represents the client to use.
   * @param usePathStyleUris <code>true</code> if path-style URIs are used; otherwise, <code>false
   *     </code>.
   * @throws StorageException If a storage service error occurred.
   * @throws URISyntaxException
   */
  private void parseQueryAndVerify(
      final StorageUri completeUri,
      final CloudFileClient existingClient,
      final boolean usePathStyleUri)
      throws StorageException, URISyntaxException {
    Utility.assertNotNull("completeUri", completeUri);

    if (!completeUri.isAbsolute()) {
      final String errorMessage =
          String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString());
      throw new IllegalArgumentException(errorMessage);
    }

    this.storageUri = PathUtility.stripURIQueryAndFragment(completeUri);
    this.fileServiceClient =
        (existingClient == null)
            ? new CloudFileClient(
                PathUtility.getServiceClientBaseAddress(this.storageUri, usePathStyleUri), null)
            : existingClient;
    this.name = PathUtility.getFileNameFromURI(completeUri.getPrimaryUri(), usePathStyleUri);
  }
  /**
   * Transforms a resource URI into a shared access signature URI, by appending a shared access
   * token and using the specified operation context.
   *
   * @param resourceUri A <code>java.net.URI</code> object that represents the resource URI to be
   *     transformed.
   * @param opContext An {@link OperationContext} object that represents the context for the current
   *     operation. This object is used to track requests to the storage service, and to provide
   *     additional runtime information about the operation.
   * @return A <code>java.net.URI</code> object that represents the signature, including the
   *     resource URI and the shared access token.
   * @throws StorageException If a storage service error occurred.
   * @throws URISyntaxException If the resource URI is not properly formatted.
   */
  @Override
  public URI transformUri(final URI resourceUri, final OperationContext opContext)
      throws URISyntaxException, StorageException {
    if (resourceUri == null) {
      return null;
    }

    if (this.isHttpsOnly() && !resourceUri.getScheme().equals(Constants.HTTPS)) {
      throw new IllegalArgumentException(
          SR.CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS);
    }

    // append the sas token to the resource uri
    URI sasUri = PathUtility.addToQuery(resourceUri, this.token);

    // append the api version parameter to the sas uri
    String apiVersion =
        Constants.QueryConstants.API_VERSION
            + "="
            + Constants.HeaderConstants.TARGET_STORAGE_VERSION;
    return PathUtility.addToQuery(sasUri, apiVersion);
  }
  /**
   * Returns the {@link CloudFileDirectory} parent directory associated with this directory.
   *
   * @return An {@link CloudFileDirectory} object that represents the parent directory associated
   *     with the directory.
   * @throws StorageException
   * @throws URISyntaxException
   */
  @Override
  public CloudFileDirectory getParent() throws URISyntaxException, StorageException {
    if (this.parent == null) {
      final String parentName =
          CloudFile.getParentNameFromURI(this.getStorageUri(), this.getShare());

      if (parentName != null) {
        StorageUri parentURI =
            PathUtility.appendPathToUri(this.getShare().getStorageUri(), parentName);
        this.parent = new CloudFileDirectory(parentURI, this.getServiceClient());
      }
    }
    return this.parent;
  }
  /**
   * Creates an instance of the <code>StorageCredentialsSharedAccessSignature</code> class using the
   * specified shared access signature token.
   *
   * @param token A <code>String</code> that represents shared access signature token.
   */
  public StorageCredentialsSharedAccessSignature(final String token) {
    this.token = token;

    if (token == null) {
      this.setHttpsOnly(false);
    } else {
      try {
        Map<String, String[]> queryParams = PathUtility.parseQueryString(token);
        final String[] protocols = queryParams.get(Constants.QueryConstants.SIGNED_PROTOCOLS);
        this.setHttpsOnly((protocols != null) && Constants.HTTPS.equals(protocols[0]));
      } catch (StorageException e) {
        this.setHttpsOnly(false);
      }
    }
  }