Issue 100: started support, adding upload functionality for nirvanix sdn

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1953 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-10-10 00:22:34 +00:00
parent 5b7878b0ea
commit ccd035df64
20 changed files with 978 additions and 29 deletions

View File

@ -29,9 +29,9 @@ import javax.ws.rs.QueryParam;
import org.jclouds.nirvanix.sdn.functions.ParseSessionTokenFromJsonResponse;
import org.jclouds.nirvanix.sdn.reference.SDNQueryParams;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.QueryParams;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.ResponseParser;
/**
* Provides access to Nirvanix SDN resources via their REST API.
@ -45,7 +45,7 @@ import org.jclouds.rest.ResponseParser;
public interface SDNAuthentication {
public interface AuthenticationResponse {
@Authentication
@SessionToken
String getSessionToken();
}

View File

@ -0,0 +1,89 @@
/**
*
* 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.nirvanix.sdn;
import java.net.URI;
import java.util.concurrent.Future;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import org.jclouds.blobstore.decorators.AddBlobEntityAsMultipartForm;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.nirvanix.sdn.decorators.AddMetadataAsQueryParams;
import org.jclouds.nirvanix.sdn.domain.UploadInfo;
import org.jclouds.nirvanix.sdn.filters.AddSessionTokenToRequest;
import org.jclouds.nirvanix.sdn.functions.ParseUploadInfoFromJsonResponse;
import org.jclouds.nirvanix.sdn.reference.SDNQueryParams;
import org.jclouds.rest.annotations.DecoratorParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import com.google.common.collect.Multimap;
/**
* Provides access to Nirvanix SDN resources via their REST API.
* <p/>
*
* @see <a href="http://developer.nirvanix.com/sitefiles/1000/API.html" />
* @author Adrian Cole
*/
@Endpoint(SDN.class)
@QueryParams(keys = SDNQueryParams.OUTPUT, values = "json")
@RequestFilters(AddSessionTokenToRequest.class)
@SkipEncoding( { '/', ':' })
public interface SDNConnection {
/**
* The GetStorageNode method is used to determine which storage node a file should be uploaded
* to. It returns the host to upload to and an Upload Token that will be used to authenticate.
*/
@GET
@Path("/IMFS/GetStorageNode.ashx")
@ResponseParser(ParseUploadInfoFromJsonResponse.class)
UploadInfo getStorageNode(@QueryParam(SDNQueryParams.DESTFOLDERPATH) String folderPath,
@QueryParam(SDNQueryParams.SIZEBYTES) long size);
@POST
@Path("/Upload.ashx")
Future<Void> upload(@Endpoint URI endpoint,
@QueryParam(SDNQueryParams.UPLOADTOKEN) String uploadToken,
@QueryParam(SDNQueryParams.DESTFOLDERPATH) String folderPath,
@DecoratorParam(AddBlobEntityAsMultipartForm.class) Blob<BlobMetadata> blob);
@PUT
@Path("/Metadata/SetMetadata.ashx")
@QueryParams(keys = SDNQueryParams.PATH, values = "{container}/{key}")
Future<Void> setMetadata(@PathParam("container") String container, @PathParam("key") String key,
@DecoratorParam(AddMetadataAsQueryParams.class) Multimap<String, String> metadata);
}

View File

@ -0,0 +1,16 @@
package org.jclouds.nirvanix.sdn;
import org.jclouds.cloud.CloudContext;
/**
* Represents an authenticated context to Nirvanix SDN.
*
* @see <a href="http://developer.nirvanix.com/sitefiles/1000/API.html" />
* @see SDNConnection
* @see CloudContext
* @author Adrian Cole
*
*/
public interface SDNContext extends CloudContext<SDNConnection> {
}

View File

@ -28,11 +28,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import org.jclouds.cloud.CloudContextBuilder;
import org.jclouds.nirvanix.sdn.config.RestSDNAuthenticationModule;
import org.jclouds.nirvanix.sdn.config.SDNContextModule;
import org.jclouds.nirvanix.sdn.reference.SDNConstants;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
@ -40,15 +43,16 @@ import com.google.inject.TypeLiteral;
*
* @author Adrian Cole
*/
public abstract class SDNContextBuilder<C> extends CloudContextBuilder<C> {
public class SDNContextBuilder extends CloudContextBuilder<SDNConnection> {
public SDNContextBuilder(TypeLiteral<C> defaultApiClass, String apikey, String id, String secret) {
this(defaultApiClass, new Properties());
public SDNContextBuilder(String apikey, String id, String secret) {
this(new Properties());
authenticate(this, apikey, id, secret);
}
public SDNContextBuilder(TypeLiteral<C> defaultApiClass, Properties props) {
super(defaultApiClass, props);
public SDNContextBuilder(Properties props) {
super(new TypeLiteral<SDNConnection>() {
}, props);
initialize(this);
}
@ -57,31 +61,109 @@ public abstract class SDNContextBuilder<C> extends CloudContextBuilder<C> {
addAuthenticationModule(this);
}
public static <C> void authenticate(CloudContextBuilder<C> builder, String appkey, String id,
public static void authenticate(SDNContextBuilder builder, String appkey, String id,
String secret) {
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_APPKEY, checkNotNull(appkey, "appkey"));
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_USERNAME, checkNotNull(id, "user"));
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_PASSWORD, checkNotNull(secret, "key"));
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_APPKEY,
checkNotNull(appkey, "appkey"));
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_USERNAME,
checkNotNull(id, "user"));
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_PASSWORD,
checkNotNull(secret, "key"));
}
public static <C> void initialize(CloudContextBuilder<C> builder) {
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_ENDPOINT, "http://services.nirvanix.com/ws");
public static void initialize(SDNContextBuilder builder) {
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_ENDPOINT,
"http://services.nirvanix.com/ws");
}
public static <C> void addAuthenticationModule(CloudContextBuilder<C> builder) {
public static void addAuthenticationModule(SDNContextBuilder builder) {
builder.withModule(new RestSDNAuthenticationModule());
}
public static <C> CloudContextBuilder<C> withEndpoint(CloudContextBuilder<C> builder,
URI endpoint) {
public static SDNContextBuilder withEndpoint(SDNContextBuilder builder, URI endpoint) {
builder.getProperties().setProperty(SDNConstants.PROPERTY_SDN_ENDPOINT,
checkNotNull(endpoint, "endpoint").toString());
return builder;
return (SDNContextBuilder) builder;
}
@Override
public SDNContextBuilder<C> withEndpoint(URI endpoint) {
return (SDNContextBuilder<C>) withEndpoint(this, endpoint);
public SDNContextBuilder relaxSSLHostname() {
return (SDNContextBuilder) super.relaxSSLHostname();
}
@Override
public SDNContextBuilder withExecutorService(ExecutorService service) {
return (SDNContextBuilder) super.withExecutorService(service);
}
@Override
public SDNContextBuilder withHttpMaxRedirects(int httpMaxRedirects) {
return (SDNContextBuilder) super.withHttpMaxRedirects(httpMaxRedirects);
}
@Override
public SDNContextBuilder withHttpMaxRetries(int httpMaxRetries) {
return (SDNContextBuilder) super.withHttpMaxRetries(httpMaxRetries);
}
@Override
public SDNContextBuilder withJsonDebug() {
return (SDNContextBuilder) super.withJsonDebug();
}
@Override
public SDNContextBuilder withModule(Module module) {
return (SDNContextBuilder) super.withModule(module);
}
@Override
public SDNContextBuilder withModules(Module... modules) {
return (SDNContextBuilder) super.withModules(modules);
}
@Override
public SDNContextBuilder withPoolIoWorkerThreads(int poolIoWorkerThreads) {
return (SDNContextBuilder) super.withPoolIoWorkerThreads(poolIoWorkerThreads);
}
@Override
public SDNContextBuilder withPoolMaxConnectionReuse(int poolMaxConnectionReuse) {
return (SDNContextBuilder) super.withPoolMaxConnectionReuse(poolMaxConnectionReuse);
}
@Override
public SDNContextBuilder withPoolMaxConnections(int poolMaxConnections) {
return (SDNContextBuilder) super.withPoolMaxConnections(poolMaxConnections);
}
@Override
public SDNContextBuilder withPoolMaxSessionFailures(int poolMaxSessionFailures) {
return (SDNContextBuilder) super.withPoolMaxSessionFailures(poolMaxSessionFailures);
}
@Override
public SDNContextBuilder withPoolRequestInvokerThreads(int poolRequestInvokerThreads) {
return (SDNContextBuilder) super.withPoolRequestInvokerThreads(poolRequestInvokerThreads);
}
@Override
public SDNContextBuilder withSaxDebug() {
return (SDNContextBuilder) super.withSaxDebug();
}
@Override
public SDNContextBuilder withEndpoint(URI endpoint) {
return (SDNContextBuilder) (SDNContextBuilder) withEndpoint(this, endpoint);
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new SDNContextModule());
}
@Override
public SDNContext buildContext() {
Injector injector = buildInjector();
return injector.getInstance(SDNContext.class);
}
}

View File

@ -39,6 +39,6 @@ import javax.inject.Qualifier;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface Authentication {
public @interface SessionToken {
}

View File

@ -29,11 +29,12 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.http.RequiresHttp;
import org.jclouds.nirvanix.sdn.Authentication;
import org.jclouds.nirvanix.sdn.SDN;
import org.jclouds.nirvanix.sdn.SDNAuthentication;
import org.jclouds.nirvanix.sdn.SDNConnection;
import org.jclouds.nirvanix.sdn.SessionToken;
import org.jclouds.nirvanix.sdn.reference.SDNConstants;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.JaxrsModule;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
@ -48,20 +49,19 @@ public class RestSDNAuthenticationModule extends AbstractModule {
@Override
protected void configure() {
install(new JaxrsModule());
bindErrorHandlers();
bindRetryHandlers();
}
@Provides
@Singleton
@Authentication
@SDN
protected URI provideAuthenticationURI(@Named(SDNConstants.PROPERTY_SDN_ENDPOINT) String endpoint) {
return URI.create(endpoint);
}
@Provides
@Authentication
@SessionToken
protected String provideSessionToken(RestClientFactory factory,
@Named(SDNConstants.PROPERTY_SDN_APPKEY) String appKey,
@Named(SDNConstants.PROPERTY_SDN_USERNAME) String username,
@ -69,6 +69,11 @@ public class RestSDNAuthenticationModule extends AbstractModule {
return factory.create(SDNAuthentication.class).authenticate(appKey, username, password);
}
@Provides
protected SDNConnection provideConnection(RestClientFactory factory) {
return factory.create(SDNConnection.class);
}
protected void bindErrorHandlers() {
// TODO
}

View File

@ -0,0 +1,34 @@
package org.jclouds.nirvanix.sdn.config;
import java.net.URI;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.cloud.internal.CloudContextImpl;
import org.jclouds.http.RequiresHttp;
import org.jclouds.lifecycle.Closer;
import org.jclouds.nirvanix.sdn.SDN;
import org.jclouds.nirvanix.sdn.SDNConnection;
import org.jclouds.nirvanix.sdn.SDNContext;
import org.jclouds.nirvanix.sdn.reference.SDNConstants;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
@RequiresHttp
public class SDNContextModule extends AbstractModule {
@Override
protected void configure() {
bind(SDNContext.class).to(SDNContextImpl.class).in(Scopes.SINGLETON);
}
public static class SDNContextImpl extends CloudContextImpl<SDNConnection> implements SDNContext {
@Inject
public SDNContextImpl(Closer closer, SDNConnection defaultApi, @SDN URI endPoint,
@Named(SDNConstants.PROPERTY_SDN_USERNAME) String account) {
super(closer, defaultApi, endPoint, account);
}
}
}

View File

@ -0,0 +1,39 @@
package org.jclouds.nirvanix.sdn.decorators;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map.Entry;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.rest.decorators.RequestDecorator;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
public class AddMetadataAsQueryParams implements RequestDecorator {
@SuppressWarnings("unchecked")
public HttpRequest decorateRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(input, "input") instanceof Multimap,
"this decorator is only valid for Multimaps!");
UriBuilder builder = UriBuilder.fromUri(request.getEndpoint());
Multimap<String, String> userMetadata = (Multimap<String, String>) input;
List<String> metadata = Lists.newArrayList();
for (Entry<String, String> entry : userMetadata.entries()) {
metadata.add(String.format("%s:%s", entry.getKey().toLowerCase(), entry.getValue()));
}
builder.replaceQueryParam("metadata", metadata.toArray());
List<HttpRequestFilter> oldFilters = request.getFilters();
request = new HttpRequest(request.getMethod(), builder.build(), request.getHeaders(), request
.getEntity());
request.getFilters().addAll(oldFilters);
return request;
}
}

View File

@ -0,0 +1,22 @@
package org.jclouds.nirvanix.sdn.domain;
import java.net.URI;
public class UploadInfo {
private final String token;
private final URI host;
public UploadInfo(String token, URI host) {
this.token = token;
this.host = host;
}
public String getToken() {
return token;
}
public URI getHost() {
return host;
}
}

View File

@ -0,0 +1,78 @@
package org.jclouds.nirvanix.sdn.filters;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.nirvanix.sdn.SessionToken;
import org.jclouds.nirvanix.sdn.reference.SDNQueryParams;
/**
* Adds the Session Token to the request. This will update the Session Token before 20 minutes is
* up.
*
* @author Adrian Cole
*
*/
@Singleton
public class AddSessionTokenToRequest implements HttpRequestFilter {
private final Provider<String> authTokenProvider;
public final long BILLION = 1000000000;
public final long MINUTES = 60 * BILLION;
private final AtomicReference<String> authToken;
private final AtomicLong trigger = new AtomicLong(0);
/**
* Start the time update service. Nirvanix clocks need to be 20 minutes of the session token.
* This is not performed per-request, as creation of the token is a slow, synchronized command.
*/
synchronized void updateIfTimeOut() {
if (trigger.get() - System.nanoTime() <= 0) {
createNewToken();
}
}
// this is a hotspot when submitted concurrently, so be lazy.
// session tokens expire in 20 minutes of no use, but let's be a little paraniod and go 19
public String createNewToken() {
authToken.set(authTokenProvider.get());
trigger.set(System.nanoTime() + System.nanoTime() + 19 * MINUTES);
return authToken.get();
}
public String getSessionToken() {
updateIfTimeOut();
return authToken.get();
}
@Inject
public AddSessionTokenToRequest(@SessionToken Provider<String> authTokenProvider) {
this.authTokenProvider = authTokenProvider;
authToken = new AtomicReference<String>();
}
public HttpRequest filter(HttpRequest request) throws HttpException {
UriBuilder builder = UriBuilder.fromUri(request.getEndpoint());
builder.replaceQueryParam(SDNQueryParams.SESSIONTOKEN, getSessionToken());
List<HttpRequestFilter> oldFilters = request.getFilters();
request = new HttpRequest(request.getMethod(), builder.build(), request.getHeaders(), request
.getEntity());
request.getFilters().addAll(oldFilters);
return request;
}
}

View File

@ -0,0 +1,69 @@
/**
*
* 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.nirvanix.sdn.functions;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Map;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.nirvanix.sdn.domain.UploadInfo;
import com.google.gson.Gson;
/**
* This parses the Nirvanix Upload host and token from a gson string.
*
* @see UploadInfo
* @author Adrian Cole
*/
public class ParseUploadInfoFromJsonResponse extends ParseJson<UploadInfo> {
@Inject
public ParseUploadInfoFromJsonResponse(Gson gson) {
super(gson);
}
private static class StorageNodeResponse {
Integer ResponseCode;
Map<String, String> GetStorageNode;
}
public UploadInfo apply(InputStream stream) {
try {
StorageNodeResponse response = gson.fromJson(new InputStreamReader(stream, "UTF-8"),
StorageNodeResponse.class);
if (response.ResponseCode == null || response.ResponseCode != 0)
throw new RuntimeException("bad response code: " + response.ResponseCode);
return new UploadInfo(response.GetStorageNode.get("UploadToken"),
URI.create("https://" + response.GetStorageNode.get("UploadHost")));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -35,4 +35,9 @@ public interface SDNQueryParams {
public static final String PASSWORD = "password";
public static final String APPKEY = "appKey";
public static final String OUTPUT = "output";
public static final String SESSIONTOKEN = "sessionToken";
public static final String DESTFOLDERPATH = "destFolderPath";
public static final String PATH = "path";
public static final String SIZEBYTES = "sizeBytes";
public static final String UPLOADTOKEN = "uploadToken";
}

View File

@ -36,7 +36,7 @@ import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.rest.config.RestModule;
import org.jclouds.util.Jsr330;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ -82,7 +82,7 @@ public class SDNAuthenticationLiveTest {
protected SDNAuthentication provideCloud(RestClientFactory factory) {
return factory.create(SDNAuthentication.class);
}
}, new JaxrsModule(), new Log4JLoggingModule(), new ExecutorServiceModule(
}, new RestModule(), new Log4JLoggingModule(), new ExecutorServiceModule(
new WithinThreadExecutorService()), new JavaUrlHttpCommandExecutorServiceModule());
}
}

View File

@ -0,0 +1,89 @@
/**
*
* 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.nirvanix.sdn;
import static org.testng.Assert.assertEquals;
import java.lang.reflect.Method;
import java.net.URI;
import javax.ws.rs.HttpMethod;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.nirvanix.sdn.functions.ParseSessionTokenFromJsonResponse;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code JaxrsAnnotationProcessor}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "sdn.SDNAuthentication")
public class SDNAuthenticationTest {
private RestAnnotationProcessor<SDNAuthentication> processor;
public void testAuthenticate() throws SecurityException, NoSuchMethodException {
Method method = SDNAuthentication.class.getMethod("authenticate", String.class, String.class,
String.class);
HttpRequest httpMethod = processor.createRequest(method,
new Object[] { "apple", "foo", "bar" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/Authentication/Login.ashx");
assertEquals(httpMethod.getEndpoint().getQuery(),
"output=json&password=bar&username=foo&appKey=apple");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(RestAnnotationProcessor.getParserOrThrowException(method),
ParseSessionTokenFromJsonResponse.class);
}
@BeforeClass
void setupFactory() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(SDN.class)
.toInstance(URI.create("http://localhost:8080"));
}
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<RestAnnotationProcessor<SDNAuthentication>>() {
}));
}
}

View File

@ -0,0 +1,59 @@
package org.jclouds.nirvanix.sdn;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertNotNull;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.nirvanix.sdn.domain.UploadInfo;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
/**
* Tests behavior of {@code SDNConnection}
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "sdn.SDNConnectionLiveTest")
public class SDNConnectionLiveTest {
protected SDNConnection connection;
private String containerPrefix = BaseBlobStoreIntegrationTest.CONTAINER_PREFIX;
URI container1;
URI container2;
@BeforeGroups(groups = { "live" })
public void setupConnection() {
String app = checkNotNull(System.getProperty("jclouds.test.app"), "jclouds.test.app");
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
connection = new SDNContextBuilder(app, user, password).withModules(new Log4JLoggingModule())
.withJsonDebug().buildContext().getApi();
}
public void testUploadToken() throws InterruptedException, ExecutionException, TimeoutException {
String containerName = containerPrefix + ".testObjectOperations";
long size = 1024;
UploadInfo uploadInfo = connection.getStorageNode(containerName, size);
assertNotNull(uploadInfo.getHost());
assertNotNull(uploadInfo.getToken());
connection.upload(uploadInfo.getHost(), uploadInfo.getToken(), "container",
new Blob<BlobMetadata>("key", "value")).get(30, TimeUnit.SECONDS);
// Multimap<String, String> metadata = ImmutableMultimap.of("chef", "sushi");
// who knows... 403 error; connection.setMetadata("container", "key", metadata).get(30, TimeUnit.SECONDS);
}
}

View File

@ -0,0 +1,148 @@
/**
*
* 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.nirvanix.sdn;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.decorators.AddBlobEntityAsMultipartFormTest;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.nirvanix.sdn.functions.ParseUploadInfoFromJsonResponse;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code JaxrsAnnotationProcessor}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "sdn.SDNConnection")
public class SDNConnectionTest {
private RestAnnotationProcessor<SDNConnection> processor;
public void testGetStorageNode() throws SecurityException, NoSuchMethodException {
Method method = SDNConnection.class.getMethod("getStorageNode", String.class, long.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "adriansmovies",
734859264 });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/IMFS/GetStorageNode.ashx");
assertEquals(httpMethod.getEndpoint().getQuery(),
"output=json&sizeBytes=734859264&destFolderPath=adriansmovies");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(RestAnnotationProcessor.getParserOrThrowException(method),
ParseUploadInfoFromJsonResponse.class);
}
public void testUpload() throws SecurityException, NoSuchMethodException, IOException {
Method method = SDNConnection.class.getMethod("upload", URI.class, String.class,
String.class, Blob.class);
Blob<BlobMetadata> blob = AddBlobEntityAsMultipartFormTest.TEST_BLOB;
HttpRequest httpMethod = processor.createRequest(method, new Object[] {
URI.create("http://uploader"), "token", "adriansmovies", blob });
assertEquals(httpMethod.getEndpoint().getHost(), "uploader");
assertEquals(httpMethod.getEndpoint().getPath(), "/Upload.ashx");
assertEquals(httpMethod.getEndpoint().getQuery(),
"output=json&uploadToken=token&destFolderPath=adriansmovies");
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(AddBlobEntityAsMultipartFormTest.EXPECTS.length() + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("multipart/form-data; boundary="
+ AddBlobEntityAsMultipartFormTest.BOUNDRY));
assertEquals(Utils.toStringAndClose((InputStream) httpMethod.getEntity()),
AddBlobEntityAsMultipartFormTest.EXPECTS);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnVoidIf2xx.class);
}
public void testSetMetadata() throws SecurityException, NoSuchMethodException, IOException {
Method method = SDNConnection.class.getMethod("setMetadata", String.class, String.class,
Multimap.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "adriansmovies",
"sushi.avi", ImmutableMultimap.of("Chef", "Kawasaki") });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/Metadata/SetMetadata.ashx");
assertEquals(httpMethod.getEndpoint().getQuery(),
"output=json&path=adriansmovies/sushi.avi&metadata=chef:Kawasaki");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(0 + ""));
assertEquals(httpMethod.getEntity(), null);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnVoidIf2xx.class);
}
@BeforeClass
void setupFactory() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(SDN.class)
.toInstance(URI.create("http://localhost:8080"));
}
@SuppressWarnings("unused")
@SessionToken
@Provides
String authTokenProvider() {
return "session-token";
}
}, new RestModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<RestAnnotationProcessor<SDNConnection>>() {
}));
}
}

View File

@ -0,0 +1,49 @@
package org.jclouds.nirvanix.sdn.decorators;
import static org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.ext.RuntimeDelegate;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.internal.RuntimeDelegateImpl;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
/**
* Tests behavior of {@code AddMetadataAsQueryParams}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "sdn.AddMetadataAsQueryParamsTest")
public class AddMetadataAsQueryParamsTest {
static {
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustBeMap() {
AddMetadataAsQueryParams binder = new AddMetadataAsQueryParams();
HttpRequest request = new HttpRequest(HttpMethod.POST, URI.create("http://localhost"));
request = binder.decorateRequest(request, new File("foo"));
}
@Test
public void testCorrect() {
AddMetadataAsQueryParams binder = new AddMetadataAsQueryParams();
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("http://localhost"));
request = binder.decorateRequest(request, ImmutableMultimap.of("imageName", "foo", "serverId", "2") );
assertEquals(request.getEndpoint().getQuery(), "metadata=imagename:foo&metadata=serverid:2");
}
@Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class })
public void testNullIsBad() {
AddMetadataAsQueryParams binder = new AddMetadataAsQueryParams();
HttpRequest request = new HttpRequest(HttpMethod.PUT, URI.create("http://localhost"));
request = binder.decorateRequest(request,null );
}
}

View File

@ -0,0 +1,102 @@
/**
*
* 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.nirvanix.sdn.filters;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.ext.RuntimeDelegate;
import org.jclouds.http.HttpRequest;
import org.jclouds.nirvanix.sdn.SessionToken;
import org.jclouds.rest.internal.RuntimeDelegateImpl;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provides;
@Test(groups = "unit", testName = "sdn.AddSessionTokenToRequestTest")
public class AddSessionTokenToRequestTest {
private Injector injector;
private AddSessionTokenToRequest filter;
@DataProvider
public Object[][] dataProvider() {
return new Object[][] { { new HttpRequest(HttpMethod.GET, URI.create("https://host:443")) },
{ new HttpRequest(HttpMethod.GET, URI.create("https://host/path")) },
{ new HttpRequest(HttpMethod.GET, URI.create("https://host/?query"))
} };
}
@Test(dataProvider = "dataProvider")
public void testRequests(HttpRequest request) {
String token = filter.getSessionToken();
String query = request.getEndpoint().getQuery();
request = filter.filter(request);
assertEquals(request.getEndpoint().getQuery(), query == null ? "sessionToken=" + token
: query + "&sessionToken=" + token);
}
@Test
void testUpdatesOnlyOncePerSecond() throws NoSuchMethodException, InterruptedException {
String token = filter.getSessionToken();
for (int i = 0; i < 10; i++)
filter.updateIfTimeOut();
assert token.equals(filter.getSessionToken());
}
/**
* before class, as we need to ensure that the filter is threadsafe.
*
*/
@BeforeClass
protected void createFilter() {
injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
bind(DateService.class);
}
@SuppressWarnings("unused")
@SessionToken
@Provides
String authTokenProvider() {
return System.currentTimeMillis() + "";
}
});
filter = injector.getInstance(AddSessionTokenToRequest.class);
}
}

View File

@ -0,0 +1,62 @@
/**
*
* 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.nirvanix.sdn.functions;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.net.UnknownHostException;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.nirvanix.sdn.domain.UploadInfo;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseUploadInfoFromJsonResponse}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "sdn.ParseUploadInfoFromJsonResponse")
public class ParseUploadInfoFromJsonResponseTest {
Injector i = Guice.createInjector(new ParserModule());
DateService dateService = new DateService();
public void testApplyInputStreamDetails() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/authtoken.json");
ParseUploadInfoFromJsonResponse parser = new ParseUploadInfoFromJsonResponse(i
.getInstance(Gson.class));
UploadInfo response = parser.apply(is);
assertEquals(response.getHost(), URI.create("https://node1.nirvanix.com"));
assertEquals(response.getToken(), "siR-ALYd~BEcJ8GR2tE~oX3SEHO8~2WXKT5xjFk~YLS5OvJyHI21TN34rQ");
}
}

View File

@ -0,0 +1 @@
{"ResponseCode":0,"GetStorageNode":{"UploadHost":"node1.nirvanix.com","UploadToken":"siR-ALYd~BEcJ8GR2tE~oX3SEHO8~2WXKT5xjFk~YLS5OvJyHI21TN34rQ"}}