mirror of https://github.com/apache/jclouds.git
initial cut of azure queue service
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1883 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
6a8c3d160c
commit
64cf29701d
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.azure.storage.queue;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
|
||||
import org.jclouds.azure.storage.domain.MetadataList;
|
||||
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
|
||||
import org.jclouds.azure.storage.options.CreateOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
|
||||
import org.jclouds.azure.storage.queue.xml.AccountNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
|
||||
import org.jclouds.rest.Header;
|
||||
import org.jclouds.rest.Query;
|
||||
import org.jclouds.rest.RequestFilters;
|
||||
import org.jclouds.rest.SkipEncoding;
|
||||
import org.jclouds.rest.XMLResponseParser;
|
||||
|
||||
/**
|
||||
* Provides access to Azure Queue via their REST API.
|
||||
* <p/>
|
||||
* The Queue service stores messages that may be read by any client who has access to the storage
|
||||
* account.
|
||||
* <p/>
|
||||
* A queue can contain an unlimited number of messages, each of which can be up to 8 KB in size.
|
||||
* Messages are generally added to the end of the queue and retrieved from the front of the queue,
|
||||
* although first in, first out (FIFO) behavior is not guaranteed.
|
||||
* <p/>
|
||||
* If you need to store messages larger than 8 KB, you can store message data as a blob or in a
|
||||
* table, and then store a reference to the data as a message in a queue.
|
||||
* <p/>
|
||||
* All commands return a Future of the result from Azure Queue. Any exceptions incurred during
|
||||
* processing will be wrapped in an {@link ExecutionException} as documented in {@link Future#get()}.
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@SkipEncoding('/')
|
||||
@RequestFilters(SharedKeyAuthentication.class)
|
||||
@Header(key = AzureStorageHeaders.VERSION, value = "2009-07-17")
|
||||
public interface AzureQueueConnection {
|
||||
|
||||
/**
|
||||
* The List Queues operation returns a list of the queues under the specified account.
|
||||
* <p />
|
||||
* The 2009-07-17 version of the List Queues operation times out after 30 seconds.
|
||||
*
|
||||
* @param listOptions
|
||||
* controls the number or type of results requested
|
||||
* @see ListOptions
|
||||
*/
|
||||
@GET
|
||||
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
|
||||
@Path("/")
|
||||
@Query(key = "comp", value = "list")
|
||||
MetadataList<QueueMetadata> listQueues(ListOptions... listOptions);
|
||||
|
||||
/**
|
||||
* The Create Queue operation creates a new queue under the specified account.
|
||||
* <p/>
|
||||
* You can specify user-defined metadata as name-value pairs on the queue at the time that it is
|
||||
* created.
|
||||
* <p/>
|
||||
* When a queue with the specified name already exists, the Queue service checks the metadata
|
||||
* associated with the existing queue. If the existing metadata is identical to the metadata
|
||||
* specified on the Create Queue request, status code 204 (No Content) is returned.
|
||||
* <p/>
|
||||
* If the existing metadata does not match the metadata provided with the Create Queue request,
|
||||
* the operation fails and status code 409 (Conflict) is returned. Clients can take advantage of
|
||||
* this behavior to avoid an additional call to check whether a named queue already exists.
|
||||
*
|
||||
* @see CreateQueueOptions
|
||||
*
|
||||
*/
|
||||
@PUT
|
||||
@Path("{queue}")
|
||||
@Query(key = "restype", value = "queue")
|
||||
boolean createQueue(@PathParam("queue") String queue, CreateOptions... options);
|
||||
|
||||
/**
|
||||
* The Delete Queue operation permanently deletes the specified queue.
|
||||
*
|
||||
* <p/>
|
||||
* When a queue is successfully deleted, the queue is immediately marked for deletion and is no
|
||||
* longer accessible to clients. The queue is later removed from the Queue service during garbage
|
||||
* collection.
|
||||
*
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{queue}")
|
||||
@Query(key = "restype", value = "queue")
|
||||
boolean deleteQueue(@PathParam("queue") String queue);
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.jclouds.azure.storage.queue;
|
||||
|
||||
import org.jclouds.cloud.CloudContext;
|
||||
|
||||
/**
|
||||
* Represents an authenticated context to Azure Queue Service.
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
|
||||
* @see AzureQueueConnection
|
||||
* @see CloudContext
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public interface AzureQueueContext extends CloudContext<AzureQueueConnection> {
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.azure.storage.queue;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_ADDRESS;
|
||||
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_MAX_REDIRECTS;
|
||||
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_MAX_RETRIES;
|
||||
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_SECURE;
|
||||
import static org.jclouds.http.HttpConstants.PROPERTY_SAX_DEBUG;
|
||||
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_IO_WORKER_THREADS;
|
||||
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTIONS;
|
||||
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTION_REUSE;
|
||||
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES;
|
||||
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_REQUEST_INVOKER_THREADS;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.azure.storage.queue.config.AzureQueueContextModule;
|
||||
import org.jclouds.azure.storage.queue.config.RestAzureQueueConnectionModule;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.azure.storage.xml.config.AzureStorageParserModule;
|
||||
import org.jclouds.cloud.CloudContextBuilder;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.logging.jdk.config.JDKLoggingModule;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
* Creates {@link AzureQueueContext} or {@link Injector} instances based on the most commonly
|
||||
* requested arguments.
|
||||
* <p/>
|
||||
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
|
||||
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see AzureQueueContext
|
||||
*/
|
||||
public class AzureQueueContextBuilder extends
|
||||
CloudContextBuilder<AzureQueueConnection, AzureQueueContext> {
|
||||
|
||||
public AzureQueueContextBuilder(Properties props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public static AzureQueueContextBuilder newBuilder(String id, String secret) {
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.setProperty(PROPERTY_HTTP_ADDRESS, id + ".queue.core.windows.net");
|
||||
properties.setProperty(PROPERTY_HTTP_SECURE, "true");
|
||||
properties.setProperty(PROPERTY_SAX_DEBUG, "false");
|
||||
properties.setProperty(PROPERTY_HTTP_MAX_RETRIES, "5");
|
||||
properties.setProperty(PROPERTY_HTTP_MAX_REDIRECTS, "5");
|
||||
properties.setProperty(PROPERTY_POOL_MAX_CONNECTION_REUSE, "75");
|
||||
properties.setProperty(PROPERTY_POOL_MAX_SESSION_FAILURES, "2");
|
||||
properties.setProperty(PROPERTY_POOL_REQUEST_INVOKER_THREADS, "1");
|
||||
properties.setProperty(PROPERTY_POOL_IO_WORKER_THREADS, "2");
|
||||
properties.setProperty(PROPERTY_POOL_MAX_CONNECTIONS, "12");
|
||||
|
||||
AzureQueueContextBuilder builder = new AzureQueueContextBuilder(properties);
|
||||
builder.authenticate(id, secret);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void authenticate(String id, String secret) {
|
||||
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id,
|
||||
"azureStorageAccount"));
|
||||
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY, checkNotNull(secret,
|
||||
"azureStorageKey"));
|
||||
}
|
||||
|
||||
public AzureQueueContext buildContext() {
|
||||
return buildInjector().getInstance(AzureQueueContext.class);
|
||||
}
|
||||
|
||||
protected void addParserModule(List<Module> modules) {
|
||||
modules.add(new AzureStorageParserModule());
|
||||
}
|
||||
|
||||
protected void addContextModule(List<Module> modules) {
|
||||
modules.add(new AzureQueueContextModule());
|
||||
}
|
||||
|
||||
protected void addConnectionModule(List<Module> modules) {
|
||||
modules.add(new RestAzureQueueConnectionModule());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.jclouds.azure.storage.queue.config;
|
||||
|
||||
import org.jclouds.azure.storage.queue.AzureQueueConnection;
|
||||
import org.jclouds.azure.storage.queue.AzureQueueContext;
|
||||
import org.jclouds.azure.storage.queue.internal.GuiceAzureQueueContext;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
/**
|
||||
* Configures the {@link AzureQueueContext}; requires {@link AzureQueueConnection} bound.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AzureQueueContextModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
this.requireBinding(AzureQueueConnection.class);
|
||||
bind(AzureQueueContext.class).to(GuiceAzureQueueContext.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.jclouds.azure.storage.queue.config;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.azure.storage.queue.AzureQueueConnection;
|
||||
import org.jclouds.azure.storage.config.RestAzureStorageConnectionModule;
|
||||
import org.jclouds.cloud.ConfiguresCloudConnection;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.rest.RestClientFactory;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Configures the Azure Queue Service connection, including logging and http transport.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresCloudConnection
|
||||
@RequiresHttp
|
||||
public class RestAzureQueueConnectionModule extends RestAzureStorageConnectionModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected AzureQueueConnection provideAzureStorageConnection(URI uri, RestClientFactory factory) {
|
||||
return factory.create(uri, AzureQueueConnection.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.azure.storage.queue.domain;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class QueueMetadata {
|
||||
private final String name;
|
||||
private final URI url;
|
||||
|
||||
public QueueMetadata(String name, URI url) {
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "QueueMetadata [name=" + name + ", url=" + url + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((url == null) ? 0 : url.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
QueueMetadata other = (QueueMetadata) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (url == null) {
|
||||
if (other.url != null)
|
||||
return false;
|
||||
} else if (!url.equals(other.url))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public URI getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.jclouds.azure.storage.queue.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.jclouds.azure.storage.queue.AzureQueueConnection;
|
||||
import org.jclouds.azure.storage.queue.AzureQueueContext;
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Uses a Guice Injector to configure the objects served by AzureQueueContext methods.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see Injector
|
||||
*/
|
||||
public class GuiceAzureQueueContext implements AzureQueueContext {
|
||||
|
||||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
private final Injector injector;
|
||||
private final Closer closer;
|
||||
|
||||
@Inject
|
||||
private GuiceAzureQueueContext(Injector injector, Closer closer) {
|
||||
this.injector = injector;
|
||||
this.closer = closer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public AzureQueueConnection getConnection() {
|
||||
return injector.getInstance(AzureQueueConnection.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see Closer
|
||||
*/
|
||||
public void close() {
|
||||
try {
|
||||
closer.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e, "error closing content");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.azure.storage.queue.xml;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.azure.storage.domain.MetadataList;
|
||||
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Parses the following XML document:
|
||||
* <p/>
|
||||
* EnumerationResults AccountName="http://myaccount.queue.core.windows.net"
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd179352.aspx" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AccountNameEnumerationResultsHandler extends
|
||||
ParseSax.HandlerWithResult<MetadataList<QueueMetadata>> {
|
||||
|
||||
private List<QueueMetadata> metadata = new ArrayList<QueueMetadata>();
|
||||
private String prefix;
|
||||
private String marker;
|
||||
private int maxResults;
|
||||
private String nextMarker;
|
||||
private String currentName;
|
||||
private URI currentUrl;
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
|
||||
@Inject
|
||||
public AccountNameEnumerationResultsHandler() {
|
||||
}
|
||||
|
||||
public MetadataList<QueueMetadata> getResult() {
|
||||
return new MetadataList<QueueMetadata>(prefix, marker, maxResults, metadata, nextMarker);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (qName.equals("MaxResults")) {
|
||||
maxResults = Integer.parseInt(currentText.toString().trim());
|
||||
} else if (qName.equals("Marker")) {
|
||||
marker = currentText.toString().trim();
|
||||
marker = (marker.equals("")) ? null : marker;
|
||||
} else if (qName.equals("Prefix")) {
|
||||
prefix = currentText.toString().trim();
|
||||
prefix = (prefix.equals("")) ? null : prefix;
|
||||
} else if (qName.equals("NextMarker")) {
|
||||
nextMarker = currentText.toString().trim();
|
||||
nextMarker = (nextMarker.equals("")) ? null : nextMarker;
|
||||
} else if (qName.equals("Queue")) {
|
||||
metadata.add(new QueueMetadata(currentName, currentUrl));
|
||||
currentUrl = null;
|
||||
currentName = null;
|
||||
} else if (qName.equals("Url")) {
|
||||
currentUrl = URI.create(currentText.toString().trim());
|
||||
} else if (qName.equals("QueueName")) {
|
||||
currentName = currentText.toString().trim();
|
||||
}
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.jclouds.azure.storage.queue.xml;
|
||||
|
||||
import org.jclouds.azure.storage.domain.MetadataList;
|
||||
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
|
||||
import org.jclouds.azure.storage.xml.AzureStorageParserFactory;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* Creates Parsers needed to interpret Azure Queue Service messages. This class uses guice assisted
|
||||
* inject, which mandates the creation of many single-method interfaces. These interfaces are not
|
||||
* intended for public api.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AzureQueueParserFactory extends AzureStorageParserFactory {
|
||||
|
||||
@Inject
|
||||
private GenericParseFactory<MetadataList<QueueMetadata>> parseContainerMetadataListFactory;
|
||||
|
||||
@Inject
|
||||
Provider<AccountNameEnumerationResultsHandler> containerMetaListHandlerProvider;
|
||||
|
||||
public ParseSax<MetadataList<QueueMetadata>> createContainerMetadataListParser() {
|
||||
return parseContainerMetadataListFactory.create(containerMetaListHandlerProvider.get());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package org.jclouds.azure.storage.queue.xml.config;
|
||||
|
||||
import org.jclouds.azure.storage.domain.MetadataList;
|
||||
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
|
||||
import org.jclouds.azure.storage.queue.xml.AccountNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.xml.AzureStorageParserFactory;
|
||||
import org.jclouds.azure.storage.xml.config.AzureStorageParserModule;
|
||||
import org.jclouds.command.ConfiguresResponseTransformer;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.assistedinject.FactoryProvider;
|
||||
|
||||
/**
|
||||
* Creates the factories needed to interpret Azure Queue Service responses
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresResponseTransformer
|
||||
public class AzureQueueParserModule extends AzureStorageParserModule {
|
||||
protected final TypeLiteral<AzureStorageParserFactory.GenericParseFactory<MetadataList<QueueMetadata>>> accountNameEnumerationResultsHandler = new TypeLiteral<AzureStorageParserFactory.GenericParseFactory<MetadataList<QueueMetadata>>>() {
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void bindParserImplementationsToReturnTypes() {
|
||||
super.bindParserImplementationsToReturnTypes();
|
||||
bind(new TypeLiteral<ParseSax.HandlerWithResult<MetadataList<QueueMetadata>>>() {
|
||||
}).to(AccountNameEnumerationResultsHandler.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindCallablesThatReturnParseResults() {
|
||||
super.bindCallablesThatReturnParseResults();
|
||||
bind(accountNameEnumerationResultsHandler).toProvider(
|
||||
FactoryProvider.newFactory(accountNameEnumerationResultsHandler,
|
||||
new TypeLiteral<ParseSax<MetadataList<QueueMetadata>>>() {
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package org.jclouds.azure.storage.queue;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.jclouds.azure.storage.domain.MetadataList;
|
||||
import org.jclouds.azure.storage.options.CreateOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AzureQueueConnection}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", sequential = true, testName = "cloudservers.AzureQueueConnectionLiveTest")
|
||||
public class AzureQueueConnectionLiveTest {
|
||||
|
||||
protected static final String sysAzureStorageAccount = System
|
||||
.getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT);
|
||||
protected static final String sysAzureStorageKey = System
|
||||
.getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY);
|
||||
protected AzureQueueConnection connection;
|
||||
|
||||
private String queuePrefix = System.getProperty("user.name") + "-azurequeue";
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
public void setupConnection() {
|
||||
Injector injector = AzureQueueContextBuilder.newBuilder(sysAzureStorageAccount,
|
||||
sysAzureStorageKey).withModules(new Log4JLoggingModule()).withSaxDebug()
|
||||
.buildInjector();
|
||||
connection = injector.getInstance(AzureQueueConnection.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListQueues() throws Exception {
|
||||
|
||||
MetadataList<QueueMetadata> response = connection.listQueues();
|
||||
assert null != response;
|
||||
long initialQueueCount = response.getMetadata().size();
|
||||
assertTrue(initialQueueCount >= 0);
|
||||
|
||||
}
|
||||
|
||||
String privateQueue;
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000)
|
||||
public void testCreateQueue() throws Exception {
|
||||
boolean created = false;
|
||||
while (!created) {
|
||||
privateQueue = queuePrefix + new SecureRandom().nextInt();
|
||||
try {
|
||||
created = connection.createQueue(privateQueue, CreateOptions.Builder
|
||||
.withMetadata(ImmutableMultimap.of("foo", "bar")));
|
||||
} catch (UndeclaredThrowableException e) {
|
||||
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
|
||||
if (htpe.getResponse().getStatusCode() == 409)
|
||||
continue;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
MetadataList<QueueMetadata> response = connection.listQueues();
|
||||
assert null != response;
|
||||
long queueCount = response.getMetadata().size();
|
||||
assertTrue(queueCount >= 1);
|
||||
// TODO ... check to see the queue actually exists
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListQueuesWithOptions() throws Exception {
|
||||
|
||||
MetadataList<QueueMetadata> response = connection.listQueues(ListOptions.Builder.prefix(
|
||||
privateQueue).maxResults(1));
|
||||
assert null != response;
|
||||
long initialQueueCount = response.getMetadata().size();
|
||||
assertTrue(initialQueueCount >= 0);
|
||||
assertEquals(privateQueue, response.getPrefix());
|
||||
assertEquals(1, response.getMaxResults());
|
||||
}
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testCreateQueue" })
|
||||
public void testDeleteQueue() throws Exception {
|
||||
assert connection.deleteQueue(privateQueue);
|
||||
// TODO loop for up to 30 seconds checking if they are really gone
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package org.jclouds.azure.storage.queue;
|
||||
|
||||
import static org.jclouds.azure.storage.options.CreateOptions.Builder.withMetadata;
|
||||
import static org.jclouds.azure.storage.options.ListOptions.Builder.maxResults;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
import org.jclouds.azure.storage.options.CreateOptions;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
import org.jclouds.azure.storage.queue.xml.config.AzureQueueParserModule;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.concurrent.WithinThreadExecutorService;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
import org.jclouds.rest.JaxrsAnnotationProcessor;
|
||||
import org.jclouds.rest.config.JaxrsModule;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AzureQueueConnection}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "cloudservers.AzureQueueConnectionTest")
|
||||
public class AzureQueueConnectionTest {
|
||||
|
||||
JaxrsAnnotationProcessor.Factory factory;
|
||||
|
||||
private static final Class<? extends ListOptions[]> listOptionsVarargsClass = new ListOptions[] {}
|
||||
.getClass();
|
||||
private static final Class<? extends CreateOptions[]> createOptionsVarargsClass = new CreateOptions[] {}
|
||||
.getClass();
|
||||
|
||||
public void testListQueues() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureQueueConnection.class.getMethod("listQueues", listOptionsVarargsClass);
|
||||
URI endpoint = URI.create("http://localhost");
|
||||
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] {});
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "comp=list");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method).getClass(), ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testListQueuesOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureQueueConnection.class.getMethod("listQueues", listOptionsVarargsClass);
|
||||
URI endpoint = URI.create("http://localhost");
|
||||
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { maxResults(
|
||||
1).marker("marker").prefix("prefix") });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(),
|
||||
"comp=list&marker=marker&maxresults=1&prefix=prefix");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method).getClass(), ParseSax.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testCreateQueue() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureQueueConnection.class.getMethod("createQueue", String.class,
|
||||
createOptionsVarargsClass);
|
||||
URI endpoint = URI.create("http://localhost");
|
||||
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "queue" });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/queue");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=queue");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 2);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testDeleteQueue() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureQueueConnection.class.getMethod("deleteQueue", String.class);
|
||||
URI endpoint = URI.create("http://localhost");
|
||||
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "queue" });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/queue");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=queue");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
public void testCreateQueueOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureQueueConnection.class.getMethod("createQueue", String.class,
|
||||
createOptionsVarargsClass);
|
||||
URI endpoint = URI.create("http://localhost");
|
||||
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "queue",
|
||||
withMetadata(ImmutableMultimap.of("foo", "bar")) });
|
||||
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
|
||||
assertEquals(httpMethod.getEndpoint().getPath(), "/queue");
|
||||
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=queue");
|
||||
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
|
||||
assertEquals(httpMethod.getHeaders().size(), 3);
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
|
||||
.singletonList("2009-07-17"));
|
||||
assertEquals(httpMethod.getHeaders().get("x-ms-meta-foo"), Collections.singletonList("bar"));
|
||||
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
|
||||
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
|
||||
// TODO check generic type of response parser
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
}
|
||||
|
||||
JaxrsAnnotationProcessor processor;
|
||||
|
||||
@BeforeClass
|
||||
void setupFactory() {
|
||||
factory = Guice.createInjector(
|
||||
new AzureQueueParserModule(),
|
||||
new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(URI.class).toInstance(URI.create("http://localhost:8080"));
|
||||
bindConstant().annotatedWith(
|
||||
Names.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT)).to(
|
||||
"user");
|
||||
bindConstant().annotatedWith(
|
||||
Names.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
|
||||
HttpUtils.toBase64String("key".getBytes()));
|
||||
}
|
||||
|
||||
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
|
||||
new JavaUrlHttpCommandExecutorServiceModule()).getInstance(
|
||||
JaxrsAnnotationProcessor.Factory.class);
|
||||
processor = factory.create(AzureQueueConnection.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.azure.storage.queue.xml;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.azure.storage.domain.MetadataList;
|
||||
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ParseFlavorListFromGsonResponseTest}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "azurequeue.AccountNameEnumerationResultsHandlerTest")
|
||||
public class AccountNameEnumerationResultsHandlerTest extends BaseHandlerTest {
|
||||
|
||||
public void testApplyInputStream() {
|
||||
InputStream is = getClass().getResourceAsStream("/test_list_queues.xml");
|
||||
MetadataList<QueueMetadata> list = new MetadataList<QueueMetadata>("q", null, 3,
|
||||
ImmutableList.of(new QueueMetadata("q1", URI
|
||||
.create("http://myaccount.queue.core.windows.net/q1")), new QueueMetadata(
|
||||
"q2", URI.create("http://myaccount.queue.core.windows.net/q2")),
|
||||
new QueueMetadata("q3", URI
|
||||
.create("http://myaccount.queue.core.windows.net/q3")))
|
||||
|
||||
, "q4");
|
||||
ParseSax<MetadataList<QueueMetadata>> parser = parserFactory
|
||||
.createContainerMetadataListParser();
|
||||
MetadataList<QueueMetadata> result = parser.parse(is);
|
||||
assertEquals(result, list);
|
||||
}
|
||||
|
||||
public void testApplyInputStreamWithOptions() {
|
||||
InputStream is = getClass().getResourceAsStream("/test_list_queues_options.xml");
|
||||
MetadataList<QueueMetadata> list = new MetadataList<QueueMetadata>("q", "q4", 3,
|
||||
ImmutableList.of(new QueueMetadata("q4", URI
|
||||
.create("http://myaccount.queue.core.windows.net/q4")), new QueueMetadata(
|
||||
"q5", URI.create("http://myaccount.queue.core.windows.net/q5")))
|
||||
|
||||
, null);
|
||||
ParseSax<MetadataList<QueueMetadata>> parser = parserFactory
|
||||
.createContainerMetadataListParser();
|
||||
MetadataList<QueueMetadata> result = parser.parse(is);
|
||||
assertEquals(result, list);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.jclouds.azure.storage.queue.xml;
|
||||
|
||||
import org.jclouds.azure.storage.queue.xml.AzureQueueParserFactory;
|
||||
import org.jclouds.azure.storage.queue.xml.config.AzureQueueParserModule;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
import org.jclouds.util.DateService;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
public class BaseHandlerTest {
|
||||
|
||||
protected AzureQueueParserFactory parserFactory = null;
|
||||
protected DateService dateService = null;
|
||||
|
||||
private Injector injector;
|
||||
|
||||
@BeforeTest
|
||||
protected void setUpInjector() {
|
||||
injector = Guice.createInjector(new AzureQueueParserModule(), new ParserModule());
|
||||
parserFactory = injector.getInstance(AzureQueueParserFactory.class);
|
||||
dateService = injector.getInstance(DateService.class);
|
||||
assert parserFactory != null;
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
protected void tearDownInjector() {
|
||||
parserFactory = null;
|
||||
dateService = null;
|
||||
injector = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EnumerationResults AccountName="http://myaccount.queue.core.windows.net">
|
||||
<Prefix>q</Prefix>
|
||||
<MaxResults>3</MaxResults>
|
||||
<Queues>
|
||||
<Queue>
|
||||
<QueueName>q1</QueueName>
|
||||
<Url>http://myaccount.queue.core.windows.net/q1</Url>
|
||||
</Queue>
|
||||
<Queue>
|
||||
<QueueName>q2</QueueName>
|
||||
<Url>http://myaccount.queue.core.windows.net/q2</Url>
|
||||
</Queue>
|
||||
<Queue>
|
||||
<QueueName>q3</QueueName>
|
||||
<Url>http://myaccount.queue.core.windows.net/q3</Url>
|
||||
</Queue>
|
||||
</Queues>
|
||||
<NextMarker>q4</NextMarker>
|
||||
</EnumerationResults>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EnumerationResults AccountName="http://myaccount.queue.core.windows.net">
|
||||
<Prefix>q</Prefix>
|
||||
<Marker>q4</Marker>
|
||||
<MaxResults>3</MaxResults>
|
||||
<Queues>
|
||||
<Queue>
|
||||
<QueueName>q4</QueueName>
|
||||
<Url>http://myaccount.queue.core.windows.net/q4</Url>
|
||||
</Queue>
|
||||
<Queue>
|
||||
<QueueName>q5</QueueName>
|
||||
<Url>http://myaccount.queue.core.windows.net/q5</Url>
|
||||
</Queue>
|
||||
</Queues>
|
||||
<NextMarker />
|
||||
</EnumerationResults>
|
Loading…
Reference in New Issue