com.microsoft.windowsazure.storage.queue.CloudQueue Maven / Gradle / Ivy
/**
* 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.windowsazure.storage.queue;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import javax.xml.stream.XMLStreamException;
import com.microsoft.windowsazure.storage.Constants;
import com.microsoft.windowsazure.storage.DoesServiceRequest;
import com.microsoft.windowsazure.storage.OperationContext;
import com.microsoft.windowsazure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.windowsazure.storage.StorageErrorCodeStrings;
import com.microsoft.windowsazure.storage.StorageException;
import com.microsoft.windowsazure.storage.StorageUri;
import com.microsoft.windowsazure.storage.core.BaseResponse;
import com.microsoft.windowsazure.storage.core.ExecutionEngine;
import com.microsoft.windowsazure.storage.core.PathUtility;
import com.microsoft.windowsazure.storage.core.RequestLocationMode;
import com.microsoft.windowsazure.storage.core.SR;
import com.microsoft.windowsazure.storage.core.SharedAccessSignatureHelper;
import com.microsoft.windowsazure.storage.core.StorageRequest;
import com.microsoft.windowsazure.storage.core.UriQueryBuilder;
import com.microsoft.windowsazure.storage.core.Utility;
/**
* This class represents a queue in the Windows Azure Queue service.
*/
public final class CloudQueue {
/**
* Gets the first message from a list of queue messages, if any.
*
* @param messages
* The Iterable
collection of {@link CloudQueueMessage} objects to get the first message
* from.
*
* @return The first {@link CloudQueueMessage} from the list of queue messages, or null
if the list is
* empty.
*/
private static CloudQueueMessage getFirstOrNull(final Iterable messages) {
for (final CloudQueueMessage m : messages) {
return m;
}
return null;
}
/**
* The name of the queue.
*/
private String name;
/**
* A reference to the queue's associated service client.
*/
private CloudQueueClient queueServiceClient;
/**
* The queue's Metadata collection.
*/
private HashMap metadata;
/**
* The queue's approximate message count, as reported by the server.
*/
private long approximateMessageCount;
/**
* The CloudQueue
class using the specified address and client.
*
* @param queueName
* A String
that represents the queue name.
* @param client
* A {@link CloudQueueClient} object that represents the associated service client, and that specifies
* the endpoint for the Queue service.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
public CloudQueue(final String queueName, final CloudQueueClient client) throws URISyntaxException,
StorageException {
Utility.assertNotNull("client", client);
Utility.assertNotNull("queueName", queueName);
this.storageUri = PathUtility.appendPathToUri(client.getStorageUri(), queueName);
this.name = PathUtility.getQueueNameFromUri(this.storageUri.getPrimaryUri(), client.isUsePathStyleUris());
this.queueServiceClient = client;
this.shouldEncodeMessage = true;
this.parseQueryAndVerify(this.storageUri, client, client.isUsePathStyleUris());
}
/**
* Creates an instance of the CloudQueue
class using the specified queue URI and client.
*
* @param uri
* A java.net.URI
object that represents the absolute URI of the queue.
* @param client
* A {@link CloudQueueClient} object that represents the associated service client, and that specifies
* the endpoint for the Queue service.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
public CloudQueue(final URI uri, final CloudQueueClient client) throws URISyntaxException, StorageException {
this(new StorageUri(uri, null), client);
}
/**
* Creates an instance of the CloudQueue
class using the specified queue URI and client.
*
* @param uri
* A StorageUri
object that represents the absolute URI of the queue.
* @param client
* A {@link CloudQueueClient} object that represents the associated service client, and that specifies
* the endpoint for the Queue service.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
public CloudQueue(final StorageUri uri, final CloudQueueClient client) throws URISyntaxException, StorageException {
Utility.assertNotNull("storageUri", uri);
this.storageUri = uri;
boolean usePathStyleUris = client == null ? Utility.determinePathStyleFromUri(this.storageUri.getPrimaryUri(),
null) : client.isUsePathStyleUris();
this.name = PathUtility.getQueueNameFromUri(uri.getPrimaryUri(), usePathStyleUris);
this.queueServiceClient = client;
this.shouldEncodeMessage = true;
this.parseQueryAndVerify(this.storageUri, client, usePathStyleUris);
}
/**
* Adds a message to the back of the queue with the default options.
*
* @param message
* A {@link CloudQueueMessage} object that specifies the message to add.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void addMessage(final CloudQueueMessage message) throws StorageException {
this.addMessage(message, 0, 0, null /* options */, null /* opContext */);
}
/**
* Adds a message to the back of the queue with the specified options.
*
* @param message
* A {@link CloudQueueMessage} object that specifies the message to add.
*
* @param timeToLiveInSeconds
* The maximum time to allow the message to be in the queue. A value of zero will set the time-to-live to
* the service default value of seven days.
*
* @param initialVisibilityDelayInSeconds
* The length of time during which the message will be invisible, starting when it is added to the queue,
* or 0 to make the message visible immediately. This value must be greater than or equal to zero and
* less than or equal to the time-to-live value.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
*
* @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 during the operation.
*/
@DoesServiceRequest
public void addMessage(final CloudQueueMessage message, final int timeToLiveInSeconds,
final int initialVisibilityDelayInSeconds, QueueRequestOptions options, OperationContext opContext)
throws StorageException {
Utility.assertNotNull("message", message);
Utility.assertNotNull("messageContent", message.getMessageContentAsByte());
Utility.assertInBounds("timeToLiveInSeconds", timeToLiveInSeconds, 0,
QueueConstants.MAX_TIME_TO_LIVE_IN_SECONDS);
final int realTimeToLiveInSeconds = timeToLiveInSeconds == 0 ? QueueConstants.MAX_TIME_TO_LIVE_IN_SECONDS
: timeToLiveInSeconds;
Utility.assertInBounds("initialVisibilityDelayInSeconds", initialVisibilityDelayInSeconds, 0,
realTimeToLiveInSeconds - 1);
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this,
this.addMessageImpl(message, realTimeToLiveInSeconds, initialVisibilityDelayInSeconds, options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest addMessageImpl(final CloudQueueMessage message,
final int timeToLiveInSeconds, final int initialVisibilityDelayInSeconds, final QueueRequestOptions options)
throws StorageException {
final String stringToSend = message.getMessageContentForTransfer(this.shouldEncodeMessage);
try {
final byte[] messageBytes = QueueRequest.generateMessageRequestBody(stringToSend);
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue,
OperationContext context) throws Exception {
this.setSendStream(new ByteArrayInputStream(messageBytes));
this.setLength((long) messageBytes.length);
return QueueRequest.putMessage(
queue.getMessageRequestAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), initialVisibilityDelayInSeconds, timeToLiveInSeconds,
context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, messageBytes.length, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client,
OperationContext context) throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) {
this.setNonExceptionedRetryableFailure(true);
return null;
}
return null;
}
};
return putRequest;
}
catch (XMLStreamException e) {
// The request was not even made. There was an error while trying to generate the message body. Just throw.
StorageException translatedException = StorageException.translateException(null, e, null);
throw translatedException;
}
}
/**
* Clears all messages from the queue, using the default request options.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void clear() throws StorageException {
this.clear(null /* options */, null /* opContext */);
}
/**
* Clears all messages from the queue, using the specified request options and operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 during the operation.
*/
@DoesServiceRequest
public void clear(QueueRequestOptions options, OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.clearImpl(options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest clearImpl(final QueueRequestOptions options)
throws StorageException {
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.clearMessages(
queue.getMessageRequestAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
}
return null;
}
};
return putRequest;
}
/**
* Creates the queue in the storage service with default request options.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void create() throws StorageException {
this.create(null /* options */, null /* opContext */);
}
/**
* Creates the queue in the storage service using the specified request options and operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 during the operation.
*/
@DoesServiceRequest
public void create(QueueRequestOptions options, OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.createImpl(options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest createImpl(final QueueRequestOptions options)
throws StorageException {
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.create(queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void setHeaders(HttpURLConnection connection, CloudQueue queue, OperationContext context) {
QueueRequest.addMetadata(connection, queue.metadata, context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, 0L, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED
&& this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
}
return null;
}
};
return putRequest;
}
/**
* Creates the queue in the storage service using default request options if it does not already exist.
*
* @return A value of true
if the queue is created in the storage service, otherwise false
* .
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public boolean createIfNotExists() throws StorageException {
return this.createIfNotExists(null /* options */, null /* opContext */);
}
/**
* Creates the queue in the storage service with the specified request options and operation context if it does not
* already exist.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 value of true
if the queue is created in the storage service, otherwise false
* .
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public boolean createIfNotExists(QueueRequestOptions options, OperationContext opContext) throws StorageException {
boolean exists = this.exists(true, options, opContext);
if (exists) {
return false;
}
else {
try {
this.create(options, opContext);
return true;
}
catch (StorageException e) {
if (e.getHttpStatusCode() == HttpURLConnection.HTTP_CONFLICT
&& StorageErrorCodeStrings.QUEUE_ALREADY_EXISTS.equals(e.getErrorCode())) {
return false;
}
else {
throw e;
}
}
}
}
/**
* Deletes the queue from the storage service.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void delete() throws StorageException {
this.delete(null /* options */, null /* opContext */);
}
/**
* Deletes the queue from the storage service, using the specified request options and operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 during the operation.
*/
@DoesServiceRequest
public void delete(QueueRequestOptions options, OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.deleteImpl(options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest deleteImpl(final QueueRequestOptions options)
throws StorageException {
final StorageRequest deleteRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.delete(queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
}
return null;
}
};
return deleteRequest;
}
/**
* Deletes the queue from the storage service if it exists.
*
* @return A value of true
if the queue existed in the storage service and has been deleted, otherwise
* false
.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public boolean deleteIfExists() throws StorageException {
return this.deleteIfExists(null /* options */, null /* opContext */);
}
/**
* Deletes the queue from the storage service using the specified request options and operation context, if it
* exists.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 value of true
if the queue existed in the storage service and has been deleted, otherwise
* false
.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public boolean deleteIfExists(QueueRequestOptions options, OperationContext opContext) throws StorageException {
boolean exists = this.exists(true, options, opContext);
if (exists) {
try {
this.delete(options, opContext);
return true;
}
catch (StorageException e) {
if (e.getHttpStatusCode() == HttpURLConnection.HTTP_NOT_FOUND
&& StorageErrorCodeStrings.QUEUE_NOT_FOUND.equals(e.getErrorCode())) {
return false;
}
else {
throw e;
}
}
}
else {
return false;
}
}
/**
* Deletes the specified message from the queue.
*
* @param message
* A {@link CloudQueueMessage} object that specifies the message to delete.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void deleteMessage(final CloudQueueMessage message) throws StorageException {
this.deleteMessage(message, null /* options */, null /* opContext */);
}
/**
* Deletes the specified message from the queue, using the specified request options and operation context.
*
* @param message
* A {@link CloudQueueMessage} object that specifies the message to delete.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
*
* @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 during the operation.
*/
@DoesServiceRequest
public void deleteMessage(final CloudQueueMessage message, QueueRequestOptions options, OperationContext opContext)
throws StorageException {
Utility.assertNotNull("message", message);
Utility.assertNotNullOrEmpty("messageId", message.getId());
Utility.assertNotNullOrEmpty("popReceipt", message.getPopReceipt());
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.deleteMessageImpl(message, options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest deleteMessageImpl(final CloudQueueMessage message,
final QueueRequestOptions options) throws StorageException {
final String messageId = message.getId();
final String messagePopReceipt = message.getPopReceipt();
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.deleteMessage(
queue.getIndividualMessageAddress(messageId, context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), messagePopReceipt, context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
}
return null;
}
};
return putRequest;
}
/**
* Downloads the queue's metadata and approximate message count value.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void downloadAttributes() throws StorageException {
this.downloadAttributes(null /* options */, null /* opContext */);
}
/**
* Downloads the queue's metadata and approximate message count value, using the specified request options and
* operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueue}).
* @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 during the operation.
*/
@DoesServiceRequest
public void downloadAttributes(QueueRequestOptions options, OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.downloadAttributesImpl(options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest downloadAttributesImpl(final QueueRequestOptions options)
throws StorageException {
final StorageRequest getRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public void setRequestLocationMode() {
this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY);
}
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.downloadAttributes(
queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public Void preProcessResponse(CloudQueue queue, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) {
this.setNonExceptionedRetryableFailure(true);
return null;
}
queue.metadata = BaseResponse.getMetadata(this.getConnection());
queue.approximateMessageCount = QueueResponse.getApproximateMessageCount(this.getConnection());
return null;
}
};
return getRequest;
}
/**
* Returns a value that indicates whether the queue exists in the storage service.
*
* @return true
if the queue exists in the storage service, otherwise false
.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public boolean exists() throws StorageException {
return this.exists(null /* options */, null /* opContext */);
}
/**
* Returns a value that indicates whether the queue exists in the storage service, using the specified request
* options and operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 queue exists in the storage service, otherwise false
.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public boolean exists(QueueRequestOptions options, OperationContext opContext) throws StorageException {
return this.exists(false, options, opContext);
}
@DoesServiceRequest
private boolean exists(final boolean primaryOnly, QueueRequestOptions options, OperationContext opContext)
throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
return ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.existsImpl(primaryOnly, options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest existsImpl(final boolean primaryOnly,
final QueueRequestOptions options) throws StorageException {
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(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.downloadAttributes(
queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public Boolean preProcessResponse(CloudQueue parentObject, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) {
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;
}
/**
* Gets the approximate messages count of the queue. This value is initialized by a request to
* {@link #downloadAttributes} and represents the approximate message count when that request completed.
*
* @return A Long
object that represents the approximate messages count of the queue.
*/
public long getApproximateMessageCount() {
return this.approximateMessageCount;
}
/**
* Get a single message request (Used internally only).
*
* @return The URI
for a single message request.
*
* @throws URISyntaxException
* If the resource URI is invalid.
* @throws StorageException
*/
private StorageUri getIndividualMessageAddress(final String messageId, final OperationContext opContext)
throws URISyntaxException, StorageException {
return PathUtility.appendPathToUri(this.getMessageRequestAddress(opContext), messageId);
}
/**
* Get the message request base address (Used internally only).
*
* @return The message request URI
.
*
* @throws URISyntaxException
* If the resource URI is invalid.
* @throws StorageException
*/
private StorageUri getMessageRequestAddress(final OperationContext opContext) throws URISyntaxException,
StorageException {
if (this.messageRequestAddress == null) {
this.messageRequestAddress = PathUtility.appendPathToUri(this.getTransformedAddress(opContext),
QueueConstants.MESSAGES);
}
return this.messageRequestAddress;
}
/**
* Gets the metadata collection for the queue as stored in this CloudQueue
object. This value is
* initialized with the metadata from the queue by a call to {@link #downloadAttributes}, and is set on the queue
* with a call to {@link #uploadMetadata}.
*
* @return A java.util.HashMap
object that represents the metadata for the queue.
*/
public HashMap getMetadata() {
return this.metadata;
}
/**
* Gets the name of the queue.
*
* @return A String
object that represents the name of the queue.
*/
public String getName() {
return this.name;
}
/**
* Gets the queue service client associated with this queue.
*
* @return A {@link CloudQueueClient} object that represents the service client associated with this queue.
*/
public CloudQueueClient getServiceClient() {
return this.queueServiceClient;
}
/**
* Gets the value indicating whether the message should be base-64 encoded.
*
* @return A Boolean
that represents whether the message should be base-64 encoded.
*/
public boolean getShouldEncodeMessage() {
return this.shouldEncodeMessage;
}
/**
* Returns the list of URIs for all locations.
*
* @return A StorageUri
that represents the list of URIs for all locations..
*/
public final StorageUri getStorageUri() {
return this.storageUri;
}
/**
* Gets the absolute URI for this queue.
*
* @return A java.net.URI
object that represents the URI for this queue.
*/
public URI getUri() {
return this.storageUri.getPrimaryUri();
}
/**
* Peeks a message from the queue. A peek request retrieves a message from the front of the queue without changing
* its visibility.
*
* @return An {@link CloudQueueMessage} object that represents a message in this queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public CloudQueueMessage peekMessage() throws StorageException {
return this.peekMessage(null /* options */, null /* opContext */);
}
/**
* Peeks a message from the queue, using the specified request options and operation context. A peek request
* retrieves a message from the front of the queue without changing its visibility.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 {@link CloudQueueMessage} object that represents the requested message from the queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public CloudQueueMessage peekMessage(final QueueRequestOptions options, final OperationContext opContext)
throws StorageException {
return getFirstOrNull(this.peekMessages(1, null /* options */, null /* opContext */));
}
/**
* Peeks a specified number of messages from the queue. A peek request retrieves messages from the front of the
* queue without changing their visibility.
*
* @param numberOfMessages
* The number of messages to retrieve.
*
* @return An enumerable collection of {@link CloudQueueMessage} objects that represents the requested messages from
* the queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public Iterable peekMessages(final int numberOfMessages) throws StorageException {
return this.peekMessages(numberOfMessages, null /* options */, null /* opContext */);
}
/**
* Peeks a set of messages from the queue, using the specified request options and operation context. A peek request
* retrieves messages from the front of the queue without changing their visibility.
*
* @param numberOfMessages
* The number of messages to retrieve.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 enumerable collection of {@link CloudQueueMessage} objects that represents the requested messages from
* the queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public Iterable peekMessages(final int numberOfMessages, QueueRequestOptions options,
OperationContext opContext) throws StorageException {
Utility.assertInBounds("numberOfMessages", numberOfMessages, 1, QueueConstants.MAX_NUMBER_OF_MESSAGES_TO_PEEK);
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
return ExecutionEngine.executeWithRetry(this.queueServiceClient, this,
this.peekMessagesImpl(numberOfMessages, options), options.getRetryPolicyFactory(), opContext);
}
private StorageRequest> peekMessagesImpl(
final int numberOfMessages, final QueueRequestOptions options) throws StorageException {
final StorageRequest> getRequest = new StorageRequest>(
options, this.getStorageUri()) {
@Override
public void setRequestLocationMode() {
this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY);
}
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.peekMessages(
queue.getMessageRequestAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), numberOfMessages, context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public ArrayList preProcessResponse(CloudQueue queue, CloudQueueClient client,
OperationContext context) throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) {
this.setNonExceptionedRetryableFailure(true);
return null;
}
else {
return QueueDeserializationHelper.readMessages(this.getConnection().getInputStream(),
queue.shouldEncodeMessage);
}
}
};
return getRequest;
}
/**
* Retrieves a message from the front of the queue using the default request options. This operation marks the
* retrieved message as invisible in the queue for the default visibility timeout period.
*
* @return An {@link CloudQueueMessage} object that represents a message in this queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public CloudQueueMessage retrieveMessage() throws StorageException {
return this.retrieveMessage(QueueConstants.DEFAULT_VISIBILITY_MESSAGE_TIMEOUT_IN_SECONDS, null /* options */,
null /* opContext */);
}
/**
* Retrieves a message from the front of the queue, using the specified request options and operation context. This
* operation marks the retrieved message as invisible in the queue for the specified visibility timeout period.
*
* @param visibilityTimeoutInSeconds
* Specifies the visibility timeout for the message, in seconds.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 {@link CloudQueueMessage} object that represents a message in this queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public CloudQueueMessage retrieveMessage(final int visibilityTimeoutInSeconds, final QueueRequestOptions options,
final OperationContext opContext) throws StorageException {
return getFirstOrNull(this.retrieveMessages(1, visibilityTimeoutInSeconds, options, opContext));
}
/**
* Retrieves the specified number of messages from the front of the queue using the default request options. This
* operation marks the retrieved messages as invisible in the queue for the default visibility timeout period.
*
* @param numberOfMessages
* The number of messages to retrieve.
*
* @return An enumerable collection of {@link CloudQueueMessage} objects that represents the retrieved messages from
* the queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public Iterable retrieveMessages(final int numberOfMessages) throws StorageException {
return this.retrieveMessages(numberOfMessages, QueueConstants.DEFAULT_VISIBILITY_MESSAGE_TIMEOUT_IN_SECONDS,
null /* options */, null /* opContext */);
}
/**
* Retrieves the specified number of messages from the front of the queue using the specified request options and
* operation context. This operation marks the retrieved messages as invisible in the queue for the default
* visibility timeout period.
*
* @param numberOfMessages
* The number of messages to retrieve.
*
* @param visibilityTimeoutInSeconds
* Specifies the visibility timeout for the retrieved messages, in seconds.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 enumerable collection of {@link CloudQueueMessage} objects that represents the messages retrieved from
* the queue.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public Iterable retrieveMessages(final int numberOfMessages,
final int visibilityTimeoutInSeconds, QueueRequestOptions options, OperationContext opContext)
throws StorageException {
Utility.assertInBounds("numberOfMessages", numberOfMessages, 1, QueueConstants.MAX_NUMBER_OF_MESSAGES_TO_PEEK);
Utility.assertInBounds("visibilityTimeoutInSeconds", visibilityTimeoutInSeconds, 0,
QueueConstants.MAX_TIME_TO_LIVE_IN_SECONDS);
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
return ExecutionEngine.executeWithRetry(this.queueServiceClient, this,
this.retrieveMessagesImpl(numberOfMessages, visibilityTimeoutInSeconds, options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest> retrieveMessagesImpl(
final int numberOfMessages, final int visibilityTimeoutInSeconds, final QueueRequestOptions options)
throws StorageException {
final StorageRequest> getRequest = new StorageRequest>(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.retrieveMessages(
queue.getMessageRequestAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), numberOfMessages, visibilityTimeoutInSeconds, context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public ArrayList preProcessResponse(CloudQueue queue, CloudQueueClient client,
OperationContext context) throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) {
this.setNonExceptionedRetryableFailure(true);
return null;
}
else {
return QueueDeserializationHelper.readMessages(this.getConnection().getInputStream(),
queue.shouldEncodeMessage);
}
}
};
return getRequest;
}
/**
* Sets the metadata collection of name-value pairs to be set on the queue with an {@link #uploadMetadata} call.
* This collection will overwrite any existing queue metadata. If this is set to an empty collection, the queue
* metadata will be cleared on an {@link #uploadMetadata} call.
*
* @param metadata
* A java.util.HashMap
object that represents the metadata being assigned to the queue.
*/
public void setMetadata(final HashMap metadata) {
this.metadata = metadata;
}
/**
* Sets the flag indicating whether the message should be base-64 encoded.
*
* @param shouldEncodeMessage
* The value indicates whether the message should be base-64 encoded.
*/
public void setShouldEncodeMessage(final boolean shouldEncodeMessage) {
this.shouldEncodeMessage = shouldEncodeMessage;
}
/**
* Sets the name of the queue.
*
* @param name
* A String
that represents the name being assigned to the queue.
*/
protected void setName(final String name) {
this.name = name;
}
/**
* Updates the specified message in the queue with a new visibility timeout value in seconds.
*
* @param message
* The {@link CloudQueueMessage} to update in the queue.
*
* @param visibilityTimeoutInSeconds
* Specifies the new visibility timeout for the message, in seconds.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
public void updateMessage(final CloudQueueMessage message, final int visibilityTimeoutInSeconds)
throws StorageException {
this.updateMessage(message, visibilityTimeoutInSeconds, EnumSet.of(MessageUpdateFields.VISIBILITY),
null /* options */, null /* opContext */);
}
/**
* Updates a message in the queue, using the specified request options and operation context.
*
* @param message
* The {@link CloudQueueMessage} to update in the queue.
*
* @param visibilityTimeoutInSeconds
* Specifies the new visibility timeout for the message, in seconds.
*
* @param messageUpdateFields
* An EnumSet
of {@link MessageUpdateFields} values that specifies which parts of the
* message are to be updated.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
*
* @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 during the operation.
*/
@DoesServiceRequest
public void updateMessage(final CloudQueueMessage message, final int visibilityTimeoutInSeconds,
final EnumSet messageUpdateFields, QueueRequestOptions options,
OperationContext opContext) throws StorageException {
Utility.assertNotNull("message", message);
Utility.assertNotNullOrEmpty("messageId", message.getId());
Utility.assertNotNullOrEmpty("popReceipt", message.getPopReceipt());
Utility.assertInBounds("visibilityTimeoutInSeconds", visibilityTimeoutInSeconds, 0,
QueueConstants.MAX_TIME_TO_LIVE_IN_SECONDS);
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this,
this.updateMessageImpl(message, visibilityTimeoutInSeconds, messageUpdateFields, options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest updateMessageImpl(final CloudQueueMessage message,
final int visibilityTimeoutInSeconds, final EnumSet messageUpdateFields,
final QueueRequestOptions options) throws StorageException {
final String stringToSend = message.getMessageContentForTransfer(this.shouldEncodeMessage);
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
if (messageUpdateFields.contains(MessageUpdateFields.CONTENT)) {
final byte[] messageBytes = QueueRequest.generateMessageRequestBody(stringToSend);
this.setSendStream(new ByteArrayInputStream(messageBytes));
this.setLength((long) messageBytes.length);
}
return QueueRequest.updateMessage(
queue.getIndividualMessageAddress(message.getId(), context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), message.getPopReceipt(), visibilityTimeoutInSeconds, context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
if (messageUpdateFields.contains(MessageUpdateFields.CONTENT)) {
StorageRequest.signBlobAndQueueRequest(connection, client, this.getLength(), null);
}
else {
connection.setFixedLengthStreamingMode(0);
StorageRequest.signBlobAndQueueRequest(connection, client, 0L, null);
}
}
@Override
public Void preProcessResponse(CloudQueue queue, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
return null;
}
message.setPopReceipt(this.getConnection().getHeaderField(Constants.HeaderConstants.POP_RECEIPT_HEADER));
message.setNextVisibleTime(Utility.parseRFC1123DateFromStringInGMT(this.getConnection().getHeaderField(
Constants.HeaderConstants.TIME_NEXT_VISIBLE_HEADER)));
return null;
}
};
return putRequest;
}
/**
* Uploads the metadata in the CloudQueue
object to the queue, using the default request options.
*
* @throws StorageException
* If a storage service error occurred during the operation.
*/
@DoesServiceRequest
public void uploadMetadata() throws StorageException {
this.uploadMetadata(null /* options */, null /* opContext */);
}
/**
* Uploads the metadata in the CloudQueue
object to the queue, using the specified request options and
* operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
*
* @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 during the operation.
*/
@DoesServiceRequest
public void uploadMetadata(QueueRequestOptions options, OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.uploadMetadataImpl(options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest uploadMetadataImpl(final QueueRequestOptions options)
throws StorageException {
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.setMetadata(queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void setHeaders(HttpURLConnection connection, CloudQueue queue, OperationContext context) {
QueueRequest.addMetadata(connection, queue.metadata, context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, 0L, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
}
return null;
}
};
return putRequest;
}
/**
* Uploads the queue's permissions.
*
* @param permissions
* A {@link QueuePermissions} object that represents the permissions to upload.
*
* @throws StorageException
* If a storage service error occurred.
*/
@DoesServiceRequest
public void uploadPermissions(final QueuePermissions permissions) throws StorageException {
this.uploadPermissions(permissions, null /* options */, null /* opContext */);
}
/**
* Uploads the queue's permissions using the specified request options and operation context.
*
* @param permissions
* A {@link QueuePermissions} object that represents the permissions to upload.
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 void uploadPermissions(final QueuePermissions permissions, QueueRequestOptions options,
OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
ExecutionEngine.executeWithRetry(this.queueServiceClient, this,
this.uploadPermissionsImpl(permissions, options), options.getRetryPolicyFactory(), opContext);
}
private StorageRequest uploadPermissionsImpl(
final QueuePermissions permissions, final QueueRequestOptions options) throws StorageException {
final StringWriter outBuffer = new StringWriter();
try {
QueueRequest.writeSharedAccessIdentifiersToStream(permissions.getSharedAccessPolicies(), outBuffer);
final byte[] aclBytes = outBuffer.toString().getBytes(Constants.UTF8_CHARSET);
final StorageRequest putRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue,
OperationContext context) throws Exception {
this.setSendStream(new ByteArrayInputStream(aclBytes));
this.setLength((long) aclBytes.length);
return QueueRequest.setAcl(queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, aclBytes.length, null);
}
@Override
public Void preProcessResponse(CloudQueue parentObject, CloudQueueClient client,
OperationContext context) throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
this.setNonExceptionedRetryableFailure(true);
}
return null;
}
};
return putRequest;
}
catch (IllegalArgumentException e) {
// to do : Move this to multiple catch clause so we can avoid the duplicated code once we move to Java 1.7.
// The request was not even made. There was an error while trying to read the permissions. Just throw.
StorageException translatedException = StorageException.translateException(null, e, null);
throw translatedException;
}
catch (XMLStreamException e) {
// The request was not even made. There was an error while trying to read the permissions. Just throw.
StorageException translatedException = StorageException.translateException(null, e, null);
throw translatedException;
}
catch (UnsupportedEncodingException e) {
// The request was not even made. There was an error while trying to read the permissions. Just throw.
StorageException translatedException = StorageException.translateException(null, e, null);
throw translatedException;
}
}
/**
* Downloads the permission settings for the queue.
*
* @return A {@link QueuePermissions} object that represents the queue's permissions.
*
* @throws StorageException
* If a storage service error occurred.
*/
@DoesServiceRequest
public QueuePermissions downloadPermissions() throws StorageException {
return this.downloadPermissions(null /* options */, null /* opContext */);
}
/**
* Downloads the permissions settings for the queue using the specified request options and operation context.
*
* @param options
* A {@link QueueRequestOptions} object that specifies any additional options for the request. Specifying
* null
will use the default request options from the associated service client (
* {@link CloudQueueClient}).
* @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 QueuePermissions} object that represents the container's permissions.
*
* @throws StorageException
* If a storage service error occurred.
*/
@DoesServiceRequest
public QueuePermissions downloadPermissions(QueueRequestOptions options, OperationContext opContext)
throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
options = QueueRequestOptions.applyDefaults(options, this.queueServiceClient);
return ExecutionEngine.executeWithRetry(this.queueServiceClient, this, this.downloadPermissionsImpl(options),
options.getRetryPolicyFactory(), opContext);
}
private StorageRequest downloadPermissionsImpl(
final QueueRequestOptions options) throws StorageException {
final StorageRequest getRequest = new StorageRequest(
options, this.getStorageUri()) {
@Override
public void setRequestLocationMode() {
this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY);
}
@Override
public HttpURLConnection buildRequest(CloudQueueClient client, CloudQueue queue, OperationContext context)
throws Exception {
return QueueRequest.getAcl(queue.getTransformedAddress(context).getUri(this.getCurrentLocation()),
options.getTimeoutIntervalInMs(), context);
}
@Override
public void signRequest(HttpURLConnection connection, CloudQueueClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobAndQueueRequest(connection, client, -1L, null);
}
@Override
public QueuePermissions preProcessResponse(CloudQueue parentObject, CloudQueueClient client,
OperationContext context) throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) {
this.setNonExceptionedRetryableFailure(true);
return null;
}
return new QueuePermissions();
}
@Override
public QueuePermissions postProcessResponse(HttpURLConnection connection, CloudQueue queue,
CloudQueueClient client, OperationContext context, QueuePermissions queuePermissions)
throws Exception {
final QueueAccessPolicyResponse response = new QueueAccessPolicyResponse(connection.getInputStream());
for (final String key : response.getAccessIdentifiers().keySet()) {
queuePermissions.getSharedAccessPolicies().put(key, response.getAccessIdentifiers().get(key));
}
return queuePermissions;
}
};
return getRequest;
}
/**
* Returns a shared access signature for the queue.
*
* @param policy
* The access policy for the shared access signature.
* @param groupPolicyIdentifier
* A queue-level access policy.
* @return A shared access signature for the queue.
* @throws InvalidKeyException
* If an invalid key was passed.
* @throws StorageException
* If a storage service error occurred.
* @throws IllegalArgumentException
* If an unexpected value is passed.
*/
public String generateSharedAccessSignature(final SharedAccessQueuePolicy policy, final String groupPolicyIdentifier)
throws InvalidKeyException, StorageException {
if (!this.queueServiceClient.getCredentials().canCredentialsSignRequest()) {
final String errorMessage = SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY;
throw new IllegalArgumentException(errorMessage);
}
final String resourceName = this.getSharedAccessCanonicalName();
final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForQueue(policy,
groupPolicyIdentifier, resourceName, this.queueServiceClient, null);
final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForQueue(policy,
groupPolicyIdentifier, signature);
return builder.toString();
}
/**
* Returns the canonical name for shared access.
*
* @return the canonical name for shared access.
*/
private String getSharedAccessCanonicalName() {
if (this.queueServiceClient.isUsePathStyleUris()) {
return this.getUri().getPath();
}
else {
return PathUtility.getCanonicalPathFromCredentials(this.queueServiceClient.getCredentials(), this.getUri()
.getPath());
}
}
/**
* 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 java.net.URI
object that represents the transformed URI.
*
* @throws IllegalArgumentException
* If the URI is not absolute.
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
private final StorageUri getTransformedAddress(final OperationContext opContext) throws URISyntaxException,
StorageException {
if (this.queueServiceClient.getCredentials().doCredentialsNeedTransformUri()) {
if (this.getStorageUri().isAbsolute()) {
return this.queueServiceClient.getCredentials().transformUri(this.getStorageUri(), opContext);
}
else {
final StorageException ex = Utility.generateNewUnexpectedStorageException(null);
ex.getExtendedErrorInformation().setErrorMessage("Queue Object relative URIs not supported.");
throw ex;
}
}
else {
return this.getStorageUri();
}
}
/**
* Parse Uri for SAS (Shared access signature) information.
*
* Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding
* credentials instance. If existingClient is passed in, any SAS information found will not be supported. Otherwise
* a new client is created based on SAS information or as anonymous credentials.
*
* @param completeUri
* The complete Uri.
* @param existingClient
* The client to use.
* @param usePathStyleUris
* If true, path style Uris are used.
* @throws URISyntaxException
* @throws StorageException
*/
private void parseQueryAndVerify(final StorageUri completeUri, final CloudQueueClient existingClient,
final boolean usePathStyleUris) throws URISyntaxException, StorageException {
Utility.assertNotNull("completeUri", completeUri);
if (!completeUri.isAbsolute()) {
final String errorMessage = String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString());
throw new IllegalArgumentException(errorMessage);
}
this.storageUri = PathUtility.stripURIQueryAndFragment(completeUri);
final HashMap queryParameters = PathUtility.parseQueryString(completeUri.getQuery());
final StorageCredentialsSharedAccessSignature sasCreds = SharedAccessSignatureHelper
.parseQuery(queryParameters);
if (sasCreds == null) {
return;
}
final Boolean sameCredentials = existingClient == null ? false : Utility.areCredentialsEqual(sasCreds,
existingClient.getCredentials());
if (existingClient == null || !sameCredentials) {
this.queueServiceClient = new CloudQueueClient(PathUtility.getServiceClientBaseAddress(
this.getStorageUri(), usePathStyleUris), sasCreds);
}
if (existingClient != null && !sameCredentials) {
this.queueServiceClient.setRetryPolicyFactory(existingClient.getRetryPolicyFactory());
this.queueServiceClient.setTimeoutInMs(existingClient.getTimeoutInMs());
this.queueServiceClient.setLocationMode(existingClient.getLocationMode());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy