mirror of https://github.com/apache/jclouds.git
Issue 86: first command for blob service
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1876 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
36aadce94f
commit
7e9229d55e
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
* 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.blob;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadataList;
|
||||
import org.jclouds.azure.storage.blob.xml.AccountNameEnumerationResultsHandler;
|
||||
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
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 Blob via their REST API.
|
||||
* <p/>
|
||||
* All commands return a Future of the result from Azure Blob. 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 AzureBlobConnection {
|
||||
|
||||
/**
|
||||
* The List Containers operation returns a list of the containers under the specified account.
|
||||
*
|
||||
* @param listOptions
|
||||
* controls the number or type of results requested
|
||||
* @see ListOptions
|
||||
*/
|
||||
@GET
|
||||
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
|
||||
@Path("/")
|
||||
@Query(key = "comp", value = "list")
|
||||
ContainerMetadataList listContainers(ListOptions... listOptions);
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.jclouds.azure.storage.blob;
|
||||
|
||||
import org.jclouds.cloud.CloudContext;
|
||||
|
||||
/**
|
||||
* Represents an authenticated context to Cloud Files.
|
||||
*
|
||||
* @see <a href="http://www.rackspacecloud.com/cf-devguide-20090311.pdf" />
|
||||
* @see AzureBlobConnection
|
||||
* @see CloudContext
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public interface AzureBlobContext extends CloudContext<AzureBlobConnection> {
|
||||
|
||||
}
|
|
@ -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.blob;
|
||||
|
||||
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.blob.config.AzureBlobContextModule;
|
||||
import org.jclouds.azure.storage.blob.config.RestAzureBlobConnectionModule;
|
||||
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 AzureBlobContext} 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 AzureBlobContext
|
||||
*/
|
||||
public class AzureBlobContextBuilder extends
|
||||
CloudContextBuilder<AzureBlobConnection, AzureBlobContext> {
|
||||
|
||||
public AzureBlobContextBuilder(Properties props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public static AzureBlobContextBuilder newBuilder(String id, String secret) {
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.setProperty(PROPERTY_HTTP_ADDRESS, id + ".blob.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");
|
||||
|
||||
AzureBlobContextBuilder builder = new AzureBlobContextBuilder(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 AzureBlobContext buildContext() {
|
||||
return buildInjector().getInstance(AzureBlobContext.class);
|
||||
}
|
||||
|
||||
protected void addParserModule(List<Module> modules) {
|
||||
modules.add(new AzureStorageParserModule());
|
||||
}
|
||||
|
||||
protected void addContextModule(List<Module> modules) {
|
||||
modules.add(new AzureBlobContextModule());
|
||||
}
|
||||
|
||||
protected void addConnectionModule(List<Module> modules) {
|
||||
modules.add(new RestAzureBlobConnectionModule());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.jclouds.azure.storage.blob.config;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobContext;
|
||||
import org.jclouds.azure.storage.blob.internal.GuiceAzureBlobContext;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
/**
|
||||
* Configures the {@link AzureBlobContext}; requires {@link AzureBlobConnection} bound.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AzureBlobContextModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
this.requireBinding(AzureBlobConnection.class);
|
||||
bind(AzureBlobContext.class).to(GuiceAzureBlobContext.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.jclouds.azure.storage.blob.config;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
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 Blob Service connection, including logging and http transport.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresCloudConnection
|
||||
@RequiresHttp
|
||||
public class RestAzureBlobConnectionModule extends RestAzureStorageConnectionModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected AzureBlobConnection provideAzureStorageConnection(URI uri, RestClientFactory factory) {
|
||||
return factory.create(uri, AzureBlobConnection.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
*
|
||||
* 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.blob.domain;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class ContainerMetadata {
|
||||
private URI url;
|
||||
private DateTime lastModified;
|
||||
private byte[] eTag;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContainerMetadata [eTag=" + Arrays.toString(eTag) + ", lastModified=" + lastModified
|
||||
+ ", url=" + url + "]";
|
||||
}
|
||||
|
||||
public ContainerMetadata(URI url, DateTime lastModified, byte[] eTag) {
|
||||
this.url = url;
|
||||
this.lastModified = lastModified;
|
||||
this.eTag = eTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(eTag);
|
||||
result = prime * result + ((lastModified == null) ? 0 : lastModified.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;
|
||||
ContainerMetadata other = (ContainerMetadata) obj;
|
||||
if (!Arrays.equals(eTag, other.eTag))
|
||||
return false;
|
||||
if (lastModified == null) {
|
||||
if (other.lastModified != null)
|
||||
return false;
|
||||
} else if (!lastModified.equals(other.lastModified))
|
||||
return false;
|
||||
if (url == null) {
|
||||
if (other.url != null)
|
||||
return false;
|
||||
} else if (!url.equals(other.url))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public URI getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public DateTime getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public byte[] getETag() {
|
||||
return eTag;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
*
|
||||
* 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.blob.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class ContainerMetadataList {
|
||||
private int maxResults;
|
||||
private List<ContainerMetadata> containerMetadata;
|
||||
private String nextMarker;
|
||||
|
||||
public ContainerMetadataList(int maxResults, List<ContainerMetadata> containerMetadata,
|
||||
String nextMarker) {
|
||||
this.maxResults = maxResults;
|
||||
this.containerMetadata = containerMetadata;
|
||||
this.nextMarker = nextMarker;
|
||||
}
|
||||
|
||||
public int getMaxResults() {
|
||||
return maxResults;
|
||||
}
|
||||
|
||||
public List<ContainerMetadata> getContainerMetadata() {
|
||||
return containerMetadata;
|
||||
}
|
||||
|
||||
public String getNextMarker() {
|
||||
return nextMarker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((containerMetadata == null) ? 0 : containerMetadata.hashCode());
|
||||
result = prime * result + maxResults;
|
||||
result = prime * result + ((nextMarker == null) ? 0 : nextMarker.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;
|
||||
ContainerMetadataList other = (ContainerMetadataList) obj;
|
||||
if (containerMetadata == null) {
|
||||
if (other.containerMetadata != null)
|
||||
return false;
|
||||
} else if (!containerMetadata.equals(other.containerMetadata))
|
||||
return false;
|
||||
if (maxResults != other.maxResults)
|
||||
return false;
|
||||
if (nextMarker == null) {
|
||||
if (other.nextMarker != null)
|
||||
return false;
|
||||
} else if (!nextMarker.equals(other.nextMarker))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContainerMetadataList [containerMetadata=" + containerMetadata + ", maxResults="
|
||||
+ maxResults + ", nextMarker=" + nextMarker + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.jclouds.azure.storage.blob.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.jclouds.azure.storage.blob.AzureBlobConnection;
|
||||
import org.jclouds.azure.storage.blob.AzureBlobContext;
|
||||
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 AzureBlobContext methods.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see Injector
|
||||
*/
|
||||
public class GuiceAzureBlobContext implements AzureBlobContext {
|
||||
|
||||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
private final Injector injector;
|
||||
private final Closer closer;
|
||||
|
||||
@Inject
|
||||
private GuiceAzureBlobContext(Injector injector, Closer closer) {
|
||||
this.injector = injector;
|
||||
this.closer = closer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public AzureBlobConnection getConnection() {
|
||||
return injector.getInstance(AzureBlobConnection.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see Closer
|
||||
*/
|
||||
public void close() {
|
||||
try {
|
||||
closer.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e, "error closing content");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
*
|
||||
* 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.blob.xml;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadataList;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.util.DateService;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Parses the following XML document:
|
||||
* <p/>
|
||||
* EnumerationResults AccountName="http://myaccount.blob.core.windows.net"
|
||||
*
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/dd179352.aspx" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AccountNameEnumerationResultsHandler extends
|
||||
ParseSax.HandlerWithResult<ContainerMetadataList> {
|
||||
|
||||
private List<ContainerMetadata> containers = new ArrayList<ContainerMetadata>();
|
||||
private int maxResults;
|
||||
private String nextMarker;
|
||||
private URI currentUrl;
|
||||
private DateTime currentLastModified;
|
||||
private byte[] currentETag;
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
|
||||
private final DateService dateParser;
|
||||
|
||||
@Inject
|
||||
public AccountNameEnumerationResultsHandler(DateService dateParser) {
|
||||
this.dateParser = dateParser;
|
||||
}
|
||||
|
||||
public ContainerMetadataList getResult() {
|
||||
return new ContainerMetadataList(maxResults, containers, nextMarker);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (qName.equals("MaxResults")) {
|
||||
maxResults = Integer.parseInt(currentText.toString().trim());
|
||||
} else if (qName.equals("NextMarker")) {
|
||||
nextMarker = currentText.toString().trim();
|
||||
} else if (qName.equals("Container")) {
|
||||
containers.add(new ContainerMetadata(currentUrl, currentLastModified, currentETag));
|
||||
currentUrl = null;
|
||||
currentLastModified = null;
|
||||
currentETag = null;
|
||||
} else if (qName.equals("Url")) {
|
||||
currentUrl = URI.create(currentText.toString().trim());
|
||||
} else if (qName.equals("LastModified")) {
|
||||
currentLastModified = dateParser.rfc822DateParse(currentText.toString().trim());
|
||||
} else if (qName.equals("Etag")) {
|
||||
currentETag = HttpUtils.fromHexString(currentText.toString().trim());
|
||||
}
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.jclouds.azure.storage.blob.xml;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadataList;
|
||||
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 Blob 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 AzureBlobParserFactory extends AzureStorageParserFactory {
|
||||
|
||||
@Inject
|
||||
private GenericParseFactory<ContainerMetadataList> parseContainerMetadataListFactory;
|
||||
|
||||
@Inject
|
||||
Provider<AccountNameEnumerationResultsHandler> containerMetaListHandlerProvider;
|
||||
|
||||
public ParseSax<ContainerMetadataList> createContainerMetadataListParser() {
|
||||
return parseContainerMetadataListFactory.create(containerMetaListHandlerProvider.get());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.jclouds.azure.storage.blob.xml.config;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadataList;
|
||||
import org.jclouds.azure.storage.blob.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 Blob Service responses
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresResponseTransformer
|
||||
public class AzureBlobParserModule extends AzureStorageParserModule {
|
||||
protected final TypeLiteral<AzureStorageParserFactory.GenericParseFactory<ContainerMetadataList>> accountNameEnumerationResultsHandler = new TypeLiteral<AzureStorageParserFactory.GenericParseFactory<ContainerMetadataList>>() {
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void bindParserImplementationsToReturnTypes() {
|
||||
super.bindParserImplementationsToReturnTypes();
|
||||
bind(new TypeLiteral<ParseSax.HandlerWithResult<ContainerMetadataList>>() {
|
||||
}).to(AccountNameEnumerationResultsHandler.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindCallablesThatReturnParseResults() {
|
||||
super.bindCallablesThatReturnParseResults();
|
||||
bind(accountNameEnumerationResultsHandler).toProvider(
|
||||
FactoryProvider.newFactory(accountNameEnumerationResultsHandler,
|
||||
new TypeLiteral<ParseSax<ContainerMetadataList>>() {
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.jclouds.azure.storage.blob;
|
||||
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadataList;
|
||||
import org.jclouds.azure.storage.reference.AzureStorageConstants;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AzureBlobConnection}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", sequential = true, testName = "cloudservers.AzureBlobConnectionLiveTest")
|
||||
public class AzureBlobConnectionLiveTest {
|
||||
|
||||
protected static final String sysAzureStorageAccount = System
|
||||
.getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT);
|
||||
protected static final String sysAzureStorageKey = System
|
||||
.getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY);
|
||||
protected AzureBlobConnection connection;
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
public void setupConnection() {
|
||||
Injector injector = AzureBlobContextBuilder.newBuilder(sysAzureStorageAccount,
|
||||
sysAzureStorageKey).withModules(new Log4JLoggingModule()).withSaxDebug()
|
||||
.buildInjector();
|
||||
connection = injector.getInstance(AzureBlobConnection.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListContainers() throws Exception {
|
||||
|
||||
ContainerMetadataList response = connection.listContainers();
|
||||
assert null != response;
|
||||
long initialContainerCount = response.getContainerMetadata().size();
|
||||
assertTrue(initialContainerCount >= 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package org.jclouds.azure.storage.blob;
|
||||
|
||||
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.blob.xml.config.AzureBlobParserModule;
|
||||
import org.jclouds.azure.storage.options.ListOptions;
|
||||
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.rest.JaxrsAnnotationProcessor;
|
||||
import org.jclouds.rest.config.JaxrsModule;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AzureBlobConnection}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "cloudservers.AzureBlobConnectionTest")
|
||||
public class AzureBlobConnectionTest {
|
||||
|
||||
JaxrsAnnotationProcessor.Factory factory;
|
||||
|
||||
private static final Class<? extends ListOptions[]> listOptionsVarargsClass = new ListOptions[] {}
|
||||
.getClass();
|
||||
|
||||
public void testListServers() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class
|
||||
.getMethod("listContainers", 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 testListServersOptions() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AzureBlobConnection.class
|
||||
.getMethod("listContainers", 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);
|
||||
}
|
||||
|
||||
JaxrsAnnotationProcessor processor;
|
||||
|
||||
@BeforeClass
|
||||
void setupFactory() {
|
||||
factory = Guice.createInjector(
|
||||
new AzureBlobParserModule(),
|
||||
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(AzureBlobConnection.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
*
|
||||
* 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.blob.xml;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadata;
|
||||
import org.jclouds.azure.storage.blob.domain.ContainerMetadataList;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
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 = "azureblob.AccountNameEnumerationResultsHandlerTest")
|
||||
public class AccountNameEnumerationResultsHandlerTest extends BaseHandlerTest {
|
||||
|
||||
public void testApplyInputStream() {
|
||||
InputStream is = getClass().getResourceAsStream("/test_list_containers.xml");
|
||||
ContainerMetadataList list = new ContainerMetadataList(3, ImmutableList.of(
|
||||
new ContainerMetadata(URI.create("http://myaccount.blob.core.windows.net/audio"),
|
||||
dateService.rfc822DateParse("Wed, 13 Aug 2008 20:39:39 GMT"), HttpUtils
|
||||
.fromHexString("0x8CACB9BD7C6B1B2")), new ContainerMetadata(URI
|
||||
.create("http://myaccount.blob.core.windows.net/images"), dateService
|
||||
.rfc822DateParse("Wed, 14 Aug 2008 20:39:39 GMT"), HttpUtils
|
||||
.fromHexString("0x8CACB9BD7C1EEEC")), new ContainerMetadata(URI
|
||||
.create("http://myaccount.blob.core.windows.net/textfiles"), dateService
|
||||
.rfc822DateParse("Wed, 15 Aug 2008 20:39:39 GMT"), HttpUtils
|
||||
.fromHexString("0x8CACB9BD7BACAC3"))
|
||||
|
||||
), "video");
|
||||
ParseSax<ContainerMetadataList> parser = parserFactory.createContainerMetadataListParser();
|
||||
ContainerMetadataList result = parser.parse(is);
|
||||
assertEquals(result, list);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.jclouds.azure.storage.blob.xml;
|
||||
|
||||
import org.jclouds.azure.storage.blob.xml.AzureBlobParserFactory;
|
||||
import org.jclouds.azure.storage.blob.xml.config.AzureBlobParserModule;
|
||||
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 AzureBlobParserFactory parserFactory = null;
|
||||
protected DateService dateService = null;
|
||||
|
||||
private Injector injector;
|
||||
|
||||
@BeforeTest
|
||||
protected void setUpInjector() {
|
||||
injector = Guice.createInjector(new AzureBlobParserModule(), new ParserModule());
|
||||
parserFactory = injector.getInstance(AzureBlobParserFactory.class);
|
||||
dateService = injector.getInstance(DateService.class);
|
||||
assert parserFactory != null;
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
protected void tearDownInjector() {
|
||||
parserFactory = null;
|
||||
dateService = null;
|
||||
injector = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EnumerationResults AccountName=" http://myaccount.blob.core.windows.net">
|
||||
<MaxResults>3</MaxResults>
|
||||
<Containers>
|
||||
<Container>
|
||||
<Url>http://myaccount.blob.core.windows.net/audio</Url>
|
||||
<LastModified>Wed, 13 Aug 2008 20:39:39 GMT</LastModified>
|
||||
<Etag>0x8CACB9BD7C6B1B2</Etag>
|
||||
</Container>
|
||||
<Container>
|
||||
<Url>http://myaccount.blob.core.windows.net/images</Url>
|
||||
<LastModified>Wed, 14 Aug 2008 20:39:39 GMT</LastModified>
|
||||
<Etag>0x8CACB9BD7C1EEEC</Etag>
|
||||
</Container>
|
||||
<Container>
|
||||
<Url>http://myaccount.blob.core.windows.net/textfiles</Url>
|
||||
<LastModified>Wed, 15 Aug 2008 20:39:39 GMT</LastModified>
|
||||
<Etag>0x8CACB9BD7BACAC3</Etag>
|
||||
</Container>
|
||||
</Containers>
|
||||
<NextMarker>video</NextMarker>
|
||||
</EnumerationResults>
|
Loading…
Reference in New Issue