diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueConnection.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueConnection.java new file mode 100644 index 0000000000..da3f821e67 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueConnection.java @@ -0,0 +1,123 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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. + *

+ * The Queue service stores messages that may be read by any client who has access to the storage + * account. + *

+ * 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. + *

+ * 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. + *

+ * 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 + * @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. + *

+ * 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 listQueues(ListOptions... listOptions); + + /** + * The Create Queue operation creates a new queue under the specified account. + *

+ * You can specify user-defined metadata as name-value pairs on the queue at the time that it is + * created. + *

+ * 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. + *

+ * 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. + * + *

+ * 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); + +} diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueContext.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueContext.java new file mode 100644 index 0000000000..510db9c725 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueContext.java @@ -0,0 +1,16 @@ +package org.jclouds.azure.storage.queue; + +import org.jclouds.cloud.CloudContext; + +/** + * Represents an authenticated context to Azure Queue Service. + * + * @see + * @see AzureQueueConnection + * @see CloudContext + * @author Adrian Cole + * + */ +public interface AzureQueueContext extends CloudContext { + +} \ No newline at end of file diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueContextBuilder.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueContextBuilder.java new file mode 100755 index 0000000000..49a25e6d79 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/AzureQueueContextBuilder.java @@ -0,0 +1,114 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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. + *

+ * Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. + *

+ *

+ * If no Modules 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 { + + 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 modules) { + modules.add(new AzureStorageParserModule()); + } + + protected void addContextModule(List modules) { + modules.add(new AzureQueueContextModule()); + } + + protected void addConnectionModule(List modules) { + modules.add(new RestAzureQueueConnectionModule()); + } + +} diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/config/AzureQueueContextModule.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/config/AzureQueueContextModule.java new file mode 100644 index 0000000000..ecc3563c96 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/config/AzureQueueContextModule.java @@ -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); + } + +} diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/config/RestAzureQueueConnectionModule.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/config/RestAzureQueueConnectionModule.java new file mode 100644 index 0000000000..323b6a2273 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/config/RestAzureQueueConnectionModule.java @@ -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); + } + +} \ No newline at end of file diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/domain/QueueMetadata.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/domain/QueueMetadata.java new file mode 100755 index 0000000000..adf4436693 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/domain/QueueMetadata.java @@ -0,0 +1,86 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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; + } + +} diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/internal/GuiceAzureQueueContext.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/internal/GuiceAzureQueueContext.java new file mode 100644 index 0000000000..f9e45ca952 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/internal/GuiceAzureQueueContext.java @@ -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"); + } + } + +} diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/AccountNameEnumerationResultsHandler.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/AccountNameEnumerationResultsHandler.java new file mode 100755 index 0000000000..d51506c2fb --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/AccountNameEnumerationResultsHandler.java @@ -0,0 +1,92 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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: + *

+ * EnumerationResults AccountName="http://myaccount.queue.core.windows.net" + * + * @see + * @author Adrian Cole + */ +public class AccountNameEnumerationResultsHandler extends + ParseSax.HandlerWithResult> { + + private List metadata = new ArrayList(); + 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 getResult() { + return new MetadataList(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); + } +} diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/AzureQueueParserFactory.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/AzureQueueParserFactory.java new file mode 100644 index 0000000000..1bae214097 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/AzureQueueParserFactory.java @@ -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> parseContainerMetadataListFactory; + + @Inject + Provider containerMetaListHandlerProvider; + + public ParseSax> createContainerMetadataListParser() { + return parseContainerMetadataListFactory.create(containerMetaListHandlerProvider.get()); + } +} \ No newline at end of file diff --git a/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/config/AzureQueueParserModule.java b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/config/AzureQueueParserModule.java new file mode 100644 index 0000000000..c9844e2b76 --- /dev/null +++ b/azure/storage/queue/core/src/main/java/org/jclouds/azure/storage/queue/xml/config/AzureQueueParserModule.java @@ -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>> accountNameEnumerationResultsHandler = new TypeLiteral>>() { + }; + + @Override + protected void bindParserImplementationsToReturnTypes() { + super.bindParserImplementationsToReturnTypes(); + bind(new TypeLiteral>>() { + }).to(AccountNameEnumerationResultsHandler.class); + } + + @Override + protected void bindCallablesThatReturnParseResults() { + super.bindCallablesThatReturnParseResults(); + bind(accountNameEnumerationResultsHandler).toProvider( + FactoryProvider.newFactory(accountNameEnumerationResultsHandler, + new TypeLiteral>>() { + })); + } + +} \ No newline at end of file diff --git a/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/AzureQueueConnectionLiveTest.java b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/AzureQueueConnectionLiveTest.java new file mode 100644 index 0000000000..3e5fea268f --- /dev/null +++ b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/AzureQueueConnectionLiveTest.java @@ -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 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 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 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 + } + +} diff --git a/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/AzureQueueConnectionTest.java b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/AzureQueueConnectionTest.java new file mode 100644 index 0000000000..1f17d1b69b --- /dev/null +++ b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/AzureQueueConnectionTest.java @@ -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 listOptionsVarargsClass = new ListOptions[] {} + .getClass(); + private static final Class 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); + } + +} diff --git a/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/xml/AccountNameEnumerationResultsHandlerTest.java b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/xml/AccountNameEnumerationResultsHandlerTest.java new file mode 100644 index 0000000000..375c72ddb3 --- /dev/null +++ b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/xml/AccountNameEnumerationResultsHandlerTest.java @@ -0,0 +1,75 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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 list = new MetadataList("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> parser = parserFactory + .createContainerMetadataListParser(); + MetadataList result = parser.parse(is); + assertEquals(result, list); + } + + public void testApplyInputStreamWithOptions() { + InputStream is = getClass().getResourceAsStream("/test_list_queues_options.xml"); + MetadataList list = new MetadataList("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> parser = parserFactory + .createContainerMetadataListParser(); + MetadataList result = parser.parse(is); + assertEquals(result, list); + } +} diff --git a/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/xml/BaseHandlerTest.java b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/xml/BaseHandlerTest.java new file mode 100644 index 0000000000..84ab104976 --- /dev/null +++ b/azure/storage/queue/core/src/test/java/org/jclouds/azure/storage/queue/xml/BaseHandlerTest.java @@ -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; + } + +} \ No newline at end of file diff --git a/azure/storage/queue/core/src/test/resources/test_list_queues.xml b/azure/storage/queue/core/src/test/resources/test_list_queues.xml new file mode 100644 index 0000000000..5b17209c1e --- /dev/null +++ b/azure/storage/queue/core/src/test/resources/test_list_queues.xml @@ -0,0 +1,20 @@ + + + q + 3 + + + q1 + http://myaccount.queue.core.windows.net/q1 + + + q2 + http://myaccount.queue.core.windows.net/q2 + + + q3 + http://myaccount.queue.core.windows.net/q3 + + + q4 + \ No newline at end of file diff --git a/azure/storage/queue/core/src/test/resources/test_list_queues_options.xml b/azure/storage/queue/core/src/test/resources/test_list_queues_options.xml new file mode 100644 index 0000000000..46affdd4fa --- /dev/null +++ b/azure/storage/queue/core/src/test/resources/test_list_queues_options.xml @@ -0,0 +1,17 @@ + + + q + q4 + 3 + + + q4 + http://myaccount.queue.core.windows.net/q4 + + + q5 + http://myaccount.queue.core.windows.net/q5 + + + + \ No newline at end of file