Issue 427: add realms collection to deltacloud

This commit is contained in:
Adrian Cole 2010-12-23 16:18:51 +01:00
parent 890c34bc5b
commit 361957ed79
14 changed files with 630 additions and 0 deletions

View File

@ -34,14 +34,18 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.collections.Images;
import org.jclouds.deltacloud.collections.Instances;
import org.jclouds.deltacloud.collections.Realms;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.deltacloud.xml.ImageHandler;
import org.jclouds.deltacloud.xml.ImagesHandler;
import org.jclouds.deltacloud.xml.InstanceHandler;
import org.jclouds.deltacloud.xml.InstancesHandler;
import org.jclouds.deltacloud.xml.LinksHandler;
import org.jclouds.deltacloud.xml.RealmHandler;
import org.jclouds.deltacloud.xml.RealmsHandler;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.EndpointParam;
@ -74,6 +78,25 @@ public interface DeltacloudAsyncClient {
@XMLResponseParser(LinksHandler.class)
ListenableFuture<Map<DeltacloudCollection, URI>> getCollections();
/**
* @see DeltacloudClient#listRealms
*/
@GET
@Endpoint(Realms.class)
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(RealmsHandler.class)
ListenableFuture<? extends Set<Realm>> listRealms();
/**
* @see DeltacloudClient#getRealm
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("")
@XMLResponseParser(RealmHandler.class)
ListenableFuture<Realm> getRealm(@EndpointParam URI realmHref);
/**
* @see DeltacloudClient#listImages
*/

View File

@ -28,6 +28,7 @@ import org.jclouds.concurrent.Timeout;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.rest.annotations.EndpointParam;
@ -49,6 +50,20 @@ public interface DeltacloudClient {
*/
Map<DeltacloudCollection, URI> getCollections();
/**
* The realms collection will return a set of all realms available to the current user.
*
* @return realms viewable to the user or empty set
*/
Set<? extends Realm> listRealms();
/**
*
* @param realmHref
* @return realm or null, if not found
*/
Realm getRealm(URI realmHref);
/**
* The images collection will return a set of all images available to the current user.
*

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.collections;
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 realms collection will return a set of all realms available to the current user.
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface Realms {
}

View File

@ -33,6 +33,7 @@ import org.jclouds.deltacloud.DeltacloudClient;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.collections.Images;
import org.jclouds.deltacloud.collections.Instances;
import org.jclouds.deltacloud.collections.Realms;
import org.jclouds.deltacloud.handlers.DeltacloudErrorHandler;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp;
@ -106,4 +107,14 @@ public class DeltacloudRestClientModule extends RestClientModule<DeltacloudClien
protected URI provideInstanceCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return collectionSupplier.get().get(DeltacloudCollection.INSTANCES);
}
/**
* since the supplier is memoized, and there are no objects created here, this doesn't need to be
* singleton.
*/
@Provides
@Realms
protected URI provideRealmCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return collectionSupplier.get().get(DeltacloudCollection.REALMS);
}
}

View File

@ -0,0 +1,148 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import javax.annotation.Nullable;
/**
* Within a cloud provider a realm represents a boundary containing resources. The exact definition
* of a realm is left to the cloud provider. In some cases, a realm may represent different
* datacenters, different continents, or different pools of resources within a single datacenter. A
* cloud provider may insist that resources must all exist within a single realm in order to
* cooperate. For instance, storage volumes may only be allowed to be mounted to instances within
* the same realm.
*
* @author Adrian Cole
*/
public class Realm {
private final URI href;
private final String id;
@Nullable
private final String limit;
private final String name;
private final RealmState state;
public Realm(URI href, String id, String name, @Nullable String limit, RealmState state) {
this.href = checkNotNull(href, "href");
this.id = checkNotNull(id, "id");
this.name = checkNotNull(name, "name");
this.limit = limit;
this.state = checkNotNull(state, "state");
}
/**
*
* @return URL to manipulate a specific realm
*/
public URI getHref() {
return href;
}
/**
*
* @return A unique identifier for the realm
*/
public String getId() {
return id;
}
/**
*
* @return A short label
*/
public String getName() {
return name;
}
/**
* for example limitation of how many machine you can launch in given region / how much computing
* power is available for you.
*
* @return Limits applicable for the current requester
*/
@Nullable
public String getLimit() {
return limit;
}
/**
*
* @return indicator of the realm's current state
*/
public RealmState getState() {
return state;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((href == null) ? 0 : href.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((limit == null) ? 0 : limit.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Realm other = (Realm) obj;
if (href == null) {
if (other.href != null)
return false;
} else if (!href.equals(other.href))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (limit == null) {
if (other.limit != null)
return false;
} else if (!limit.equals(other.limit))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (state != other.state)
return false;
return true;
}
@Override
public String toString() {
return "[href=" + href + ", id=" + id + ", limit=" + limit + ", name=" + name + ", state=" + state + "]";
}
}

View File

@ -0,0 +1,55 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.domain;
import static com.google.common.base.Preconditions.checkNotNull;
/**
*
* Indicator of the realm's current state
*
* @author Adrian Cole
*
*/
public enum RealmState {
/**
* the realm is available
*/
AVAILABLE,
/**
* the realm is unavailable
*/
UNAVAILABLE,
/**
* state returned as something besides the above.
*/
UNRECOGNIZED;
public static RealmState fromValue(String state) {
try {
return valueOf(checkNotNull(state, "state"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.xml;
import java.net.URI;
import java.util.Map;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.RealmState;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class RealmHandler extends ParseSax.HandlerWithResult<Realm> {
private StringBuilder currentText = new StringBuilder();
private URI href;
private String id;
private String name;
private String limit;
private RealmState state;
private Realm realm;
public Realm getResult() {
return realm;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
if (attributes.containsKey("href")) {
this.href = URI.create(attributes.get("href"));
this.id = attributes.get("id");
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("limit")) {
this.limit = currentText.toString().trim();
if ("".equals(limit))
limit = null;
} else if (qName.equalsIgnoreCase("name")) {
this.name = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("state")) {
this.state = RealmState.fromValue(currentText.toString().trim());
} else if (qName.equalsIgnoreCase("realm")) {
this.realm = new Realm(href, id, name, limit, state);
this.href = null;
this.id = null;
this.name = null;
this.limit = null;
this.state = null;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class RealmsHandler extends ParseSax.HandlerWithResult<Set<? extends Realm>> {
private StringBuilder currentText = new StringBuilder();
private Set<Realm> realms = Sets.newLinkedHashSet();
private final RealmHandler realmHandler;
@Inject
public RealmsHandler(RealmHandler realmHandler) {
this.realmHandler = realmHandler;
}
public Set<? extends Realm> getResult() {
return realms;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
realmHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
realmHandler.endElement(uri, localName, qName);
if (qName.equals("realm") && currentText.toString().trim().equals("")) {
this.realms.add(realmHandler.getResult());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
realmHandler.characters(ch, start, length);
currentText.append(ch, start, length);
}
}

View File

@ -35,6 +35,8 @@ import org.jclouds.deltacloud.xml.ImagesHandler;
import org.jclouds.deltacloud.xml.InstanceHandler;
import org.jclouds.deltacloud.xml.InstancesHandler;
import org.jclouds.deltacloud.xml.LinksHandler;
import org.jclouds.deltacloud.xml.RealmHandler;
import org.jclouds.deltacloud.xml.RealmsHandler;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.filters.BasicAuthentication;
@ -91,6 +93,36 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
}
public void testListRealms() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("listRealms");
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(request, "GET http://localhost:3001/api/realms HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, RealmsHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testGetRealm() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("getRealm", URI.class);
HttpRequest request = processor.createRequest(method, URI.create("https://delta/realm1"));
assertRequestLineEquals(request, "GET https://delta/realm1 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, RealmHandler.class);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(request);
}
public void testListImages() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("listImages");
HttpRequest request = processor.createRequest(method);
@ -252,6 +284,11 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
return URI.create("http://localhost:3001/api/instances");
}
@Override
protected URI provideRealmCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return URI.create("http://localhost:3001/api/realms");
}
}
@Override

View File

@ -37,6 +37,7 @@ import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.InstanceAction;
import org.jclouds.deltacloud.domain.InstanceState;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
@ -117,6 +118,17 @@ public class DeltacloudClientLiveTest {
assert (links.get(link) != null) : link;
}
public void testListAndGetRealms() throws Exception {
Set<? extends Realm> response = client.listRealms();
assert null != response;
long realmCount = response.size();
assertTrue(realmCount >= 0);
for (Realm realm : response) {
Realm newDetails = client.getRealm(realm.getHref());
assertEquals(realm, newDetails);
}
}
public void testListAndGetImages() throws Exception {
Set<? extends Image> response = client.listImages();
assert null != response;

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.RealmState;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code RealmHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class RealmHandlerTest {
static ParseSax<Realm> createParser() {
Injector injector = Guice.createInjector(new SaxParserModule());
ParseSax<Realm> parser = injector.getInstance(ParseSax.Factory.class).create(
injector.getInstance(RealmHandler.class));
return parser;
}
public static Realm parseRealm() {
return parseRealm("/test_get_realm.xml");
}
public static Realm parseRealm(String resource) {
InputStream is = RealmHandlerTest.class.getResourceAsStream(resource);
return createParser().parse(is);
}
public void test() {
Realm expects = new Realm(URI.create("http://fancycloudprovider.com/api/realms/us"), "us", "United States", null,
RealmState.AVAILABLE);
assertEquals(parseRealm(), expects);
}
}

View File

@ -0,0 +1,54 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.Set;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.RealmState;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code RealmsHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class RealmsHandlerTest extends BaseHandlerTest {
@Test
public void test() {
InputStream is = getClass().getResourceAsStream("/test_list_realms.xml");
Set<? extends Realm> expects = ImmutableSet.of(
new Realm(URI.create("http://fancycloudprovider.com/api/realms/us"), "us", "United States", null,
RealmState.AVAILABLE), new Realm(URI.create("http://fancycloudprovider.com/api/realms/eu"), "eu",
"Europe", null, RealmState.AVAILABLE));
// not sure why this isn't always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(RealmsHandler.class)).parse(is), expects);
}
}

View File

@ -0,0 +1,5 @@
<realm href="http://fancycloudprovider.com/api/realms/us" id='us'>
<name>United States</name>
<state>AVAILABLE</state>
<limit/>
</realm>

View File

@ -0,0 +1,12 @@
<realms>
<realm href="http://fancycloudprovider.com/api/realms/us" id='us'>
<name>United States</name>
<state>AVAILABLE</state>
<limit/>
</realm>
<realm href="http://fancycloudprovider.com/api/realms/eu" id='eu'>
<name>Europe</name>
<state>AVAILABLE</state>
<limit/>
</realm>
</realms>