All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.azure.storage.file.CloudFile Maven / Gradle / Ivy

There is a newer version: 8.6.6
Show newest version
/**
 * Copyright Microsoft Corporation
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.microsoft.azure.storage.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

import com.microsoft.azure.storage.AccessCondition;
import com.microsoft.azure.storage.Constants;
import com.microsoft.azure.storage.DoesServiceRequest;
import com.microsoft.azure.storage.IPRange;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.SharedAccessProtocols;
import com.microsoft.azure.storage.StorageCredentials;
import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.azure.storage.StorageErrorCode;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.StorageLocation;
import com.microsoft.azure.storage.StorageUri;
import com.microsoft.azure.storage.blob.BlobRequestOptions;
import com.microsoft.azure.storage.blob.CloudBlob;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.core.Base64;
import com.microsoft.azure.storage.core.BaseResponse;
import com.microsoft.azure.storage.core.ExecutionEngine;
import com.microsoft.azure.storage.core.Logger;
import com.microsoft.azure.storage.core.NetworkInputStream;
import com.microsoft.azure.storage.core.PathUtility;
import com.microsoft.azure.storage.core.RequestLocationMode;
import com.microsoft.azure.storage.core.SR;
import com.microsoft.azure.storage.core.SharedAccessSignatureHelper;
import com.microsoft.azure.storage.core.StorageCredentialsHelper;
import com.microsoft.azure.storage.core.StorageRequest;
import com.microsoft.azure.storage.core.StreamMd5AndLength;
import com.microsoft.azure.storage.core.UriQueryBuilder;
import com.microsoft.azure.storage.core.Utility;
import com.microsoft.azure.storage.core.WrappedByteArrayOutputStream;

/**
 * Represents a Microsoft Azure File.
 */
public final class CloudFile implements ListFileItem {
    /**
     * Holds the number of bytes to buffer when writing to a {@link FileOutputStream}.
     */
    protected int streamWriteSizeInBytes = Constants.DEFAULT_STREAM_WRITE_IN_BYTES;

    /**
     * Holds the minimum read size when using a {@link FileInputStream}.
     */
    protected int streamMinimumReadSizeInBytes = Constants.DEFAULT_MINIMUM_READ_SIZE_IN_BYTES;

    /**
     * Holds the file's share reference.
     */
    private CloudFileShare share;

    /**
     * Represents the file's directory reference.
     */
    protected CloudFileDirectory parent;

    /**
     * Holds the file's name.
     */
    private String name;

    /**
     * Represents the file service client.
     */
    protected CloudFileClient fileServiceClient;

    /**
     * Holds the metadata for the file.
     */
    private HashMap metadata = new HashMap();

    /**
     * Holds the properties of the file.
     */
    private FileProperties properties = new FileProperties();

    /**
     * Stores the absolute URI to the file.
     */
    private StorageUri storageUri;

    /**
     * Creates an instance of the CloudFile class using the specified absolute URI.
     * 
     * @param fileAbsoluteUri
     *            A java.net.URI object that represents the absolute URI to the file.
     * 
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException
     *             If the resource URI is invalid.
     */
    public CloudFile(final URI fileAbsoluteUri) throws StorageException, URISyntaxException {
        this(new StorageUri(fileAbsoluteUri));
    }

    /**
     * Creates an instance of the CloudFile class using the specified absolute StorageUri.
     * 
     * @param fileAbsoluteUri
     *            A {@link StorageUri} object that represents the absolute URI to the file.
     * 
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException
     *             If the resource URI is invalid.
     */
    public CloudFile(final StorageUri fileAbsoluteUri) throws StorageException, URISyntaxException {
        this(fileAbsoluteUri, null);
    }

    /**
     * Creates an instance of the CloudFile class using the specified absolute URI 
     * and credentials.
     * 
     * @param fileAbsoluteUri
     *            A java.net.URI object that represents the absolute URI to the file.
     * @param credentials
     *            A {@link StorageCredentials} object used to authenticate access.
     * 
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException 
     */
    public CloudFile(final URI fileAbsoluteUri, final StorageCredentials credentials) throws StorageException, URISyntaxException {
        this(new StorageUri(fileAbsoluteUri), credentials);
    }

    /**
     * Creates an instance of the CloudFile class using the specified absolute StorageUri 
     * and credentials.
     * 
     * @param fileAbsoluteUri
     *            A {@link StorageUri} object that represents the absolute URI to the file.
     * @param credentials
     *            A {@link StorageCredentials} object used to authenticate access.
     * 
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException 
     */
    public CloudFile(final StorageUri fileAbsoluteUri, final StorageCredentials credentials) throws StorageException, URISyntaxException {    
        this.parseQueryAndVerify(fileAbsoluteUri, credentials);
    }

    /**
     * Creates an instance of the CloudFile class by copying values from another cloud file.
     * 
     * @param otherFile
     *            A CloudFile object that represents the file to copy.
     */
    public CloudFile(final CloudFile otherFile) {
        this.metadata = new HashMap();
        this.properties = new FileProperties(otherFile.properties);
        if (otherFile.metadata != null) {
            for (final String key : otherFile.metadata.keySet()) {
                this.metadata.put(key, otherFile.metadata.get(key));
            }
        }

        this.storageUri = otherFile.storageUri;
        this.share = otherFile.share;
        this.parent = otherFile.parent;
        this.fileServiceClient = otherFile.fileServiceClient;
        this.name = otherFile.name;
        this.setStreamMinimumReadSizeInBytes(otherFile.getStreamMinimumReadSizeInBytes());
        this.setStreamWriteSizeInBytes(otherFile.getStreamWriteSizeInBytes());
    }
    
    /**
     * Creates an instance of the CloudFile class using the specified address, share,
     * and client.
     * 
     * @param uri
     *            A {@link StorageUri} that represents the file directory's address.
     * @param fileName
     *            A String that represents the name of the file.
     * @param share
     *            A {@link CloudFileShare} object that represents the associated file share.
     */
    protected CloudFile(final StorageUri uri, final String fileName, final CloudFileShare share) {
        Utility.assertNotNull("uri", uri);
        Utility.assertNotNull("fileName", fileName);
        Utility.assertNotNull("share", share);

        this.name = fileName;
        this.fileServiceClient = share.getServiceClient();
        this.share = share;
        this.storageUri = uri;
    }

    /**
     * Aborts an ongoing Azure File copy operation.
     *
     * @param copyId
     *            A String object that identifies the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException 
     */
    @DoesServiceRequest
    public final void abortCopy(final String copyId) throws StorageException, URISyntaxException {
        this.abortCopy(copyId, null /* accessCondition */, null /* options */, null /* opContext */);
    }

    /**
     * Aborts an ongoing Azure File copy operation.
     *
     * @param copyId
     *            A String object that identifies the copy operation.
     * @param accessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the Azure File.
     * @param options
     *            A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying
     *            null will use the default request options from the associated service client (
     *            {@link CloudFileClient}).
     * @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.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException 
     */
    @DoesServiceRequest
    public final void abortCopy(final String copyId, final AccessCondition accessCondition, FileRequestOptions options,
            OperationContext opContext) throws StorageException, URISyntaxException {
        if (opContext == null) {
            opContext = new OperationContext();
        }

        this.getShare().assertNoSnapshot();

        opContext.initialize();
        options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);

        ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
                this.abortCopyImpl(copyId, accessCondition, options), options.getRetryPolicyFactory(), opContext);
    }

    private StorageRequest abortCopyImpl(final String copyId,
            final AccessCondition accessCondition, final FileRequestOptions options) {
        Utility.assertNotNull("copyId", copyId);

        final StorageRequest putRequest =
                new StorageRequest(options, this.getStorageUri()) {

            @Override
            public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context)
                    throws Exception {
                return FileRequest.abortCopy(file.getTransformedAddress(context).getUri(this.getCurrentLocation()),
                        options, context, accessCondition, copyId);
            }

            @Override
            public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context)
                    throws Exception {
                StorageRequest.signBlobQueueAndFileRequest(connection, client, 0, context);
            }

            @Override
            public Void preProcessResponse(CloudFile parentObject, CloudFileClient client, OperationContext context)
                    throws Exception {
                if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) {
                    this.setNonExceptionedRetryableFailure(true);
                    return null;
                }

                return null;
            }
        };

        return putRequest;
    }

    /**
     * Requests the service to start copying a blob's contents, properties, and metadata to a new file.
     *
     * @param sourceBlob
     *            A CloudBlob object that represents the source blob to copy.
     *
     * @return A String which represents the copy ID associated with the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException
     */
    @DoesServiceRequest
    public final String startCopy(final CloudBlob sourceBlob) throws StorageException, URISyntaxException {
        return this.startCopy(sourceBlob, null /* sourceAccessCondition */,
                null /* destinationAccessCondition */, null /* options */, null /* opContext */);
    }

    /**
     * Requests the service to start copying a file's contents, properties, and metadata to a new file,
     * using the specified access conditions, lease ID, request options, and operation context.
     *
     * @param sourceBlob
     *            A CloudBlob object that represents the source blob to copy.
     * @param sourceAccessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the source blob.
     * @param destinationAccessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the destination file.
     * @param options
     *            A {@link BlobRequestOptions} object that specifies any additional options for the request.
     *            Specifying null will use the default request options from the associated
     *            service client ({@link CloudBlobClient}).
     * @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 String which represents the copy ID associated with the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException
     *
     */
    @DoesServiceRequest
    public final String startCopy(final CloudBlob sourceBlob, final AccessCondition sourceAccessCondition,
            final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext)
            throws StorageException, URISyntaxException {
        Utility.assertNotNull("sourceBlob", sourceBlob);

        URI source = sourceBlob.getSnapshotQualifiedUri();
        if (sourceBlob.getServiceClient() != null && sourceBlob.getServiceClient().getCredentials() != null)
        {
            source = sourceBlob.getServiceClient().getCredentials().transformUri(sourceBlob.getSnapshotQualifiedUri());
        }

        return this.startCopy(source, sourceAccessCondition, destinationAccessCondition, options, opContext);
    }

    /**
     * Requests the service to start copying an Azure File's contents, properties, and metadata to a new Azure File.
     *
     * @param sourceFile
     *            A CloudFile object that represents the source Azure File to copy.
     *
     * @return A String which represents the copy ID associated with the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException
     */
    @DoesServiceRequest
    public final String startCopy(final CloudFile sourceFile) throws StorageException, URISyntaxException {
        return this.startCopy(sourceFile, null /* sourceAccessCondition */,
                null /* destinationAccessCondition */, null /* options */, null /* opContext */);
    }

    /**
     * Requests the service to start copying an Azure File's contents, properties, and metadata to a new Azure File,
     * using the specified access conditions, lease ID, request options, and operation context.
     *
     * @param sourceFile
     *            A CloudFile object that represents the source file to copy.
     * @param sourceAccessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the source.
     * @param destinationAccessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the destination.
     * @param options
     *            A {@link FileRequestOptions} object that specifies any additional options for the request.
     *            Specifying null will use the default request options from the associated
     *            service client ({@link CloudFileClient}).
     * @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 String which represents the copy ID associated with the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException
     *
     */
    @DoesServiceRequest
    public final String startCopy(final CloudFile sourceFile, final AccessCondition sourceAccessCondition,
            final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext)
            throws StorageException, URISyntaxException {
        Utility.assertNotNull("sourceFile", sourceFile);
        return this.startCopy(sourceFile.getTransformedAddress(opContext).getPrimaryUri(),
                sourceAccessCondition, destinationAccessCondition, options, opContext);

    }

    /**
     * Requests the service to start copying a URI's contents, properties, and metadata to a new Azure File.
     *
     * @param source
     *            The source's java.net.URI.
     *
     * @return A String which represents the copy ID associated with the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException 
     */
    @DoesServiceRequest
    public final String startCopy(final URI source) throws StorageException, URISyntaxException {
        return this.startCopy(source, null /* sourceAccessCondition */,
                null /* destinationAccessCondition */, null /* options */, null /* opContext */);
    }

    /**
     * Requests the service to start copying a URI's contents, properties, and metadata to a new Azure File,
     * using the specified access conditions, lease ID, request options, and operation context.
     *
     * @param source
     *            The source's java.net.URI.
     * @param sourceAccessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the source.
     * @param destinationAccessCondition
     *            An {@link AccessCondition} object that represents the access conditions for the destination.
     * @param options
     *            A {@link FileRequestOptions} object that specifies any additional options for the request.
     *            Specifying null will use the default request options from the associated
     *            service client ({@link CloudFileClient}).
     * @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 String which represents the copy ID associated with the copy operation.
     *
     * @throws StorageException
     *             If a storage service error occurred.
     * @throws URISyntaxException 
     *
     */
    @DoesServiceRequest
    public final String startCopy(final URI source, final AccessCondition sourceAccessCondition,
            final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext)
            throws StorageException, URISyntaxException {
        if (opContext == null) {
            opContext = new OperationContext();
        }

        this.getShare().assertNoSnapshot();

        opContext.initialize();
        options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);

        return ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
                this.startCopyImpl(source, sourceAccessCondition, destinationAccessCondition, options),
                options.getRetryPolicyFactory(), opContext);
    }

    private StorageRequest startCopyImpl(final URI source,
            final AccessCondition sourceAccessCondition, final AccessCondition destinationAccessCondition,
            final FileRequestOptions options) {

        if (sourceAccessCondition != null && !Utility.isNullOrEmpty(sourceAccessCondition.getLeaseID())) {
            throw new IllegalArgumentException(SR.LEASE_CONDITION_ON_SOURCE);
        }

        final StorageRequest putRequest =
                new StorageRequest(options, this.getStorageUri()) {

            @Override
            public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context)
                    throws Exception {
                return FileRequest.copyFrom(file.getTransformedAddress(context).getUri(this.getCurrentLocation()),
                        options, context, sourceAccessCondition, destinationAccessCondition, source.toASCIIString());
            }

            @Override
            public void setHeaders(HttpURLConnection connection, CloudFile file, OperationContext context) {
                FileRequest.addMetadata(connection, file.metadata, context);
            }

            @Override
            public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context)
                    throws Exception {
                StorageRequest.signBlobQueueAndFileRequest(connection, client, 0, context);
            }

            @Override
            public String preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context)
                    throws Exception {
                if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) {
                    this.setNonExceptionedRetryableFailure(true);
                    return null;
                }

                file.updateEtagAndLastModifiedFromResponse(this.getConnection());
                file.properties.setCopyState(FileResponse.getCopyState(this.getConnection()));

                return file.properties.getCopyState().getCopyId();
            }
        };

        return putRequest;
    }

    /**
     * Clears a range from a file.
     * 

* Calling clearRange releases the storage space used by the specified range. Ranges that have been * cleared are no longer tracked as part of the file. * * @param offset * The offset, in bytes, at which to begin clearing. * @param length * The length, in bytes, of the data range to be cleared. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void clearRange(final long offset, final long length) throws StorageException, URISyntaxException { this.clearRange(offset, length, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Clears a range from a file using the specified lease ID, request options, and operation context. *

* Calling clearRange releases the storage space used by the specified range. Ranges that have been * cleared are no longer tracked as part of the file. * * @param offset * A long which represents the offset, in bytes, at which to begin clearing. * @param length * A long which represents the length, in bytes, of the data range to be cleared. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void clearRange(final long offset, final long length, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); final FileRange range = new FileRange(offset, offset + length - 1); this.putRangeInternal(range, FileRangeOperationType.CLEAR, null, length, null, accessCondition, options, opContext); } /** * Creates a file. If the file already exists, this will replace it. * * @param size * A long which represents the size, in bytes, of the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void create(final long size) throws StorageException, URISyntaxException { this.create(size, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Creates a file using the specified access condition, request options and operation context. If the file already * exists, this will replace it. * * @param size * A long which represents the size, in bytes, of the file. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void create(final long size, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.createImpl(size, accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest createImpl(final long size, final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest putRequest = new StorageRequest(options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.putFile(file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, file.properties, size); } @Override public void setHeaders(HttpURLConnection connection, CloudFile file, OperationContext context) { FileRequest.addMetadata(connection, file.metadata, context); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context); } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); return null; } file.updateEtagAndLastModifiedFromResponse(this.getConnection()); this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection())); return null; } }; return putRequest; } /** * Deletes the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final void delete() throws StorageException, URISyntaxException { this.delete(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Deletes the file using the specified access condition, request options, and operation context. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final void delete(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.deleteImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext); } /** * Deletes the file if it exists. * * @return true if the file was deleted; otherwise, false. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException * */ @DoesServiceRequest public final boolean deleteIfExists() throws StorageException, URISyntaxException { return this.deleteIfExists(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Deletes the file if it exists, using the specified access condition, request options, and operation context. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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 true if the file existed and was deleted; otherwise, false * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final boolean deleteIfExists(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); this.getShare().assertNoSnapshot(); boolean exists = this.exists(true, accessCondition, options, opContext); if (exists) { try { this.delete(accessCondition, options, opContext); return true; } catch (StorageException e) { if (e.getHttpStatusCode() == HttpURLConnection.HTTP_NOT_FOUND && StorageErrorCodeStrings.RESOURCE_NOT_FOUND.equals(e.getErrorCode())) { return false; } else { throw e; } } } else { return false; } } private StorageRequest deleteImpl(final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest deleteRequest = new StorageRequest(options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.deleteFile(file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context); } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); return null; } return null; } }; return deleteRequest; } /** * Downloads the contents of a file to a stream. * * @param outStream * An {@link OutputStream} object that represents the target stream. * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final void download(final OutputStream outStream) throws StorageException { this.download(outStream, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Downloads the contents of a file to a stream using the specified request options and operation context. * * @param outStream * An OutputStream object that represents the target stream. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final void download(final OutputStream outStream, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.downloadToStreamImpl( null /* fileOffset */, null /* length */, outStream, accessCondition, options, opContext), options .getRetryPolicyFactory(), opContext); } /** * Downloads the contents of a file to a stream. * * @param offset * A long which represents the offset to use as the starting point for the source. * @param length * A Long which represents the number of bytes to read or null. * @param outStream * An {@link OutputStream} object that represents the target stream. * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final void downloadRange(final long offset, final Long length, final OutputStream outStream) throws StorageException { this.downloadRange(offset, length, outStream, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Downloads the contents of a file to a stream using the specified request options and operation context. * * @param offset * A long which represents the offset to use as the starting point for the source. * @param length * A Long which represents the number of bytes to read or null. * @param outStream * An {@link OutputStream} object that represents the target stream. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final void downloadRange(final long offset, final Long length, final OutputStream outStream, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (offset < 0 || (length != null && length <= 0)) { throw new IndexOutOfBoundsException(); } if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.downloadToStreamImpl(offset, length, outStream, accessCondition, options, opContext), options.getRetryPolicyFactory(), opContext); } /** * Downloads a range of bytes from the file to the given byte buffer. * * @param fileOffset * A long which represents the offset within the file to begin downloading. * @param length * A Long which represents the number of bytes to read. * @param buffer * A byte array which represents the buffer to write to. * @param bufferOffset * An int which represents the offset in the byte buffer to begin writing. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. * @param opContext * An {@link OperationContext} object used to track the execution of the operation. * @throws StorageException * an exception representing any error which occurred during the operation. */ @DoesServiceRequest protected final int downloadRangeInternal(final long fileOffset, final Long length, final byte[] buffer, final int bufferOffset, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (bufferOffset < 0 || fileOffset < 0 || (length != null && length <= 0)) { throw new IndexOutOfBoundsException(); } if (opContext == null) { opContext = new OperationContext(); } options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); WrappedByteArrayOutputStream outputStream = new WrappedByteArrayOutputStream(buffer, bufferOffset); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.downloadToStreamImpl(fileOffset, length, outputStream, accessCondition, options, opContext), options.getRetryPolicyFactory(), opContext); return outputStream.getPosition(); } /** * Downloads a range of bytes from the file to the given byte buffer. * * @param offset * A long which represents the byte offset to use as the starting point for the source. * @param length * A Long which represents the number of bytes to read or null. * @param buffer * A byte array which represents the buffer to which the file bytes are downloaded. * @param bufferOffset * An int which represents the byte offset to use as the starting point for the target. * * @throws StorageException */ @DoesServiceRequest public final int downloadRangeToByteArray(final long offset, final Long length, final byte[] buffer, final int bufferOffset) throws StorageException { return this.downloadRangeToByteArray(offset, length, buffer, bufferOffset, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Downloads a range of bytes from the file to the given byte buffer, using the specified request options and * operation context. * * @param offset * A long which represents the byte offset to use as the starting point for the source. * @param length * A Long which represents the number of bytes to read or null. * @param buffer * A byte array which represents the buffer to which the file bytes are downloaded. * @param bufferOffset * An int which represents the byte offset to use as the starting point for the target. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final int downloadRangeToByteArray(final long offset, final Long length, final byte[] buffer, final int bufferOffset, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { Utility.assertNotNull("buffer", buffer); if (length != null) { if (length + bufferOffset > buffer.length) { throw new IndexOutOfBoundsException(); } } if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); return this.downloadRangeInternal(offset, length, buffer, bufferOffset, accessCondition, options, opContext); } /** * Downloads a range of bytes from the file to the given byte buffer. * * @param buffer * A byte array which represents the buffer to which the file bytes are downloaded. * @param bufferOffset * An int which represents the byte offset to use as the starting point for the target. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final int downloadToByteArray(final byte[] buffer, final int bufferOffset) throws StorageException { return this .downloadToByteArray(buffer, bufferOffset, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Downloads a range of bytes from the file to the given byte buffer, using the specified request options and * operation context. * * @param buffer * A byte array which represents the buffer to which the file bytes are downloaded. * @param bufferOffset * A long which represents the byte offset to use as the starting point for the target. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final int downloadToByteArray(final byte[] buffer, final int bufferOffset, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { Utility.assertNotNull("buffer", buffer); if (bufferOffset < 0) { throw new IndexOutOfBoundsException(); } if (bufferOffset >= buffer.length) { throw new IndexOutOfBoundsException(); } if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); WrappedByteArrayOutputStream outputStream = new WrappedByteArrayOutputStream(buffer, bufferOffset); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.downloadToStreamImpl(null, null, outputStream, accessCondition, options, opContext), options.getRetryPolicyFactory(), opContext); return outputStream.getPosition(); } /** * Downloads a file. * * @param path * A String which represents the path to the file that will be created. * * @throws StorageException * If a storage service error occurred. * @throws IOException */ public void downloadToFile(final String path) throws StorageException, IOException { downloadToFile(path, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Downloads a file. * * @param path * A String which represents the path to the file that will be created. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws IOException */ public void downloadToFile(final String path, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException { OutputStream outputStream = new BufferedOutputStream(new java.io.FileOutputStream(path)); try { this.download(outputStream, accessCondition, options, opContext); outputStream.close(); } catch (StorageException e) { deleteEmptyFileOnException(outputStream, path); throw e; } catch (IOException e) { deleteEmptyFileOnException(outputStream, path); throw e; } } /** * Helper to delete an empty file in the case of an exception * * @param outputStream * @param path * @throws IOException */ private void deleteEmptyFileOnException(OutputStream outputStream, String path) { try { outputStream.close(); File fileToDelete = new File(path); fileToDelete.delete(); } catch (Exception e) { // Best effort delete. } } /** * Downloads a file to a string using the platform's default encoding. * * @return A String which represents the file's contents. * * @throws StorageException * If a storage service error occurred. * @throws IOException */ public String downloadText() throws StorageException, IOException { return this .downloadText(null /* charsetName */, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Downloads a file to a string using the specified encoding. * * @param charsetName * A String which represents the name of the charset to use to encode the content. * If null, the platform's default encoding is used. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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 String which represents the file's contents. * * @throws StorageException * If a storage service error occurred. * @throws IOException */ public String downloadText(final String charsetName, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.download(baos, accessCondition, options, opContext); return charsetName == null ? baos.toString() : baos.toString(charsetName); } /** * Returns a collection of file ranges and their starting and ending byte offsets. *

* The start and end byte offsets for each file range are inclusive. * * @return An ArrayList object which represents the set of file ranges and their starting and ending * byte offsets. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public ArrayList downloadFileRanges() throws StorageException { return this.downloadFileRanges(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Returns a collection of file ranges and their starting and ending byte offsets using the specified request * options and operation context. * * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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 An ArrayList object which represents the set of file ranges and their starting * and ending byte offsets. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public ArrayList downloadFileRanges(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); return ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.downloadFileRangesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest> downloadFileRangesImpl( final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest> getRequest = new StorageRequest>(options, this.getStorageUri()) { @Override public void setRequestLocationMode() { this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY); } @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.getFileRanges(file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, file.getShare().snapshotID); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context); } @Override public ArrayList preProcessResponse(CloudFile parentObject, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); } return null; } @Override public ArrayList postProcessResponse(HttpURLConnection connection, CloudFile file, CloudFileClient client, OperationContext context, ArrayList storageObject) throws Exception { file.updateEtagAndLastModifiedFromResponse(this.getConnection()); file.updateLengthFromResponse(this.getConnection()); return FileRangeHandler.getFileRanges(this.getConnection().getInputStream()); } }; return getRequest; } @DoesServiceRequest private final StorageRequest downloadToStreamImpl(final Long fileOffset, final Long length, final OutputStream outStream, final AccessCondition accessCondition, final FileRequestOptions options, OperationContext opContext) { final long startingOffset = fileOffset == null ? 0 : fileOffset; final StorageRequest getRequest = new StorageRequest( options, this.getStorageUri()) { @Override public void setRequestLocationMode() { this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY); } @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { // The first time this is called, we have to set the length and offset. // On retries, these will already have values and need not be called. if (this.getOffset() == null) { this.setOffset(fileOffset); } if (this.getLength() == null) { this.setLength(length); } // Only do this when we have support from the service. // AccessCondition tempCondition = (this.getETagLockCondition() != null) ? this.getETagLockCondition() // : accessCondition; return FileRequest.getFile(file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, file.getShare().snapshotID, this.getOffset(), this.getLength(), (options.getUseTransactionalContentMD5() && !this.getArePropertiesPopulated())); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context); } @Override public Integer preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_PARTIAL && this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); return null; } if (!this.getArePropertiesPopulated()) { final FileAttributes retrievedAttributes = FileResponse.getFileAttributes(this.getConnection(), file.getStorageUri()); file.properties = retrievedAttributes.getProperties(); file.metadata = retrievedAttributes.getMetadata(); // Need to store the Content MD5 in case we fail part way through. // We would still need to verify the entire range. this.setContentMD5(this.getConnection().getHeaderField(Constants.HeaderConstants.CONTENT_MD5)); if (!options.getDisableContentMD5Validation() && options.getUseTransactionalContentMD5() && Utility.isNullOrEmpty(this.getContentMD5())) { throw new StorageException(StorageErrorCodeStrings.MISSING_MD5_HEADER, SR.MISSING_MD5, Constants.HeaderConstants.HTTP_UNUSED_306, null, null); } this.setLockedETag(file.properties.getEtag()); this.setArePropertiesPopulated(true); } else { if (this.getLockedETag() != null) { if (!this.getLockedETag().equals(file.properties.getEtag())) { throw new StorageException(StorageErrorCode.CONDITION_FAILED.toString(), SR.INVALID_CONDITIONAL_HEADERS, HttpURLConnection.HTTP_PRECON_FAILED, null, null); } } } // If the download fails and we need to resume the download, going to the // same storage location is important to prevent a possible ETag mismatch. this.setRequestLocationMode((this.getResult().getTargetLocation() == StorageLocation.PRIMARY) ? RequestLocationMode.PRIMARY_ONLY : RequestLocationMode.SECONDARY_ONLY); return null; } @Override public Integer postProcessResponse(HttpURLConnection connection, CloudFile file, CloudFileClient client, OperationContext context, Integer storageObject) throws Exception { final Boolean validateMD5 = !options.getDisableContentMD5Validation() && !Utility.isNullOrEmpty(this.getContentMD5()); final String contentLength = connection.getHeaderField(Constants.HeaderConstants.CONTENT_LENGTH); final long expectedLength = Long.parseLong(contentLength); Logger.info(context, String.format(SR.CREATING_NETWORK_STREAM, expectedLength)); final NetworkInputStream streamRef = new NetworkInputStream(connection.getInputStream(), expectedLength); try { // writeToOutputStream will update the currentRequestByteCount on this request in case a retry // is needed and download should resume from that point final StreamMd5AndLength descriptor = Utility.writeToOutputStream(streamRef, outStream, -1, false, validateMD5, context, options, true, this, this.getCurrentDescriptor()); // length was already checked by the NetworkInputStream, now check Md5 if (validateMD5 && !this.getContentMD5().equals(descriptor.getMd5())) { throw new StorageException(StorageErrorCodeStrings.INVALID_MD5, String.format( SR.FILE_HASH_MISMATCH, this.getContentMD5(), descriptor.getMd5()), Constants.HeaderConstants.HTTP_UNUSED_306, null, null); } } finally { // Close the stream and return. Closing an already closed stream is harmless. So its fine to try // to drain the response and close the stream again in the executor. streamRef.close(); } return null; } @Override public void recoveryAction(OperationContext context) throws IOException { if (this.getETagLockCondition() == null && (!Utility.isNullOrEmpty(this.getLockedETag()))) { AccessCondition etagLockCondition = new AccessCondition(); etagLockCondition.setIfMatch(this.getLockedETag()); if (accessCondition != null) { etagLockCondition.setLeaseID(accessCondition.getLeaseID()); } this.setETagLockCondition(etagLockCondition); } if (this.getCurrentRequestByteCount() > 0) { this.setOffset(startingOffset + this.getCurrentRequestByteCount()); if (length != null) { this.setLength(length - this.getCurrentRequestByteCount()); } } } }; return getRequest; } /** * Populates a file's properties and metadata. *

* This method populates the file's system properties and user-defined metadata. Before reading or modifying * a file's properties or metadata, call this method or its overload to retrieve the latest values for the * file's properties and metadata from the Microsoft Azure storage service. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final void downloadAttributes() throws StorageException { this.downloadAttributes(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Populates a file's properties and metadata using the specified request options and operation context. *

* This method populates the file's system properties and user-defined metadata. Before reading or modifying * a file's properties or metadata, call this method or its overload to retrieve the latest values for * the file's properties and metadata from the Microsoft Azure storage service. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final void downloadAttributes(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.downloadAttributesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest downloadAttributesImpl( final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest getRequest = new StorageRequest(options, this.getStorageUri()) { @Override public void setRequestLocationMode() { this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY); } @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.getFileProperties( file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, file.getShare().snapshotID); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context); } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); return null; } // Set attributes final FileAttributes retrievedAttributes = FileResponse.getFileAttributes(this.getConnection(), file.getStorageUri()); file.properties = retrievedAttributes.getProperties(); file.metadata = retrievedAttributes.getMetadata(); return null; } }; return getRequest; } /** * Checks to see if the file exists. * * @return true if the file exists, otherwise false. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final boolean exists() throws StorageException { return this.exists(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Checks to see if the file exists, using the specified access condition, request options and operation context. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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 true if the file exists, otherwise false. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final boolean exists(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { return this.exists(false /* primaryOnly */, accessCondition, options, opContext); } @DoesServiceRequest private final boolean exists(final boolean primaryOnly, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); return ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.existsImpl(primaryOnly, accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest existsImpl(final boolean primaryOnly, final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest getRequest = new StorageRequest(options, this.getStorageUri()) { @Override public void setRequestLocationMode() { this.setRequestLocationMode(primaryOnly ? RequestLocationMode.PRIMARY_ONLY : RequestLocationMode.PRIMARY_OR_SECONDARY); } @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.getFileProperties( file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, file.getShare().snapshotID); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context); } @Override public Boolean preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) { final FileAttributes retrievedAttributes = FileResponse.getFileAttributes(this.getConnection(), file.getStorageUri()); file.properties = retrievedAttributes.getProperties(); file.metadata = retrievedAttributes.getMetadata(); return Boolean.valueOf(true); } else if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND) { return Boolean.valueOf(false); } else { this.setNonExceptionedRetryableFailure(true); // return false instead of null to avoid SCA issues return false; } } }; return getRequest; } /** * Returns a shared access signature for the file using the specified group policy identifier and * shared access file headers. Note this does not contain the leading "?". * * @param policy * A {@link SharedAccessFilePolicy} object that represents the access policy for the shared * access signature. * @param groupPolicyIdentifier * A String that represents the share-level access policy. * * @return A String that represents the shared access signature. * * @throws InvalidKeyException * If the credentials are invalid. * @throws StorageException * If a storage service error occurred. */ public String generateSharedAccessSignature(final SharedAccessFilePolicy policy, final String groupPolicyIdentifier) throws InvalidKeyException, StorageException { return generateSharedAccessSignature(policy, null /* headers */, groupPolicyIdentifier); } /** * Returns a shared access signature for the file using the specified group policy identifier and * shared access file headers. Note this does not contain the leading "?". * * @param policy * A {@link SharedAccessFilePolicy} object that represents the access policy for the shared * access signature. * @param headers * A {@link SharedAccessFileHeaders} object that represents the optional header values to * set for a file accessed with this shared access signature. * @param groupPolicyIdentifier * A String that represents the share-level access policy. * * @return A String that represents the shared access signature. * * @throws IllegalArgumentException * If the credentials are invalid. * @throws InvalidKeyException * If the credentials are invalid. * @throws StorageException * If a storage service error occurred. */ public String generateSharedAccessSignature( final SharedAccessFilePolicy policy, final SharedAccessFileHeaders headers, final String groupPolicyIdentifier) throws InvalidKeyException, StorageException { return this.generateSharedAccessSignature(policy, headers, groupPolicyIdentifier, null /* IP range */, null /* protocols */); } /** * Returns a shared access signature for the file using the specified group policy identifier and * shared access file headers. Note this does not contain the leading "?". * * @param policy * A {@link SharedAccessFilePolicy} object that represents the access policy for the shared * access signature. * @param headers * A {@link SharedAccessFileHeaders} object that represents the optional header values to * set for a file accessed with this shared access signature. * @param groupPolicyIdentifier * A String that represents the share-level access policy. * @param ipRange * A {@link IPRange} object containing the range of allowed IP addresses. * @param protocols * A {@link SharedAccessProtocols} representing the allowed Internet protocols. * * @return A String that represents the shared access signature. * * @throws IllegalArgumentException * If the credentials are invalid. * @throws InvalidKeyException * If the credentials are invalid. * @throws StorageException * If a storage service error occurred. */ public String generateSharedAccessSignature( final SharedAccessFilePolicy policy, final SharedAccessFileHeaders headers, final String groupPolicyIdentifier, final IPRange ipRange, final SharedAccessProtocols protocols) throws InvalidKeyException, StorageException { if (!StorageCredentialsHelper.canCredentialsSignRequest(this.fileServiceClient.getCredentials())) { throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY); } final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlobAndFile( policy, headers, groupPolicyIdentifier, this.getCanonicalName(), ipRange, protocols, this.fileServiceClient); final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlobAndFile( policy, headers, groupPolicyIdentifier, "f", ipRange, protocols, signature); return builder.toString(); } /** * Returns the canonical name of the file in the format of * /<service-name>/<account-name>/<share-name>/<file-name>. *

* This format is used for Shared Access operations. * * @return The canonical name in the format of /<service-name>/<account-name> * /<share-name>/<file-name>. */ String getCanonicalName() { StringBuilder canonicalName = new StringBuilder("/"); canonicalName.append(SR.FILE); String rawPath = this.getUri().getRawPath(); if (this.fileServiceClient.isUsePathStyleUris()) { canonicalName.append(rawPath); } else { canonicalName.append(PathUtility.getCanonicalPathFromCredentials( this.getServiceClient().getCredentials(), rawPath)); } return canonicalName.toString(); } /** * Returns the Azure File's copy state. * * @return A {@link CopyState} object that represents the copy state of the file. */ public CopyState getCopyState() { return this.properties.getCopyState(); } /** * Opens a file input stream to download the file. *

* Use {@link CloudFile#setStreamMinimumReadSizeInBytes(int)} to configure the read size. * * @return An InputStream object that represents the stream to use for reading from the file. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final FileInputStream openRead() throws StorageException { return this.openRead(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Opens a file input stream to download the file using the specified request options and * operation context. *

* Use {@link #setStreamMinimumReadSizeInBytes(int)} to configure the read size. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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 An InputStream object that represents the stream to use for reading from the file. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest public final FileInputStream openRead(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient, false /* setStartTime */); return new FileInputStream(this, accessCondition, options, opContext); } /** * Opens an output stream object to write data to the file. The file must already exist and any existing data may * be overwritten. * * @return A {@link FileOutputStream} object used to write data to the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public FileOutputStream openWriteExisting() throws StorageException, URISyntaxException { return this .openOutputStreamInternal(null /* length */, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Opens an output stream object to write data to the file, using specified request options and * operation context. The file must already exist and any existing data may be overwritten. * * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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 {@link FileOutputStream} object used to write data to the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public FileOutputStream openWriteExisting(AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { return this.openOutputStreamInternal(null /* length */, accessCondition, options, opContext); } /** * Opens an output stream object to write data to the file. The file does not yet exist and will * be created with the length specified. If the file already exists on the service, it will be overwritten. *

* To avoid overwriting and instead throw an error, please use the * {@link #openWriteNew(long, AccessCondition, FileRequestOptions, OperationContext)} overload with the appropriate * {@link AccessCondition}. * * @param length * A long which represents the length, in bytes, of the stream to create. * * @return A {@link FileOutputStream} object used to write data to the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public FileOutputStream openWriteNew(final long length) throws StorageException, URISyntaxException { return this .openOutputStreamInternal(length, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Opens an output stream object to write data to the file, using the specified lease ID, request options and * operation context. The file does not need to yet exist and will be created with the length specified. If the file * already exists on the service, it will be overwritten. *

* To avoid overwriting and instead throw an error, please pass in an {@link AccessCondition} generated using * {@link AccessCondition#generateIfNotExistsCondition()}. * * @param length * A long which represents the length, in bytes, of the stream to create. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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 {@link FileOutputStream} object used to write data to the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public FileOutputStream openWriteNew(final long length, AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { return openOutputStreamInternal(length, accessCondition, options, opContext); } /** * Opens an output stream object to write data to the file, using the specified lease ID, request options and * operation context. If the length is specified, a new file will be created with the length specified. * Otherwise, the file must already exist and a stream of its current length will be opened. * * @param length * A long which represents the length, in bytes, of the stream to create. This value must be * null if the file already exists. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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 {@link FileOutputStream} object used to write data to the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ private FileOutputStream openOutputStreamInternal(Long length, AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient, false /* setStartTime */); if (length != null) { this.create(length, accessCondition, options, opContext); } else { if (options.getStoreFileContentMD5()) { throw new IllegalArgumentException(SR.FILE_MD5_NOT_POSSIBLE); } this.downloadAttributes(accessCondition, options, opContext); length = this.getProperties().getLength(); } if (accessCondition != null) { accessCondition = AccessCondition.generateLeaseCondition(accessCondition.getLeaseID()); } return new FileOutputStream(this, length, accessCondition, options, opContext); } /** * Uploads a file from data in a byte array. If the file already exists on the service, it will be overwritten. * * @param buffer * A byte array which represents the data to write to the file. * @param offset * A int which represents the offset of the byte array from which to start the data upload. * @param length * An int which represents the number of bytes to upload from the input buffer. * * @throws StorageException * If a storage service error occurred. * @throws IOException * @throws URISyntaxException */ public void uploadFromByteArray(final byte[] buffer, final int offset, final int length) throws StorageException, IOException, URISyntaxException { uploadFromByteArray(buffer, offset, length, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Uploads a file from data in a byte array. If the file already exists on the service, it will be overwritten. * * @param buffer * A byte array which represents the data to write to the file. * @param offset * A int which represents the offset of the byte array from which to start the data upload. * @param length * An int which represents the number of bytes to upload from the input buffer. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws IOException * @throws URISyntaxException */ public void uploadFromByteArray(final byte[] buffer, final int offset, final int length, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException, URISyntaxException { ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer, offset, length); this.upload(inputStream, length, accessCondition, options, opContext); inputStream.close(); } /** * Uploads a local file. If the file already exists on the service, it will be overwritten. * * @param path * A String which represents the path to the file to be uploaded. * * @throws StorageException * If a storage service error occurred. * @throws IOException * @throws URISyntaxException */ public void uploadFromFile(final String path) throws StorageException, IOException, URISyntaxException { uploadFromFile(path, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Uploads a file from a local file. If the file already exists on the service, it will be overwritten. * * @param path * A String which represents the path to the file to be uploaded. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws IOException * @throws URISyntaxException */ public void uploadFromFile(final String path, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException, URISyntaxException { File file = new File(path); long fileLength = file.length(); InputStream inputStream = new BufferedInputStream(new java.io.FileInputStream(file)); this.upload(inputStream, fileLength, accessCondition, options, opContext); inputStream.close(); } /** * Uploads a file from a string using the platform's default encoding. If the file already exists on the service, it * will be overwritten. * * @param content * A String which represents the content that will be uploaded to the file. * * @throws StorageException * If a storage service error occurred. * @throws IOException * @throws URISyntaxException */ public void uploadText(final String content) throws StorageException, IOException, URISyntaxException { this.uploadText(content, null /* charsetName */, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Uploads a file from a string using the specified encoding. If the file already exists on the service, it will be * overwritten. * * @param content * A String which represents the content that will be uploaded to the file. * @param charsetName * A String which represents the name of the charset to use to encode the content. * If null, the platform's default encoding is used. * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws IOException * @throws URISyntaxException */ public void uploadText(final String content, final String charsetName, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException, URISyntaxException { byte[] bytes = (charsetName == null) ? content.getBytes() : content.getBytes(charsetName); this.uploadFromByteArray(bytes, 0, bytes.length, accessCondition, options, opContext); } /** * Uploads a range to a file. * * @param sourceStream * An {@link InputStream} object which represents the input stream to write to the file. * @param offset * A long which represents the offset, in number of bytes, at which to begin writing the * data. * @param length * A long which represents the length, in bytes, of the data to write. * * @throws IOException * If an I/O exception occurred. * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void uploadRange(final InputStream sourceStream, final long offset, final long length) throws StorageException, IOException, URISyntaxException { this.uploadRange(sourceStream, offset, length, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Uploads a range to a file using the specified lease ID, request options, and operation context. * * @param sourceStream * An {@link InputStream} object which represents the input stream to write to the file. * @param offset * A long which represents the offset, in number of bytes, at which to begin writing the * data. * @param length * A long which represents the length, in bytes, of the data to write. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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. * * @throws IOException * If an I/O exception occurred. * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void uploadRange(final InputStream sourceStream, final long offset, final long length, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); final FileRange range = new FileRange(offset, offset + length - 1); final byte[] data = new byte[(int) length]; String md5 = null; int count = 0; int total = 0; while (total < length) { count = sourceStream.read(data, total, (int) Math.min(length - total, Integer.MAX_VALUE)); total += count; } if (options.getUseTransactionalContentMD5()) { try { final MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(data, 0, data.length); md5 = Base64.encode(digest.digest()); } catch (final NoSuchAlgorithmException e) { // This wont happen, throw fatal. throw Utility.generateNewUnexpectedStorageException(e); } } this.putRangeInternal(range, FileRangeOperationType.UPDATE, data, length, md5, accessCondition, options, opContext); } /** * Used for both uploadRange and clearRange. * * @param range * A {@link FileRange} object that specifies the file range. * @param operationType * A {@link FileRangeOperationType} enumeration value that specifies the operation type. * @param data * A byte array which represents the data to write. * @param length * A long which represents the number of bytes to write. * @param md5 * A String which represents the MD5 hash for the data. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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. * * @throws StorageException * If a storage service error occurred. */ @DoesServiceRequest private void putRangeInternal(final FileRange range, final FileRangeOperationType operationType, final byte[] data, final long length, final String md5, final AccessCondition accessCondition, final FileRequestOptions options, final OperationContext opContext) throws StorageException { ExecutionEngine.executeWithRetry(this.fileServiceClient, this, putRangeImpl(range, operationType, data, length, md5, accessCondition, options, opContext), options.getRetryPolicyFactory(), opContext); } private StorageRequest putRangeImpl(final FileRange range, final FileRangeOperationType operationType, final byte[] data, final long length, final String md5, final AccessCondition accessCondition, final FileRequestOptions options, final OperationContext opContext) { final StorageRequest putRequest = new StorageRequest(options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { if (operationType == FileRangeOperationType.UPDATE) { this.setSendStream(new ByteArrayInputStream(data)); this.setLength(length); } return FileRequest.putRange(file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, opContext, accessCondition, range, operationType); } @Override public void setHeaders(HttpURLConnection connection, CloudFile file, OperationContext context) { if (operationType == FileRangeOperationType.UPDATE) { if (options.getUseTransactionalContentMD5()) { connection.setRequestProperty(Constants.HeaderConstants.CONTENT_MD5, md5); } } } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { if (operationType == FileRangeOperationType.UPDATE) { StorageRequest.signBlobQueueAndFileRequest(connection, client, length, context); } else { StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context); } } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); return null; } file.updateEtagAndLastModifiedFromResponse(this.getConnection()); this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection())); return null; } }; return putRequest; } /** * Uploads the file's metadata to the storage service. *

* Use {@link CloudFile#downloadAttributes} to retrieve the latest values for the file's properties and metadata * from the Microsoft Azure storage service. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final void uploadMetadata() throws StorageException, URISyntaxException { this.uploadMetadata(null /* accessCondition */, null /* options */, null /* opContext */); } /** * Uploads the file's metadata to the storage service using the access condition, request options, and operation * context. *

* Use {@link CloudFile#downloadAttributes} to retrieve the latest values for the file's properties and metadata * from the Microsoft Azure storage service. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final void uploadMetadata(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.uploadMetadataImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest uploadMetadataImpl(final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest putRequest = new StorageRequest( options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.setFileMetadata( file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition); } @Override public void setHeaders(HttpURLConnection connection, CloudFile file, OperationContext context) { FileRequest.addMetadata(connection, file.metadata, context); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context); } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); return null; } file.updateEtagAndLastModifiedFromResponse(this.getConnection()); this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection())); return null; } }; return putRequest; } /** * Updates the file's properties to the storage service. *

* Use {@link CloudFile#downloadAttributes} to retrieve the latest values for the file's properties and metadata * from the Microsoft Azure storage service. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final void uploadProperties() throws StorageException, URISyntaxException { this.uploadProperties(null /* accessCondition */, null /* options */, null /*opContext */); } /** * Updates the file's properties using the access condition, request options, and operation context. *

* Use {@link CloudFile#downloadAttributes} to retrieve the latest values for the file's properties and metadata * from the Microsoft Azure storage service. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @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. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public final void uploadProperties(final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.uploadPropertiesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest uploadPropertiesImpl( final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest putRequest = new StorageRequest(options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.setFileProperties( file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, file.properties); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context); } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); return null; } file.updateEtagAndLastModifiedFromResponse(this.getConnection()); this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection())); return null; } }; return putRequest; } /** * Resizes the file to the specified size. * * @param size * A long which represents the size of the file, in bytes. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ public void resize(long size) throws StorageException, URISyntaxException { this.resize(size, null /* accessCondition */, null /* options */, null /* operationContext */); } /** * Resizes the file to the specified size. * * @param size * A long which represents the size of the file, in bytes. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ public void resize(long size, AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); opContext.initialize(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.resizeImpl(size, accessCondition, options), options.getRetryPolicyFactory(), opContext); } private StorageRequest resizeImpl(final long size, final AccessCondition accessCondition, final FileRequestOptions options) { final StorageRequest putRequest = new StorageRequest(options, this.getStorageUri()) { @Override public HttpURLConnection buildRequest(CloudFileClient client, CloudFile file, OperationContext context) throws Exception { return FileRequest.resize(file.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, accessCondition, size); } @Override public void signRequest(HttpURLConnection connection, CloudFileClient client, OperationContext context) throws Exception { StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context); } @Override public Void preProcessResponse(CloudFile file, CloudFileClient client, OperationContext context) throws Exception { if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); return null; } file.getProperties().setLength(size); file.updateEtagAndLastModifiedFromResponse(this.getConnection()); this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection())); return null; } }; return putRequest; } /** * Uploads the source stream data to the file. If the file already exists on the service, it will be overwritten. * * @param sourceStream * An {@link InputStream} object to read from. * @param length * A long which represents the length, in bytes, of the stream data. Must be non zero. * * @throws IOException * If an I/O exception occurred. * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void upload(final InputStream sourceStream, final long length) throws StorageException, IOException, URISyntaxException { this.upload(sourceStream, length, null /* accessCondition */, null /* options */, null /* opContext */); } /** * Uploads the source stream data to the file using the specified access condition, request options, and operation * context. If the file already exists on the service, it will be overwritten. * * @param sourceStream * An {@link InputStream} object to read from. * @param length * A long which represents the length, in bytes, of the stream data. This must be greater than * or equal to zero. * @param accessCondition * An {@link AccessCondition} object which represents the access conditions for the file. * @param options * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying * null will use the default request options from the associated service client ( * {@link CloudFileClient}). * @param opContext * An {@link OperationContext} object which 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. * * @throws IOException * If an I/O exception occurred. * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ @DoesServiceRequest public void upload(final InputStream sourceStream, final long length, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException, IOException, URISyntaxException { if (opContext == null) { opContext = new OperationContext(); } this.getShare().assertNoSnapshot(); options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient); if (length < 0) { throw new IllegalArgumentException(SR.INVALID_FILE_LENGTH); } if (sourceStream.markSupported()) { // Mark sourceStream for current position. sourceStream.mark(Constants.MAX_MARK_LENGTH); } final FileOutputStream streamRef = this.openWriteNew(length, accessCondition, options, opContext); try { streamRef.write(sourceStream, length); } finally { streamRef.close(); } } /** * Retrieves the parent name for a file URI. * * @param resourceAddress * A {@link StorageUri} object which represents the resource URI. * @param delimiter * A String which specifies the directory delimiter to use. * @param usePathStyleUris * A Boolean which specifies whether path style URIs are used. * @param share * A {@link CloudFileShare} object which represents the file share. * * @return A String which represents the parent address for a file URI. * * @throws URISyntaxException */ protected static String getParentNameFromURI(final StorageUri resourceAddress, final CloudFileShare share) throws URISyntaxException { Utility.assertNotNull("resourceAddress", resourceAddress); Utility.assertNotNull("share", share); String delimiter = "/"; String shareName = share.getName() + delimiter; String relativeURIString = Utility.safeRelativize(share.getStorageUri().getPrimaryUri(), resourceAddress.getPrimaryUri()); if (relativeURIString.endsWith(delimiter)) { relativeURIString = relativeURIString.substring(0, relativeURIString.length() - delimiter.length()); } String parentName; if (Utility.isNullOrEmpty(relativeURIString)) { // Case 1 /[Delimiter]*? => / // Parent of share is share itself parentName = null; } else { final int lastDelimiterDex = relativeURIString.lastIndexOf(delimiter); if (lastDelimiterDex < 0) { // Case 2 // // Parent of a Directory is Share parentName = ""; } else { // Case 3 ///[/]* // Parent of CloudFile is CloudFileDirectory parentName = relativeURIString.substring(0, lastDelimiterDex); if (parentName != null && parentName.equals(shareName)) { parentName = ""; } } } return parentName; } /** * Verifies the passed in URI. Then parses it and uses its components to populate this resource's properties. * * @param completeUri * A {@link StorageUri} object which represents the complete URI. * @param credentials * A {@link StorageCredentials} object used to authenticate access. * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException */ private void parseQueryAndVerify(final StorageUri completeUri, final StorageCredentials credentials) throws StorageException, URISyntaxException { Utility.assertNotNull("completeUri", completeUri); if (!completeUri.isAbsolute()) { throw new IllegalArgumentException(String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString())); } this.storageUri = PathUtility.stripURIQueryAndFragment(completeUri); final StorageCredentialsSharedAccessSignature parsedCredentials = SharedAccessSignatureHelper.parseQuery(completeUri); if (credentials != null && parsedCredentials != null) { throw new IllegalArgumentException(SR.MULTIPLE_CREDENTIALS_PROVIDED); } try { final boolean usePathStyleUris = Utility.determinePathStyleFromUri(this.storageUri.getPrimaryUri()); this.fileServiceClient = new CloudFileClient(PathUtility.getServiceClientBaseAddress( this.getStorageUri(), usePathStyleUris), credentials != null ? credentials : parsedCredentials); this.name = PathUtility.getFileNameFromURI(this.storageUri.getPrimaryUri(), usePathStyleUris); } catch (final URISyntaxException e) { throw Utility.generateNewUnexpectedStorageException(e); } final HashMap queryParameters = PathUtility.parseQueryString(completeUri.getQuery()); final String[] snapshotIDs = queryParameters.get(Constants.QueryConstants.SHARE_SNAPSHOT); if (snapshotIDs != null && snapshotIDs.length > 0) { this.getShare().snapshotID = snapshotIDs[0]; } } protected void updateEtagAndLastModifiedFromResponse(HttpURLConnection request) { // ETag this.getProperties().setEtag(request.getHeaderField(Constants.HeaderConstants.ETAG)); // Last Modified if (0 != request.getLastModified()) { final Calendar lastModifiedCalendar = Calendar.getInstance(Utility.LOCALE_US); lastModifiedCalendar.setTimeZone(Utility.UTC_ZONE); lastModifiedCalendar.setTime(new Date(request.getLastModified())); this.getProperties().setLastModified(lastModifiedCalendar.getTime()); } } protected void updateLengthFromResponse(HttpURLConnection request) { final String xContentLengthHeader = request.getHeaderField(FileConstants.CONTENT_LENGTH_HEADER); if (!Utility.isNullOrEmpty(xContentLengthHeader)) { this.getProperties().setLength(Long.parseLong(xContentLengthHeader)); } } /** * Returns the file's share. * * @return A {@link CloudFileShare} object that represents the share of the file. * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException * If the resource URI is invalid. */ @Override public final CloudFileShare getShare() throws StorageException, URISyntaxException { if (this.share == null) { final StorageUri shareUri = PathUtility.getShareURI(this.getStorageUri(), this.fileServiceClient.isUsePathStyleUris()); this.share = new CloudFileShare(shareUri, this.fileServiceClient.getCredentials()/*, null*/); } return this.share; } /** * Returns the metadata for the file. * * @return A java.util.HashMap object that represents the metadata for the file. */ public final HashMap getMetadata() { return this.metadata; } /** * Returns the name of the file. * * @return A String that represents the name of the file. */ public final String getName() { return this.name; } /** * Returns the file item's parent. * * @return A {@link CloudFileDirectory} object that represents the parent directory for the file. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException * If the resource URI is invalid. */ @Override public final CloudFileDirectory getParent() throws URISyntaxException, StorageException { if (this.parent == null) { final String parentName = getParentNameFromURI(this.getStorageUri(), this.getShare()); if (parentName != null) { StorageUri parentURI = PathUtility.appendPathToUri(this.share.getStorageUri(), parentName); this.parent = new CloudFileDirectory(parentURI, this.getServiceClient().getCredentials()); } } return this.parent; } /** * Returns the file's properties. * * @return A {@link FileProperties} object that represents the properties of the file. */ public final FileProperties getProperties() { return this.properties; } /** * Returns the file service client associated with the file. * * @return A {@link CloudFileClient} object that represents the client. */ public final CloudFileClient getServiceClient() { return this.fileServiceClient; } /** * Gets the number of bytes to buffer when writing to a {@link FileOutputStream}. * * @return * A int which represents the number of bytes to buffer. */ public final int getStreamWriteSizeInBytes() { return this.streamWriteSizeInBytes; } /** * Returns the minimum read size when using a {@link FileInputStream}. * * @return A int which represents the minimum read size, in bytes, when using a {@link FileInputStream} * object. */ public final int getStreamMinimumReadSizeInBytes() { return this.streamMinimumReadSizeInBytes; } /** * Returns the list of URIs for all locations. * * @return A {@link StorageUri} that represents the list of URIs for all locations. */ @Override public final StorageUri getStorageUri() { return this.storageUri; } /** * Returns the URI for this file. * * @return A java.net.URI object that represents the URI for the file. */ @Override public final URI getUri() { return this.storageUri.getPrimaryUri(); } /** * Sets the share for the file. * * @param share * A {@link CloudFileShare} object that represents the share being assigned to the file. */ protected final void setShare(final CloudFileShare share) { this.share = share; } /** * Sets the metadata for the file. * * @param metadata * A java.util.HashMap object that contains the metadata being assigned to the file. */ public final void setMetadata(final HashMap metadata) { this.metadata = metadata; } /** * Sets the properties for the file. * * @param properties * A {@link FileProperties} object that represents the properties being assigned to the file. */ protected final void setProperties(final FileProperties properties) { this.properties = properties; } /** * Sets the list of URIs for all locations. * * @param storageUri * A {@link StorageUri} that represents the list of URIs for all locations. */ protected void setStorageUri(final StorageUri storageUri) { this.storageUri = storageUri; } /** * Sets the minimum read size when using a {@link FileInputStream}. * * @param minimumReadSize * An int that represents the minimum number of bytes to buffer when reading from * a file while using a {@link FileInputStream} object. Must be greater than or equal to 16 KB. * @throws IllegalArgumentException * If minimumReadSize is less than 16 KB. */ public void setStreamMinimumReadSizeInBytes(final int minimumReadSize) { if (minimumReadSize < 16 * Constants.KB) { throw new IllegalArgumentException("MinimumReadSize"); } this.streamMinimumReadSizeInBytes = minimumReadSize; } /** * Sets the number of bytes to buffer when writing to a {@link FileOutputStream}. * * @param streamWriteSizeInBytes * An int which represents the number of bytes to buffer while using a * {@link FileOutputStream} object, ranging from 512 bytes to 4 MB, inclusive. * * @throws IllegalArgumentException * If streamWriteSizeInBytes is less than 512 bytes or greater than 4 MB. */ public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) { if (streamWriteSizeInBytes > Constants.MAX_FILE_WRITE_SIZE || streamWriteSizeInBytes < Constants.MIN_PERMITTED_FILE_WRITE_SIZE) { throw new IllegalArgumentException("StreamWriteSizeInBytes"); } this.streamWriteSizeInBytes = streamWriteSizeInBytes; } /** * Returns the transformed URI for the resource if the given credentials require transformation. * * @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 {@link StorageUri} object that represents the transformed URI. * * @throws StorageException * If a storage service error occurred. * @throws URISyntaxException * If the resource URI is invalid. */ protected final StorageUri getTransformedAddress(final OperationContext opContext) throws URISyntaxException, StorageException { return this.fileServiceClient.getCredentials().transformUri(this.getStorageUri(), opContext); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy