Issue 830: initial vCloud 1.5 with session functionality complete

This commit is contained in:
Adrian Cole 2012-02-05 21:55:39 -08:00
parent edbd09b984
commit 1905615c49
33 changed files with 2458 additions and 0 deletions

View File

@ -61,6 +61,9 @@ opscodeplatform.propertiesbuilder=org.jclouds.opscodeplatform.OpscodePlatformPro
vcloud.contextbuilder=org.jclouds.vcloud.VCloudContextBuilder
vcloud.propertiesbuilder=org.jclouds.vcloud.VCloudPropertiesBuilder
vcloud-director.contextbuilder=org.jclouds.vcloud.director.v1_5.VCloudDirectorContextBuilder
vcloud-director.propertiesbuilder=org.jclouds.vcloud.director.v1_5.VCloudDirectorPropertiesBuilder
eucalyptus.contextbuilder=org.jclouds.ec2.EC2ContextBuilder
eucalyptus.propertiesbuilder=org.jclouds.eucalyptus.EucalyptusPropertiesBuilder

View File

@ -34,5 +34,6 @@
<modules>
<module>openstack-nova</module>
<module>virtualbox</module>
<module>vcloud-director</module>
</modules>
</project>

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.5.0-SNAPSHOT</version>
<relativePath>../../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds.labs</groupId>
<artifactId>vcloud-director</artifactId>
<name>jcloud vcloud-director api</name>
<description>jclouds components to access an implementation of VMware vCloud Director 1.5+</description>
<packaging>bundle</packaging>
<properties>
<test.vcloud-director.endpoint>https://vcloudbeta.bluelock.com/api</test.vcloud-director.endpoint>
<test.vcloud-director.api-version>1.5</test.vcloud-director.api-version>
<test.vcloud-director.build-version>1.5.0.464915</test.vcloud-director.build-version>
<test.vcloud-director.identity>FIXME_USERNAME_WHICH_MIGHT_BE_EMAIL@JClouds</test.vcloud-director.identity>
<test.vcloud-director.credential>FIXME_PASSWORD</test.vcloud-director.credential>
<test.vcloud-director.image-id></test.vcloud-director.image-id>
<test.vcloud-director.image.login-user></test.vcloud-director.image.login-user>
<test.vcloud-director.image.authenticate-sudo></test.vcloud-director.image.authenticate-sudo>
</properties>
<dependencies>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-sshj</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.29</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.vcloud-director.endpoint>${test.vcloud-director.endpoint}</test.vcloud-director.endpoint>
<test.vcloud-director.api-version>${test.vcloud-director.api-version}</test.vcloud-director.api-version>
<test.vcloud-director.build-version>${test.vcloud-director.build-version}</test.vcloud-director.build-version>
<test.vcloud-director.identity>${test.vcloud-director.identity}</test.vcloud-director.identity>
<test.vcloud-director.credential>${test.vcloud-director.credential}</test.vcloud-director.credential>
<test.vcloud-director.image-id>${test.vcloud-director.image-id}</test.vcloud-director.image-id>
<test.vcloud-director.image.login-user>${test.vcloud-director.image.login-user}</test.vcloud-director.image.login-user>
<test.vcloud-director.image.authenticate-sudo>${test.vcloud-director.image.authenticate-sudo}</test.vcloud-director.image.authenticate-sudo>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>org.jclouds.vcloud.director.v1_5.*;version="${project.version}"</Export-Package>
<Import-Package>
org.jclouds.compute.internal;version="${project.version}",
org.jclouds.rest.internal;version="${project.version}",
org.jclouds.*;version="${project.version}",
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,41 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import com.google.inject.Provides;
/**
* Provides asynchronous access to VCloudDirector via their REST API.
* <p/>
*
* @see VCloudDirectorClient
* @author Adrian Cole
*/
public interface VCloudDirectorAsyncClient {
/**
*
* @return the current login session
*/
@Provides
Session getCurrentSession();
}

View File

@ -0,0 +1,44 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import com.google.inject.Provides;
/**
* Provides synchronous access to VCloudDirector.
* <p/>
*
* @see VCloudDirectorAsyncClient
* @author Adrian Cole
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface VCloudDirectorClient {
/**
*
* @return the current login session
*/
@Provides
Session getCurrentSession();
}

View File

@ -0,0 +1,44 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5;
import java.util.List;
import java.util.Properties;
import org.jclouds.vcloud.director.v1_5.config.VCloudDirectorRestClientModule;
import org.jclouds.rest.RestContextBuilder;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
public class VCloudDirectorContextBuilder extends RestContextBuilder<VCloudDirectorClient, VCloudDirectorAsyncClient> {
public VCloudDirectorContextBuilder(Properties props) {
super(VCloudDirectorClient.class, VCloudDirectorAsyncClient.class, props);
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new VCloudDirectorRestClientModule());
}
}

View File

@ -0,0 +1,37 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5;
import javax.ws.rs.core.MediaType;
/**
* Resource Types used in VCloud
*
* <br/>
* The object type, specified as a MIME content type, of the object that the link references. This
* attribute is present only for links to objects. It is not present for links to actions.
*
* @see MediaType
*/
public interface VCloudDirectorMediaType {
public final static String NS = "http://www.vmware.com/vcloud/v1.5";
public final static String SESSION_XML = "application/vnd.vmware.vcloud.session+xml";
}

View File

@ -0,0 +1,48 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import java.util.Properties;
import org.jclouds.PropertiesBuilder;
/**
* Builds properties used in VCloudDirector Clients
*
* @author Adrian Cole
*/
public class VCloudDirectorPropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ENDPOINT, "http://localhost/api");
properties.setProperty(PROPERTY_SESSION_INTERVAL, 30*60 + "");
properties.setProperty(PROPERTY_API_VERSION, "1.5");
return properties;
}
public VCloudDirectorPropertiesBuilder(Properties properties) {
super(properties);
}
}

View File

@ -0,0 +1,21 @@
package org.jclouds.vcloud.director.v1_5.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* The login url for the vCloud, typically {@code https://vdc_host/api/sessions}
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.PARAMETER })
@Qualifier
public @interface Login {
}

View File

@ -0,0 +1,21 @@
package org.jclouds.vcloud.director.v1_5.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* relating to the current session on the vCloud
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.PARAMETER })
@Qualifier
public @interface Session {
}

View File

@ -0,0 +1,63 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.binders;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.MapBinder;
import com.google.common.base.Throwables;
/**
* Uses Basic Authentication to sign the request.
*
* @see <a href= "http://en.wikipedia.org/wiki/Basic_access_authentication" />
* @author Adrian Cole
*
*/
@Singleton
public class BindUserOrgAndPasswordAsBasicAuthorizationHeader implements MapBinder {
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
try {
String header = "Basic "
+ CryptoStreams.base64(String.format("%s@%s:%s", checkNotNull(postParams.get("user"), "user"),
checkNotNull(postParams.get("org"), "org"),
checkNotNull(postParams.get("password"), "password")).getBytes("UTF-8"));
return ModifyRequest.replaceHeader(request, HttpHeaders.AUTHORIZATION, header);
} catch (UnsupportedEncodingException e) {
throw Throwables.propagate(e);
}
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,171 @@
/**
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.config;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.jclouds.Constants;
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.location.Provider;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorAsyncClient;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient;
import org.jclouds.vcloud.director.v1_5.annotations.Login;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.jclouds.vcloud.director.v1_5.functions.LoginUserInOrgWithPassword;
import org.jclouds.vcloud.director.v1_5.handlers.InvalidateSessionAndRetryOn401AndLogoutOnClose;
import org.jclouds.vcloud.director.v1_5.handlers.VCloudDirectorErrorHandler;
import org.jclouds.vcloud.director.v1_5.login.SessionAsyncClient;
import org.jclouds.vcloud.director.v1_5.login.SessionClient;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
/**
* Configures the VCloudDirector connection.
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class VCloudDirectorRestClientModule extends RestClientModule<VCloudDirectorClient, VCloudDirectorAsyncClient> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
// TODO
.build();
public VCloudDirectorRestClientModule() {
super(VCloudDirectorClient.class, VCloudDirectorAsyncClient.class, DELEGATE_MAP);
}
@Override
protected void configure() {
// session client is used directly for filters and retry handlers, so let's bind it explicitly
bindClientAndAsyncClient(binder(), SessionClient.class, SessionAsyncClient.class);
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
InvalidateSessionAndRetryOn401AndLogoutOnClose.class);
super.configure();
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(VCloudDirectorErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(VCloudDirectorErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(VCloudDirectorErrorHandler.class);
}
@Provides
@Login
protected Supplier<URI> loginUrl(@Provider Supplier<URI> provider) {
// TODO: technically, we should implement version client, but this will work
return Suppliers.compose(new Function<URI, URI>() {
@Override
public URI apply(URI arg0) {
return URI.create(arg0.toASCIIString() + "/sessions");
}
}, provider);
}
@Provides
protected Supplier<Session> currentSession(Supplier<SessionWithToken> in) {
return Suppliers.compose(new Function<SessionWithToken, Session>() {
@Override
public Session apply(SessionWithToken arg0) {
return arg0.getSession();
}
}, in);
}
@Provides
@Singleton
@org.jclouds.vcloud.director.v1_5.annotations.Session
protected Supplier<String> sessionToken(Supplier<SessionWithToken> in) {
return Suppliers.compose(new Function<SessionWithToken, String>() {
@Override
public String apply(SessionWithToken arg0) {
return arg0.getToken();
}
}, in);
}
@Provides
@Singleton
protected Function<Credentials, SessionWithToken> makeSureFilterRetriesOnTimeout(
LoginUserInOrgWithPassword loginWithPasswordCredentials) {
// we should retry on timeout exception logging in.
return new RetryOnTimeOutExceptionFunction<Credentials, SessionWithToken>(loginWithPasswordCredentials);
}
@Provides
@Singleton
public LoadingCache<Credentials, SessionWithToken> provideSessionWithTokenCache(
Function<Credentials, SessionWithToken> getSessionWithToken,
@Named(Constants.PROPERTY_SESSION_INTERVAL) int seconds) {
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(
CacheLoader.from(getSessionWithToken));
}
// Temporary conversion of a cache to a supplier until there is a single-element cache
// http://code.google.com/p/guava-libraries/issues/detail?id=872
@Provides
@Singleton
protected Supplier<SessionWithToken> provideSessionWithTokenSupplier(
final LoadingCache<Credentials, SessionWithToken> cache, @Provider final Credentials creds) {
return new Supplier<SessionWithToken>() {
@Override
public SessionWithToken get() {
try {
return cache.get(creds);
} catch (ExecutionException e) {
throw propagate(e.getCause());
}
}
};
}
}

View File

@ -0,0 +1,124 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.domain;
import static com.google.common.base.Objects.equal;
import java.net.URI;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* Location of a Rest resource <xs:complexType name="ReferenceType">
*
* @author Adrian Cole
*
*/
public class BaseNamedResource<T extends BaseNamedResource<T>> extends BaseResource<T> {
public static <T extends BaseNamedResource<T>> Builder<T> builder() {
return new Builder<T>();
}
public Builder<T> toBuilder() {
return new Builder<T>().fromNamedResource(this);
}
public static class Builder<T extends BaseNamedResource<T>> extends BaseResource.Builder<T> {
protected String name;
/**
* @see BaseNamedResource#getName
*/
public Builder<T> name(String name) {
this.name = name;
return this;
}
public BaseNamedResource<T> build() {
return new BaseNamedResource<T>(href, type, name);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public Builder<T> fromBaseResource(BaseResource<T> in) {
return Builder.class.cast(super.fromBaseResource(in));
}
public Builder<T> fromNamedResource(BaseNamedResource<T> in) {
return fromBaseResource(in).name(in.getName());
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public Builder<T> fromAttributes(Map<String, String> attributes) {
return Builder.class.cast(super.fromAttributes(attributes)).name(attributes.get("name"));
}
}
@XmlAttribute
protected String name;
protected BaseNamedResource(URI href, String type, String name) {
super(href, type);
this.name = name;
}
protected BaseNamedResource() {
// For JAXB
}
/**
* The name of the referenced object, taken from the value of that object's name attribute.
* Action links do not include a name attribute.
*
* @return name;
*/
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (!super.equals(o))
return false;
BaseNamedResource<?> that = BaseNamedResource.class.cast(o);
return equal(name, that.name);
}
@Override
public int hashCode() {
return super.hashCode() + Objects.hashCode(name);
}
@Override
public ToStringHelper string() {
return super.string().add("name", name);
}
}

View File

@ -0,0 +1,152 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.domain;
import static com.google.common.base.Objects.equal;
import java.net.URI;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* Location of a Rest resource
*
* @author Adrian Cole
*
*/
public class BaseResource<T extends BaseResource<T>> {
public static <T extends BaseResource<T>> Builder<T> builder() {
return new Builder<T>();
}
public Builder<T> toBuilder() {
return new Builder<T>().fromBaseResource(this);
}
public static class Builder<T extends BaseResource<T>> {
protected String type;
protected URI href;
/**
* @see BaseResource#getType
*/
public Builder<T> type(String type) {
this.type = type;
return this;
}
/**
* @see BaseResource#getHref
*/
public Builder<T> href(URI href) {
this.href = href;
return this;
}
public BaseResource<T> build() {
return new BaseResource<T>(href, type);
}
protected Builder<T> fromBaseResource(BaseResource<T> in) {
return type(in.getType()).href(in.getHref());
}
protected Builder<T> fromAttributes(Map<String, String> attributes) {
return href(URI.create(attributes.get("href"))).type(attributes.get("type"));
}
}
@XmlAttribute
protected String type;
@XmlAttribute
protected URI href;
protected BaseResource(URI href, String type) {
this.type = type;
this.href = href;
}
protected BaseResource() {
// For JAXB
}
/**
* The object type, specified as a MIME content type, of the object that the link references.
* This attribute is present only for links to objects. It is not present for links to actions.
*
* @return type definition, type, expressed as an HTTP Content-Type
*/
public String getType() {
return type;
}
/**
* An object reference, expressed in URL format. Because this URL includes the object identifier
* portion of the id attribute value, it uniquely identifies the object, persists for the life of
* the object, and is never reused. The value of the href attribute is a reference to a view of
* the object, and can be used to access a representation of the object that is valid in a
* particular context. Although URLs have a well-known syntax and a well-understood
* interpretation, a client should treat each href as an opaque string. The rules that govern how
* the server constructs href strings might change in future releases.
*
* @return an opaque reference and should never be parsed
*/
public URI getHref() {
return href;
}
/**
* @see #getHref
*/
public URI getURI() {
return getHref();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
BaseResource<?> that = BaseResource.class.cast(o);
return equal(href, that.href) && equal(type, that.type);
}
@Override
public int hashCode() {
return Objects.hashCode(type, href);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper("").add("href", href).add("type", type);
}
}

View File

@ -0,0 +1,148 @@
package org.jclouds.vcloud.director.v1_5.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* <xs:complexType name="LinkType">
*
* @author Adrian Cole
*
*/
public class Link extends BaseNamedResource<Link> {
@SuppressWarnings("unchecked")
public static Builder builder() {
return new Builder();
}
/**
* {@inheritDoc}
*/
@Override
public Builder toBuilder() {
return new Builder().fromLink(this);
}
public static class Builder extends BaseNamedResource.Builder<Link> {
protected String rel;
/**
* @see Link#getString
*/
public Builder rel(String rel) {
this.rel = rel;
return this;
}
@Override
public Link build() {
return new Link(href, type, name, rel);
}
public Builder fromLink(Link in) {
return fromNamedResource(in).rel(in.getRel());
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromBaseResource(BaseResource<Link> in) {
return Builder.class.cast(super.fromBaseResource(in));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromNamedResource(BaseNamedResource<Link> in) {
return Builder.class.cast(super.fromNamedResource(in));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder href(URI href) {
return Builder.class.cast(super.href(href));
}
/**
* {@inheritDoc}
*/
@Override
public Builder type(String type) {
return Builder.class.cast(super.type(type));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromAttributes(Map<String, String> attributes) {
super.fromAttributes(attributes);
rel(attributes.get("rel"));
return this;
}
}
@XmlAttribute
protected String rel;
private Link(URI href, String type, String name, String rel) {
super(href, type, name);
this.rel = checkNotNull(rel, "rel");
}
private Link() {
// For JAXB
}
/**
* Defines the relationship of the link to the object that contains it. A relationship can be the
* name of an operation on the object, a reference to a contained or containing object, or a
* reference to an alternate representation of the object. The relationship value implies the
* HTTP verb to use when you use the link's href value as a request URL.
*
* @return relationship of the link to the object that contains it.
*/
public String getRel() {
return rel;
}
@Override
public boolean equals(Object o) {
if (!super.equals(o))
return false;
Link that = (Link) o;
return equal(this.rel, that.rel);
}
@Override
public int hashCode() {
return super.hashCode() + Objects.hashCode(rel);
}
@Override
public ToStringHelper string() {
return super.string().add("rel", rel);
}
}

View File

@ -0,0 +1,175 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType.NS;
import java.net.URI;
import java.util.Set;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
/**
* Login Session
*
* @author Adrian Cole
*/
@XmlRootElement(namespace = NS, name = "Session")
public class Session {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().fromSession(this);
}
public static class Builder {
private String user;
private String org;
private URI href;
private Set<Link> links = Sets.newLinkedHashSet();
/**
* @see Session#getUser
*/
public Builder user(String user) {
this.user = user;
return this;
}
/**
* @see Session#getOrg
*/
public Builder org(String org) {
this.org = org;
return this;
}
/**
* @see Session#getHref
*/
public Builder href(URI href) {
this.href = href;
return this;
}
/**
* @see Session#getLinks
*/
public Builder links(Set<Link> links) {
this.links = Sets.newLinkedHashSet(checkNotNull(links, "links"));
return this;
}
/**
* @see Session#getLinks
*/
public Builder addLink(Link link) {
links.add(checkNotNull(link, "link"));
return this;
}
public Session build() {
return new Session(user, org, href, links);
}
public Builder fromSession(Session in) {
return user(in.getUser()).org(in.getOrg()).href(in.getHref()).links(in.getLinks());
}
}
private Session() {
// For JAXB and builder use
}
private Session(String user, String org, URI href, Set<Link> links) {
this.user = user;
this.org = org;
this.href = href;
this.links = ImmutableSet.copyOf(links);
}
@XmlElement(namespace = NS, name = "Link")
private Set<Link> links = Sets.newLinkedHashSet();
@XmlAttribute
private String user;
@XmlAttribute
private String org;
@XmlAttribute
private URI href;
public Set<Link> getLinks() {
return ImmutableSet.copyOf(links);
}
/**
*
* @return the user's login name.
*/
public String getUser() {
return user;
}
/**
*
* @return is the name of an organization of which the user is a member
*/
public String getOrg() {
return org;
}
/**
*
* @return a reference to the current session
*/
public URI getHref() {
return href;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Session that = Session.class.cast(o);
return equal(user, that.user) && equal(org, that.org) && equal(href, that.href) && equal(links, that.links);
}
@Override
public int hashCode() {
return Objects.hashCode(org, user, href, links);
}
@Override
public String toString() {
return Objects.toStringHelper("").add("user", user).add("org", org).add("href", href).add("links", links)
.toString();
}
}

View File

@ -0,0 +1,125 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.domain;
import static com.google.common.base.Objects.equal;
import com.google.common.base.Objects;
/**
* Session and its corresponding token
*
* @author Adrian Cole
*
*/
public class SessionWithToken {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().fromSessionWithToken(this);
}
public static class Builder {
protected Session session;
protected String token;
/**
* @see SessionWithToken#getType
*/
public Builder session(Session session) {
this.session = session;
return this;
}
/**
* @see SessionWithToken#getHref
*/
public Builder token(String token) {
this.token = token;
return this;
}
public SessionWithToken build() {
return new SessionWithToken(token, session);
}
protected Builder fromSessionWithToken(SessionWithToken in) {
return session(in.getSession()).token(in.getToken());
}
}
protected Session session;
protected String token;
protected SessionWithToken(String token, Session session) {
this.session = session;
this.token = token;
}
protected SessionWithToken() {
// For JAXB
}
/**
* TODO
*/
public Session getSession() {
return session;
}
/**
* An object reference, expressed in URL format. Because this URL includes the object identifier
* portion of the id attribute value, it uniquely identifies the object, persists for the life of
* the object, and is never reused. The value of the token attribute is a reference to a view of
* the object, and can be used to access a representation of the object that is valid in a
* particular context. Although URLs have a well-known syntax and a well-understood
* interpretation, a client should treat each token as an opaque string. The rules that govern
* how the server constructs token strings might change in future releases.
*
* @return an opaque reference and should never be parsed
*/
public String getToken() {
return token;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
SessionWithToken that = SessionWithToken.class.cast(o);
return equal(token, that.token) && equal(session, that.session);
}
@Override
public int hashCode() {
return Objects.hashCode(session, token);
}
@Override
public String toString() {
return Objects.toStringHelper("").add("session", session).add("token", token).toString();
}
}

View File

@ -0,0 +1,33 @@
package org.jclouds.vcloud.director.v1_5.filters;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.vcloud.director.v1_5.annotations.Session;
import com.google.common.base.Supplier;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AddVCloudAuthorizationToRequest implements HttpRequestFilter {
private final Supplier<String> sessionSupplier;
@Inject
public AddVCloudAuthorizationToRequest(@Session Supplier<String> sessionSupplier) {
this.sessionSupplier = sessionSupplier;
}
@Override
public HttpRequest filter(HttpRequest request) throws HttpException {
return ModifyRequest.replaceHeader(request, "x-vcloud-authorization", sessionSupplier.get());
}
}

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.functions;
import java.net.URI;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.domain.Credentials;
import org.jclouds.vcloud.director.v1_5.annotations.Login;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.jclouds.vcloud.director.v1_5.login.SessionClient;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@Singleton
public class LoginUserInOrgWithPassword implements Function<Credentials, SessionWithToken> {
private final SessionClient client;
private final Supplier<URI> loginUrl;
@Inject
public LoginUserInOrgWithPassword(SessionClient client, @Login Supplier<URI> loginUrl) {
this.client = client;
this.loginUrl = loginUrl;
}
@Override
public SessionWithToken apply(Credentials input) {
String user = input.identity.substring(0, input.identity.lastIndexOf('@'));
String org = input.identity.substring(input.identity.lastIndexOf('@') + 1);
String password = input.credential;
return client.loginUserInOrgWithPassword(loginUrl.get(), user, org, password);
}
@Override
public String toString() {
return "loginUserInOrgWithPassword()";
}
}

View File

@ -0,0 +1,92 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import static org.jclouds.http.HttpUtils.releasePayload;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.logging.Logger;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.jclouds.vcloud.director.v1_5.login.SessionClient;
import com.google.common.cache.LoadingCache;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* If the credentials supplied in the authentication header are invalid, or if the token has
* expired, the server returns HTTP response code 401. The token expires after a configurable
* interval of client inactivity. The default is 30 minutes after the token is created. After the
* token expires, you must log in again to obtain a new token.
*
* @author Adrian Cole
*
*/
@Singleton
public class InvalidateSessionAndRetryOn401AndLogoutOnClose extends BackoffLimitedRetryHandler {
@Resource
protected Logger logger = Logger.NULL;
private final LoadingCache<Credentials, SessionWithToken> authenticationResponseCache;
private final SessionClient sessionClient;
@Inject
protected InvalidateSessionAndRetryOn401AndLogoutOnClose(
LoadingCache<Credentials, SessionWithToken> authenticationResponseCache, SessionClient sessionClient) {
this.authenticationResponseCache = authenticationResponseCache;
this.sessionClient = sessionClient;
}
@Override
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
boolean retry = false; // default
try {
if (response.getStatusCode() == 401) {
closeClientButKeepContentStream(response);
logger.debug("invalidating session");
authenticationResponseCache.invalidateAll();
retry = super.shouldRetryRequest(command, response);
}
return retry;
} finally {
releasePayload(response);
}
}
/**
* it is important that we close any sessions on close to help the server not become overloaded.
*/
@PreDestroy
public void logoutOnClose() {
for (SessionWithToken s : authenticationResponseCache.asMap().values()) {
try {
sessionClient.logoutSessionWithToken(s.getSession().getHref(), s.getToken());
} catch (Exception e) {
logger.error(e, "error logging out session %s", s.getSession());
}
}
}
}

View File

@ -0,0 +1,68 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import javax.inject.Singleton;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
/**
* This will parse and set an appropriate exception on the command object.
*
* @author Adrian Cole
*
*/
//TODO: is there error spec someplace? let's type errors, etc.
@Singleton
public class VCloudDirectorErrorHandler implements HttpErrorHandler {
public void handleError(HttpCommand command, HttpResponse response) {
// it is important to always read fully and close streams
byte[] data = closeClientButKeepContentStream(response);
String message = data != null ? new String(data) : null;
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
switch (response.getStatusCode()) {
case 401:
case 403:
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
default:
exception = new HttpResponseException(command, response, message);
break;
}
command.setException(exception);
}
}

View File

@ -0,0 +1,78 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.login;
import java.net.URI;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.JAXBResponseParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.vcloud.director.v1_5.binders.BindUserOrgAndPasswordAsBasicAuthorizationHeader;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.jclouds.vcloud.director.v1_5.parsers.SessionWithTokenFromXMLAndHeader;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Session via their REST API.
* <p/>
*
* @see SessionClient
* @author Adrian Cole
*/
public interface SessionAsyncClient {
/**
* @see SessionClient#loginUserInOrgWithPassword
*/
@POST
@Consumes
@ResponseParser(SessionWithTokenFromXMLAndHeader.class)
@MapBinder(BindUserOrgAndPasswordAsBasicAuthorizationHeader.class)
ListenableFuture<SessionWithToken> loginUserInOrgWithPassword(@EndpointParam URI loginUrl,
@PayloadParam("user") String user, @PayloadParam("org") String org,
@PayloadParam("password") String password);
/**
* @see SessionClient#getSessionWithToken
*/
@GET
@Consumes
@JAXBResponseParser
ListenableFuture<Session> getSessionWithToken(@EndpointParam URI session,
@HeaderParam("x-vcloud-authorization") String authenticationToken);
/**
* @see SessionClient#logoutSessionWithToken
*/
@DELETE
@Consumes
@JAXBResponseParser
ListenableFuture<Void> logoutSessionWithToken(@EndpointParam URI session,
@HeaderParam("x-vcloud-authorization") String authenticationToken);
}

View File

@ -0,0 +1,52 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.login;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
/**
* Provides synchronous access to Session.
* <p/>
*
* @see SessionAsyncClient
* @author Adrian Cole
*/
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
public interface SessionClient {
/**
* TODO
*/
SessionWithToken loginUserInOrgWithPassword(URI loginUrl, String user, String org, String password);
/**
* TODO
*/
Session getSessionWithToken(URI session, String authenticationToken);
/**
* TODO
*/
void logoutSessionWithToken(URI session, String authenticationToken);
}

View File

@ -0,0 +1,54 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.parsers;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseXMLWithJAXB;
import org.jclouds.logging.Logger;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SessionWithTokenFromXMLAndHeader implements Function<HttpResponse, SessionWithToken> {
@Resource
protected Logger logger = Logger.NULL;
private ParseXMLWithJAXB<Session> sessionParser;
@Inject
public SessionWithTokenFromXMLAndHeader(ParseXMLWithJAXB<Session> sessionParser) {
this.sessionParser = sessionParser;
}
@Override
public SessionWithToken apply(final HttpResponse from) {
Session session = sessionParser.apply(from);
return SessionWithToken.builder().session(session).token(from.getFirstHeaderOrNull("x-vcloud-authorization"))
.build();
}
}

View File

@ -0,0 +1,42 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5;
import static org.testng.Assert.assertEquals;
import org.jclouds.vcloud.director.v1_5.internal.BaseVCloudDirectorRestClientExpectTest;
import org.jclouds.vcloud.director.v1_5.login.SessionClientExpectTest;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "VCloudDirectorClient")
public class VCloudDirectorClientExpectTest extends BaseVCloudDirectorRestClientExpectTest {
public void testRestClientModuleWorksProperly() throws Exception {
VCloudDirectorClient clientWhenSessionsExist = requestSendsResponse(loginRequest, sessionResponse);
assertEquals(clientWhenSessionsExist.getCurrentSession(), SessionClientExpectTest.SESSION);
}
}

View File

@ -0,0 +1,89 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.handlers;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.jclouds.vcloud.director.v1_5.login.SessionClient;
import org.testng.annotations.Test;
import com.google.common.cache.LoadingCache;
/**
* Tests behavior of {@code InvalidateSessionAndRetryOn401AndLogoutOnClose} handler
*
* @author grkvlt@apache.org
*/
@Test(groups = "unit", testName = "InvalidateSessionAndRetryOn401AndLogoutOnCloseTest")
public class InvalidateSessionAndRetryOn401AndLogoutOnCloseTest {
@SuppressWarnings("unchecked")
@Test
public void test401ShouldInvalidateSessionAndRetry() {
HttpCommand command = createMock(HttpCommand.class);
SessionClient sessionClient = createMock(SessionClient.class);
LoadingCache<Credentials, SessionWithToken> cache = createMock(LoadingCache.class);
cache.invalidateAll();
expectLastCall();
expect(command.incrementFailureCount()).andReturn(1);
expect(command.isReplayable()).andReturn(true);
expect(command.getFailureCount()).andReturn(1).atLeastOnce();
replay(cache, command);
HttpResponse response = HttpResponse.builder().statusCode(401).build();
InvalidateSessionAndRetryOn401AndLogoutOnClose retry = new InvalidateSessionAndRetryOn401AndLogoutOnClose(cache,
sessionClient);
assertTrue(retry.shouldRetryRequest(command, response));
verify(cache, command);
}
@SuppressWarnings("unchecked")
@Test
public void test403ShouldNotInvalidateSessionOrRetry() {
HttpCommand command = createMock(HttpCommand.class);
SessionClient sessionClient = createMock(SessionClient.class);
LoadingCache<Credentials, SessionWithToken> cache = createMock(LoadingCache.class);
replay(cache, command);
HttpResponse response = HttpResponse.builder().statusCode(403).build();
InvalidateSessionAndRetryOn401AndLogoutOnClose retry = new InvalidateSessionAndRetryOn401AndLogoutOnClose(cache,
sessionClient);
assertFalse(retry.shouldRetryRequest(command, response));
verify(cache, command);
}
}

View File

@ -0,0 +1,106 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.handlers;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reportMatcher;
import static org.easymock.EasyMock.verify;
import java.net.URI;
import org.easymock.IArgumentMatcher;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.io.Payloads;
import org.jclouds.vcloud.director.v1_5.handlers.VCloudDirectorErrorHandler;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.inject.Guice;
/**
*
* @author Adrian Cole
*/
@Test(groups = { "unit" })
public class VCloudDirectorErrorHandlerTest {
@Test
public void test401MakesAuthorizationException() {
assertCodeMakes("GET", URI.create("https://api.vcloud.director.com/foo"), 401, "", "Unauthorized",
AuthorizationException.class);
}
@Test
public void test404MakesResourceNotFoundException() {
assertCodeMakes("GET", URI.create("https://api.vcloud.director.com/foo"), 404, "", "Not Found",
ResourceNotFoundException.class);
}
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content,
Class<? extends Exception> expected) {
assertCodeMakes(method, uri, statusCode, message, "text/xml", content, expected);
}
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
String content, Class<? extends Exception> expected) {
VCloudDirectorErrorHandler function = Guice.createInjector().getInstance(VCloudDirectorErrorHandler.class);
HttpCommand command = createMock(HttpCommand.class);
HttpRequest request = new HttpRequest(method, uri);
HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Strings2
.toInputStream(content)));
response.getPayload().getContentMetadata().setContentType(contentType);
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
command.setException(classEq(expected));
replay(command);
function.handleError(command, response);
verify(command);
}
public static Exception classEq(final Class<? extends Exception> in) {
reportMatcher(new IArgumentMatcher() {
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("classEq(");
buffer.append(in);
buffer.append(")");
}
@Override
public boolean matches(Object arg) {
return arg.getClass() == in;
}
});
return null;
}
}

View File

@ -0,0 +1,64 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.internal;
import java.util.Properties;
import org.jclouds.compute.BaseVersionedServiceLiveTest;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorAsyncClient;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code VCloudDirectorClient}
*
* @author Adrian Cole
*/
@Test(groups = "live")
public class BaseVCloudDirectorClientLiveTest extends BaseVersionedServiceLiveTest {
public BaseVCloudDirectorClientLiveTest() {
provider = "vcloud-director";
}
protected RestContext<VCloudDirectorClient, VCloudDirectorAsyncClient> context;
@BeforeGroups(groups = { "live" })
public void setupClient() {
setupCredentials();
Properties overrides = setupProperties();
context = new RestContextFactory().createContext(provider, identity, credential,
ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()), overrides);
}
@AfterGroups(groups = "live")
protected void tearDown() {
if (context != null)
context.close();
}
}

View File

@ -0,0 +1,60 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.vcloud.director.v1_5.internal;
import java.net.URI;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.BaseRestClientExpectTest;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorClient;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType;
import com.google.common.collect.ImmutableMultimap;
/**
* Base class for writing KeyStone Rest Client Expect tests
*
* @author Adrian Cole
*/
public class BaseVCloudDirectorRestClientExpectTest extends BaseRestClientExpectTest<VCloudDirectorClient> {
public static final String user = "adrian@jclouds.org";
public static final String org = "JClouds";
public static final String password = "password";
public static final String token = "mIaR3/6Lna8DWImd7/JPR5rK8FcUHabt+G/UCJV5pJQ=";
protected HttpRequest loginRequest = HttpRequest.builder().method("POST").endpoint(
URI.create("http://localhost/api/sessions")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "*/*").put("Authorization",
"Basic YWRyaWFuQGpjbG91ZHMub3JnQEpDbG91ZHM6cGFzc3dvcmQ=").build()).build();
protected HttpResponse sessionResponse = HttpResponse.builder().statusCode(200).headers(
ImmutableMultimap.<String, String> builder().put("x-vcloud-authorization", token).put("Set-Cookie",
String.format("vcloud-token=%s; Secure; Path=/", token)).build()).payload(
payloadFromResourceWithContentType("/session.xml", VCloudDirectorMediaType.SESSION_XML + ";version=1.5"))
.build();
public BaseVCloudDirectorRestClientExpectTest() {
provider = "vcloud-director";
identity = String.format("%s@%s", user, org);
credential = password;
}
}

View File

@ -0,0 +1,127 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
*(Link.builder().regarding copyright ownership. jclouds 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(Link.builder().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.vcloud.director.v1_5.login;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.BaseRestClientExpectTest;
import org.jclouds.rest.BaseRestClientExpectTest.RegisterContext;
import org.jclouds.vcloud.director.v1_5.VCloudDirectorMediaType;
import org.jclouds.vcloud.director.v1_5.domain.Link;
import org.jclouds.vcloud.director.v1_5.domain.Session;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
/**
*
* Allows us to test a client via its side effects.
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "SessionClientExpectTest")
// only needed as SessionClient is not(Link.builder().registered in(Link.builder().rest.properties
@RegisterContext(sync = SessionClient.class, async = SessionAsyncClient.class)
public class SessionClientExpectTest extends BaseRestClientExpectTest<SessionClient> {
public static final String user = "adrian@jclouds.org";
public static final String org = "JClouds";
public static final Session SESSION = Session.builder().user(user).org(org).href(
URI.create("https://vcloudbeta.bluelock.com/api/session/")).addLink(
Link.builder().rel("down").type("application/vnd.vmware.vcloud.orgList+xml").href(
URI.create("https://vcloudbeta.bluelock.com/api/org/")).build()).addLink(
Link.builder().rel("down").type("application/vnd.vmware.admin.vcloud+xml").href(
URI.create("https://vcloudbeta.bluelock.com/api/admin/")).build()).addLink(
Link.builder().rel("down").type("application/vnd.vmware.vcloud.query.queryList+xml").href(
URI.create("https://vcloudbeta.bluelock.com/api/query")).build()).addLink(
Link.builder().rel("entityResolver").type("application/vnd.vmware.vcloud.entity+xml").href(
URI.create("https://vcloudbeta.bluelock.com/api/entity/")).build()).build();
public void testWhenResponseIs2xxLoginReturnsValidSession() {
URI loginUrl = URI.create("https://vcloudbeta.bluelock.com/api/sessions");
String token = "mIaR3/6Lna8DWImd7/JPR5rK8FcUHabt+G/UCJV5pJQ=";
SessionClient client = requestSendsResponse(
HttpRequest.builder().method("POST").endpoint(loginUrl).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "*/*").put("Authorization",
"Basic YWRyaWFuQGpjbG91ZHMub3JnQEpDbG91ZHM6cGFzc3dvcmQ=").build()).build(),
HttpResponse.builder().statusCode(200).headers(
ImmutableMultimap.<String, String> builder().put("x-vcloud-authorization", token).put("Set-Cookie",
String.format("vcloud-token=%s; Secure; Path=/", token)).build())
.payload(
payloadFromResourceWithContentType("/session.xml", VCloudDirectorMediaType.SESSION_XML
+ ";version=1.5")).build()
);
assertEquals(client.loginUserInOrgWithPassword(loginUrl, user, org, "password"), SessionWithToken.builder()
.session(SESSION)
.token(token).build());
}
public void testWhenResponseIs2xxGetSessionReturnsValidSession() {
URI sessionUrl = URI.create("https://vcloudbeta.bluelock.com/api/session");
String token = "mIaR3/6Lna8DWImd7/JPR5rK8FcUHabt+G/UCJV5pJQ=";
SessionClient client = requestSendsResponse(
HttpRequest.builder().method("GET").endpoint(sessionUrl).headers(
ImmutableMultimap.<String, String> builder().put("x-vcloud-authorization", token).put("Accept", "*/*")
.build()).build(),
HttpResponse.builder().statusCode(200)
.payload(
payloadFromResourceWithContentType("/session.xml", VCloudDirectorMediaType.SESSION_XML
+ ";version=1.5")).build()
);
assertEquals(client.getSessionWithToken(sessionUrl, token), SESSION);
}
public void testLogoutWhenResponseIs2xx() {
URI sessionUrl = URI.create("https://vcloudbeta.bluelock.com/api/session");
String token = "mIaR3/6Lna8DWImd7/JPR5rK8FcUHabt+G/UCJV5pJQ=";
SessionClient client = requestSendsResponse(
HttpRequest.builder().method("DELETE").endpoint(sessionUrl).headers(
ImmutableMultimap.<String, String> builder().put("x-vcloud-authorization", token).put("Accept", "*/*")
.build()).build(),
HttpResponse.builder().statusCode(204).build()
);
client.logoutSessionWithToken(sessionUrl, token);
}
}

View File

@ -0,0 +1,103 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
*(Link.builder().regarding copyright ownership. jclouds 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(Link.builder().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.vcloud.director.v1_5.login;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.jclouds.rest.RestContextFactory.createContextBuilder;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.Properties;
import org.jclouds.compute.BaseVersionedServiceLiveTest;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextSpec;
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code SessionClient}. Note this class is tested completely independently of
* VCloudClient as it is a dependency of the VCloud context working.
*
* @author Adrian Cole
*/
@Test(groups = { "live", "apitests" }, testName = "SessionClientLiveTest")
public class SessionClientLiveTest extends BaseVersionedServiceLiveTest {
public SessionClientLiveTest() {
provider = "vcloud-director";
}
private RestContext<SessionClient, SessionAsyncClient> context;
@BeforeGroups(groups = { "live" })
public void setupClient() {
setupCredentials();
Properties overrides = setupProperties();
RestContextSpec<SessionClient, SessionAsyncClient> contextSpec = contextSpec("vcloud-director", endpoint,
apiVersion, buildVersion, "", identity, credential, SessionClient.class, SessionAsyncClient.class);
context = createContextBuilder(contextSpec, overrides).withModules(
ImmutableSet.<Module> of(new SLF4JLoggingModule())).buildContext();
// session client isn't typically exposed to the user, as it is implicit
client = context.utils().injector().getInstance(SessionClient.class);
}
private SessionClient client;
private SessionWithToken sessionWithToken;
@Test(testName = "POST /sessions")
public void testLogin() {
String user = identity.substring(0, identity.lastIndexOf('@'));
String org = identity.substring(identity.lastIndexOf('@') + 1);
String password = credential;
sessionWithToken = client.loginUserInOrgWithPassword(URI.create(endpoint + "/sessions"), user, org, password);
assertEquals(sessionWithToken.getSession().getUser(), user);
assertEquals(sessionWithToken.getSession().getOrg(), org);
assertTrue(sessionWithToken.getSession().getLinks().size() > 0);
assertNotNull(sessionWithToken.getToken());
}
@Test(testName = "GET /session", dependsOnMethods = "testLogin")
public void testGetSession() {
assertEquals(client.getSessionWithToken(sessionWithToken.getSession().getHref(), sessionWithToken.getToken()),
sessionWithToken.getSession());
}
@Test(testName = "DELETE /session", dependsOnMethods = "testGetSession")
public void testLogout() {
client.logoutSessionWithToken(sessionWithToken.getSession().getHref(), sessionWithToken.getToken());
}
@AfterGroups(groups = "live")
protected void tearDown() {
if (context != null)
context.close();
}
}

View File

@ -0,0 +1,64 @@
<?xml version="1.0"?>
<configuration scan="false">
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d %-5p [%c] (%t) %m%n</Pattern>
</layout>
</appender>
<appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds-wire.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d %-5p [%c] (%t) %m%n</Pattern>
</layout>
</appender>
<appender name="COMPUTEFILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds-compute.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d %-5p [%c] (%t) %m%n</Pattern>
</layout>
</appender>
<appender name="SSHFILE" class="ch.qos.logback.core.FileAppender">
<file>target/test-data/jclouds-ssh.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d %-5p [%c] (%t) %m%n</Pattern>
</layout>
</appender>
<root>
<level value="warn" />
</root>
<logger name="org.jclouds">
<level value="DEBUG" />
<appender-ref ref="FILE" />
</logger>
<logger name="jclouds.wire">
<level value="DEBUG" />
<appender-ref ref="WIREFILE" />
</logger>
<logger name="jclouds.headers">
<level value="DEBUG" />
<appender-ref ref="WIREFILE" />
</logger>
<logger name="jclouds.compute">
<level value="DEBUG" />
<appender-ref ref="COMPUTEFILE" />
</logger>
<logger name="jclouds.ssh">
<level value="DEBUG" />
<appender-ref ref="SSHFILE" />
</logger>
</configuration>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Session xmlns="http://www.vmware.com/vcloud/v1.5" user="adrian@jclouds.org" org="JClouds" type="application/vnd.vmware.vcloud.session+xml" href="https://vcloudbeta.bluelock.com/api/session/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://vcloudbeta.bluelock.com/api/v1.5/schema/master.xsd">
<Link rel="down" type="application/vnd.vmware.vcloud.orgList+xml" href="https://vcloudbeta.bluelock.com/api/org/"/>
<Link rel="down" type="application/vnd.vmware.admin.vcloud+xml" href="https://vcloudbeta.bluelock.com/api/admin/"/>
<Link rel="down" type="application/vnd.vmware.vcloud.query.queryList+xml" href="https://vcloudbeta.bluelock.com/api/query"/>
<Link rel="entityResolver" type="application/vnd.vmware.vcloud.entity+xml" href="https://vcloudbeta.bluelock.com/api/entity/"/>
</Session>