From e7c6cbf4921fec328e67e9494ee4286fc6f23ed3 Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Mon, 28 Dec 2009 01:41:31 +0000 Subject: [PATCH] Issue 29, Issue 76: added new annotation @EndpointParam, added support for Availability Zones and Regions git-svn-id: http://jclouds.googlecode.com/svn/trunk@2526 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../org/jclouds/aws/ec2/EC2AsyncClient.java | 5 + .../java/org/jclouds/aws/ec2/EC2Client.java | 6 + .../jclouds/aws/ec2/EC2PropertiesBuilder.java | 2 +- .../aws/ec2/config/EC2RestClientModule.java | 25 +++ .../aws/ec2/domain/AvailabilityZone.java | 53 +++++ .../aws/ec2/domain/AvailabilityZoneInfo.java | 167 +++++++++++++++ .../org/jclouds/aws/ec2/domain/Region.java | 53 +++++ .../aws/ec2/functions/RegionToEndpoint.java | 56 +++++ .../aws/ec2/internal/EC2AsyncClientImpl.java | 16 +- .../aws/ec2/internal/EC2ClientImpl.java | 14 +- .../DescribeAvailabilityZonesOptions.java | 77 +++++++ .../ec2/options/DescribeRegionsOptions.java | 77 +++++++ .../AvailabilityZoneAndRegionAsyncClient.java | 85 ++++++++ .../AvailabilityZoneAndRegionClient.java | 68 ++++++ ...cribeAvailabilityZonesResponseHandler.java | 110 ++++++++++ .../xml/DescribeRegionsResponseHandler.java | 75 +++++++ .../aws/ec2/EC2ContextBuilderTest.java | 4 +- ...ilabilityZoneAndRegionAsyncClientTest.java | 202 ++++++++++++++++++ ...ailabilityZoneAndRegionClientLiveTest.java | 115 ++++++++++ ...eAvailabilityZonesResponseHandlerTest.java | 69 ++++++ .../DescribeRegionsResponseHandlerTest.java | 96 +++++++++ .../test/resources/ec2/availabilityZones.xml | 35 +++ .../ec2/regionEndpoints-additional.xml | 22 ++ .../test/resources/ec2/regionEndpoints.xml | 18 ++ .../azure/storage/blob/AzureBlobUtil.java | 4 +- .../java/org/jclouds/compute/NodeService.java | 67 ++++++ .../jclouds/compute/NodeServiceFactory.java | 59 +++++ .../compute/domain/CreateNodeResponse.java | 36 ++++ .../org/jclouds/compute/domain/Image.java.new | 51 +++++ .../jclouds/compute/domain/NodeIdentity.java | 49 +++++ .../jclouds/compute/domain/NodeMetadata.java | 49 +++++ .../org/jclouds/compute/domain/NodeState.java | 26 +++ .../jclouds/compute/domain/Profile.java.new | 33 +++ .../java/org/jclouds/compute/domain/Size.java | 79 +++++++ .../domain/internal/NodeIdentityImpl.java | 96 +++++++++ .../org/jclouds/rest/RestContextBuilder.java | 1 - .../jclouds/rest/annotations/Endpoint.java | 8 +- .../rest/annotations/EndpointParam.java | 59 +++++ .../internal/RestAnnotationProcessor.java | 31 +-- .../internal/RestAnnotationProcessorTest.java | 3 +- .../jclouds/mezeo/pcs2/PCSAsyncClient.java | 23 +- .../jclouds/nirvanix/sdn/SDNAsyncClient.java | 3 +- .../filters/AddSessionTokenToRequestTest.java | 4 +- .../InsertUserContextIntoPathTest.java | 4 +- 44 files changed, 2083 insertions(+), 52 deletions(-) create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZone.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZoneInfo.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/domain/Region.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/functions/RegionToEndpoint.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeAvailabilityZonesOptions.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeRegionsOptions.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClient.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClient.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandler.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandler.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClientTest.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClientLiveTest.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandlerTest.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandlerTest.java create mode 100644 aws/core/src/test/resources/ec2/availabilityZones.xml create mode 100644 aws/core/src/test/resources/ec2/regionEndpoints-additional.xml create mode 100644 aws/core/src/test/resources/ec2/regionEndpoints.xml create mode 100644 core/src/main/java/org/jclouds/compute/NodeService.java create mode 100644 core/src/main/java/org/jclouds/compute/NodeServiceFactory.java create mode 100644 core/src/main/java/org/jclouds/compute/domain/CreateNodeResponse.java create mode 100644 core/src/main/java/org/jclouds/compute/domain/Image.java.new create mode 100644 core/src/main/java/org/jclouds/compute/domain/NodeIdentity.java create mode 100644 core/src/main/java/org/jclouds/compute/domain/NodeMetadata.java create mode 100644 core/src/main/java/org/jclouds/compute/domain/NodeState.java create mode 100644 core/src/main/java/org/jclouds/compute/domain/Profile.java.new create mode 100644 core/src/main/java/org/jclouds/compute/domain/Size.java create mode 100644 core/src/main/java/org/jclouds/compute/domain/internal/NodeIdentityImpl.java create mode 100644 core/src/main/java/org/jclouds/rest/annotations/EndpointParam.java diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2AsyncClient.java b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2AsyncClient.java index 72c2c6070b..c07dbd686c 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2AsyncClient.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2AsyncClient.java @@ -25,6 +25,7 @@ package org.jclouds.aws.ec2; import org.jclouds.aws.ec2.internal.EC2AsyncClientImpl; import org.jclouds.aws.ec2.services.AMIAsyncClient; +import org.jclouds.aws.ec2.services.AvailabilityZoneAndRegionAsyncClient; import org.jclouds.aws.ec2.services.ElasticIPAddressAsyncClient; import org.jclouds.aws.ec2.services.InstanceAsyncClient; import org.jclouds.aws.ec2.services.KeyPairAsyncClient; @@ -70,4 +71,8 @@ public interface EC2AsyncClient { */ MonitoringAsyncClient getMonitoringServices(); + /** + * Provides asynchronous access to Availability Zones and Regions services. + */ + AvailabilityZoneAndRegionAsyncClient getAvailabilityZoneAndRegionServices(); } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java index daa9fe4065..aed796060a 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java @@ -25,6 +25,7 @@ package org.jclouds.aws.ec2; import org.jclouds.aws.ec2.internal.EC2ClientImpl; import org.jclouds.aws.ec2.services.AMIClient; +import org.jclouds.aws.ec2.services.AvailabilityZoneAndRegionClient; import org.jclouds.aws.ec2.services.ElasticIPAddressClient; import org.jclouds.aws.ec2.services.InstanceClient; import org.jclouds.aws.ec2.services.KeyPairClient; @@ -69,4 +70,9 @@ public interface EC2Client { * Provides synchronous access to Monitoring services. */ MonitoringClient getMonitoringServices(); + + /** + * Provides synchronous access to Availability Zones and Regions services. + */ + AvailabilityZoneAndRegionClient getAvailabilityZoneAndRegionServices(); } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2PropertiesBuilder.java b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2PropertiesBuilder.java index 46e9e30d9e..71303236e5 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2PropertiesBuilder.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2PropertiesBuilder.java @@ -43,7 +43,7 @@ public class EC2PropertiesBuilder extends HttpPropertiesBuilder { @Override protected Properties defaultProperties() { Properties properties = super.defaultProperties(); - properties.setProperty(PROPERTY_EC2_ENDPOINT, "http://ec2.amazonaws.com"); + properties.setProperty(PROPERTY_EC2_ENDPOINT, "https://ec2.amazonaws.com"); properties.setProperty(PROPERTY_EC2_EXPIREINTERVAL, "60"); return properties; } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/config/EC2RestClientModule.java b/aws/core/src/main/java/org/jclouds/aws/ec2/config/EC2RestClientModule.java index 25768d4655..34b1b72128 100755 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/config/EC2RestClientModule.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/config/EC2RestClientModule.java @@ -25,18 +25,22 @@ package org.jclouds.aws.ec2.config; import java.net.URI; import java.util.Date; +import java.util.Map; import java.util.concurrent.TimeUnit; import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.aws.ec2.EC2; +import org.jclouds.aws.ec2.domain.Region; import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.aws.ec2.filters.FormSigner; import org.jclouds.aws.ec2.predicates.InstanceStateRunning; import org.jclouds.aws.ec2.reference.EC2Constants; import org.jclouds.aws.ec2.services.AMIAsyncClient; import org.jclouds.aws.ec2.services.AMIClient; +import org.jclouds.aws.ec2.services.AvailabilityZoneAndRegionAsyncClient; +import org.jclouds.aws.ec2.services.AvailabilityZoneAndRegionClient; import org.jclouds.aws.ec2.services.ElasticIPAddressAsyncClient; import org.jclouds.aws.ec2.services.ElasticIPAddressClient; import org.jclouds.aws.ec2.services.InstanceAsyncClient; @@ -88,6 +92,12 @@ public class EC2RestClientModule extends AbstractModule { bindRetryHandlers(); } + @Provides + @Singleton + Map provideRegions(AvailabilityZoneAndRegionClient client) { + return client.describeRegions(); + } + @Provides @TimeStamp protected String provideTimeStamp(final DateService dateService, @@ -181,6 +191,21 @@ public class EC2RestClientModule extends AbstractModule { return SyncProxy.create(MonitoringClient.class, client); } + @Provides + @Singleton + protected AvailabilityZoneAndRegionAsyncClient provideAvailabilityZoneAndRegionAsyncClient( + RestClientFactory factory) { + return factory.create(AvailabilityZoneAndRegionAsyncClient.class); + } + + @Provides + @Singleton + public AvailabilityZoneAndRegionClient provideAvailabilityZoneAndRegionClient( + AvailabilityZoneAndRegionAsyncClient client) throws IllegalArgumentException, + SecurityException, NoSuchMethodException { + return SyncProxy.create(AvailabilityZoneAndRegionClient.class, client); + } + @Provides @Singleton @EC2 diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZone.java b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZone.java new file mode 100644 index 0000000000..11d53d7fdf --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZone.java @@ -0,0 +1,53 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.CaseFormat; + +/** + * + * Availability zones used for all ec2 instance commands. + * + * @author Adrian Cole + */ +public enum AvailabilityZone { + + UNKNOWN, EU_WEST_1A, EU_WEST_1B, US_EAST_1A, US_EAST_1B, US_EAST_1C, US_EAST_1D, US_WEST_1A, US_WEST_1B; + + public String value() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name()); + } + + @Override + public String toString() { + return value(); + } + + public static AvailabilityZone fromValue(String availablilityZone) { + return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull( + availablilityZone, "availablilityZone"))); + } +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZoneInfo.java b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZoneInfo.java new file mode 100644 index 0000000000..a51596fbc2 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/AvailabilityZoneInfo.java @@ -0,0 +1,167 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Set; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; + +/** + * + * @see + * @author Adrian Cole + */ +public class AvailabilityZoneInfo implements Comparable{ + + public static enum State { + UNKNOWN, AVAILABLE; + public String value() { + return name().toLowerCase(); + } + + @Override + public String toString() { + return value(); + } + + public static State fromValue(String state) { + return valueOf(checkNotNull(state, "state").toUpperCase()); + } + } + + private final String zoneName; + private final AvailabilityZone zone; + private final State state; + private final Region region; + private final Set messages = Sets.newHashSet(); + + public AvailabilityZoneInfo(String zoneName, AvailabilityZone zone, State zoneState, + Region region, Iterable messages) { + this.zoneName = checkNotNull(zoneName, "zoneName"); + this.zone = checkNotNull(zone, "zone"); + this.state = checkNotNull(zoneState, "zoneState"); + this.region = checkNotNull(region, "region"); + Iterables.addAll(this.messages, checkNotNull(messages, "messages")); + } + + /** + * Name of the Availability Zone. + */ + public String getZoneName() { + return zoneName; + } + + /** + * the Availability Zone. + */ + public AvailabilityZone getZone() { + return zone; + } + + /** + * State of the Availability Zone. + */ + public State getState() { + return state; + } + + /** + * Name of the Region. + */ + public Region getRegion() { + return region; + } + + /** + * Messages + */ + public Set getMessages() { + return messages; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((messages == null) ? 0 : messages.hashCode()); + result = prime * result + ((region == null) ? 0 : region.hashCode()); + result = prime * result + ((state == null) ? 0 : state.hashCode()); + result = prime * result + ((zone == null) ? 0 : zone.hashCode()); + result = prime * result + ((zoneName == null) ? 0 : zoneName.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; + AvailabilityZoneInfo other = (AvailabilityZoneInfo) obj; + if (messages == null) { + if (other.messages != null) + return false; + } else if (!messages.equals(other.messages)) + return false; + if (region == null) { + if (other.region != null) + return false; + } else if (!region.equals(other.region)) + return false; + if (state == null) { + if (other.state != null) + return false; + } else if (!state.equals(other.state)) + return false; + if (zone == null) { + if (other.zone != null) + return false; + } else if (!zone.equals(other.zone)) + return false; + if (zoneName == null) { + if (other.zoneName != null) + return false; + } else if (!zoneName.equals(other.zoneName)) + return false; + return true; + } + + @Override + public String toString() { + return "AvailabilityZoneInfo [messages=" + messages + ", region=" + region + ", state=" + + state + ", zone=" + zone + ", zoneName=" + zoneName + "]"; + } + + @Override + public int compareTo(AvailabilityZoneInfo that) { + return zoneName.compareTo(that.zoneName); + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/domain/Region.java b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/Region.java new file mode 100644 index 0000000000..8bbc4b692c --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/Region.java @@ -0,0 +1,53 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.CaseFormat; + +/** + * + * Regions used for all ec2 commands. + * + * @author Adrian Cole + */ +public enum Region { + + DEFAULT, UNKNOWN, EU_WEST_1, US_EAST_1, US_WEST_1; + + public String value() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name()); + } + + @Override + public String toString() { + return value(); + } + + public static Region fromValue(String region) { + return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(region, + "region"))); + } +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/functions/RegionToEndpoint.java b/aws/core/src/main/java/org/jclouds/aws/ec2/functions/RegionToEndpoint.java new file mode 100644 index 0000000000..aec9a7c22d --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/functions/RegionToEndpoint.java @@ -0,0 +1,56 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.functions; + +import java.net.URI; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.aws.ec2.EC2; +import org.jclouds.aws.ec2.domain.Region; + +import com.google.common.base.Function; + +/** + * + * @author Adrian Cole + */ +@Singleton +public class RegionToEndpoint implements Function { + private final Map regionToEndpoint; + private final URI defaultUri; + + @Inject + public RegionToEndpoint(Map regionToEndpoint, @EC2 URI defaultUri) { + this.regionToEndpoint = regionToEndpoint; + this.defaultUri = defaultUri; + } + + public URI apply(Object from) { + return from.equals(Region.DEFAULT) ? defaultUri : regionToEndpoint.get(from); + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2AsyncClientImpl.java b/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2AsyncClientImpl.java index 69cdb3df87..ab90bb2d15 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2AsyncClientImpl.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2AsyncClientImpl.java @@ -30,6 +30,7 @@ import javax.inject.Singleton; import org.jclouds.aws.ec2.EC2AsyncClient; import org.jclouds.aws.ec2.services.AMIAsyncClient; +import org.jclouds.aws.ec2.services.AvailabilityZoneAndRegionAsyncClient; import org.jclouds.aws.ec2.services.ElasticIPAddressAsyncClient; import org.jclouds.aws.ec2.services.InstanceAsyncClient; import org.jclouds.aws.ec2.services.KeyPairAsyncClient; @@ -49,12 +50,15 @@ public class EC2AsyncClientImpl implements EC2AsyncClient { private final KeyPairAsyncClient keyPairServices; private final SecurityGroupAsyncClient securityGroupServices; private final MonitoringAsyncClient monitoringServices; + private final AvailabilityZoneAndRegionAsyncClient availabilityZoneAndRegionServices; @Inject public EC2AsyncClientImpl(AMIAsyncClient AMIServices, ElasticIPAddressAsyncClient elasticIPAddressServices, InstanceAsyncClient instanceServices, KeyPairAsyncClient keyPairServices, - SecurityGroupAsyncClient securityGroupServices, MonitoringAsyncClient monitoringServices) { + SecurityGroupAsyncClient securityGroupServices, + MonitoringAsyncClient monitoringServices, + AvailabilityZoneAndRegionAsyncClient availabilityZoneAndRegionServices) { this.AMIServices = checkNotNull(AMIServices, "AMIServices"); this.elasticIPAddressServices = checkNotNull(elasticIPAddressServices, "elasticIPAddressServices"); @@ -62,6 +66,8 @@ public class EC2AsyncClientImpl implements EC2AsyncClient { this.keyPairServices = checkNotNull(keyPairServices, "keyPairServices"); this.securityGroupServices = checkNotNull(securityGroupServices, "securityGroupServices"); this.monitoringServices = checkNotNull(monitoringServices, "monitoringServices"); + this.availabilityZoneAndRegionServices = checkNotNull(availabilityZoneAndRegionServices, + "availabilityZoneAndRegionServices"); } /** @@ -102,9 +108,15 @@ public class EC2AsyncClientImpl implements EC2AsyncClient { /** * {@inheritDoc} */ - @Override public MonitoringAsyncClient getMonitoringServices() { return monitoringServices; } + /** + * {@inheritDoc} + */ + public AvailabilityZoneAndRegionAsyncClient getAvailabilityZoneAndRegionServices() { + return availabilityZoneAndRegionServices; + } + } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2ClientImpl.java b/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2ClientImpl.java index 236f29713d..c384e197ad 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2ClientImpl.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/internal/EC2ClientImpl.java @@ -30,6 +30,7 @@ import javax.inject.Singleton; import org.jclouds.aws.ec2.EC2Client; import org.jclouds.aws.ec2.services.AMIClient; +import org.jclouds.aws.ec2.services.AvailabilityZoneAndRegionClient; import org.jclouds.aws.ec2.services.ElasticIPAddressClient; import org.jclouds.aws.ec2.services.InstanceClient; import org.jclouds.aws.ec2.services.KeyPairClient; @@ -49,11 +50,13 @@ public class EC2ClientImpl implements EC2Client { private final KeyPairClient keyPairServices; private final SecurityGroupClient securityGroupServices; private final MonitoringClient monitoringServices; + private final AvailabilityZoneAndRegionClient availabilityZoneAndRegionServices; @Inject public EC2ClientImpl(AMIClient AMIServices, ElasticIPAddressClient elasticIPAddressServices, InstanceClient instanceServices, KeyPairClient keyPairServices, - SecurityGroupClient securityGroupServices, MonitoringClient monitoringServices) { + SecurityGroupClient securityGroupServices, MonitoringClient monitoringServices, + AvailabilityZoneAndRegionClient availabilityZoneAndRegionServices) { this.AMIServices = checkNotNull(AMIServices, "AMIServices"); this.elasticIPAddressServices = checkNotNull(elasticIPAddressServices, "elasticIPAddressServices"); @@ -61,6 +64,8 @@ public class EC2ClientImpl implements EC2Client { this.keyPairServices = checkNotNull(keyPairServices, "keyPairServices"); this.securityGroupServices = checkNotNull(securityGroupServices, "securityGroupServices"); this.monitoringServices = checkNotNull(monitoringServices, "monitoringServices"); + this.availabilityZoneAndRegionServices = checkNotNull(availabilityZoneAndRegionServices, + "availabilityZoneAndRegionServices"); } /** @@ -105,4 +110,11 @@ public class EC2ClientImpl implements EC2Client { return monitoringServices; } + /** + * {@inheritDoc} + */ + public AvailabilityZoneAndRegionClient getAvailabilityZoneAndRegionServices() { + return availabilityZoneAndRegionServices; + } + } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeAvailabilityZonesOptions.java b/aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeAvailabilityZonesOptions.java new file mode 100644 index 0000000000..19bf2afff8 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeAvailabilityZonesOptions.java @@ -0,0 +1,77 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.options; + +import java.util.Set; + +import org.jclouds.aws.ec2.domain.AvailabilityZone; +import org.jclouds.aws.ec2.options.internal.BaseEC2RequestOptions; + +/** + * Contains options supported in the Form API for the DescribeAvailabilityZones operation.

+ * Usage

The recommended way to instantiate a DescribeAvailabilityZonesOptions object is to + * statically import DescribeAvailabilityZonesOptions.Builder.* and invoke a static creation method + * followed by an instance mutator (if needed): + *

+ * + * import static org.jclouds.aws.ec2.options.DescribeAvailabilityZonesOptions.Builder.* + *

+ * EC2Client connection = // get connection + * Future> images = connection.getAvailabilityZoneAndRegionServices().describeAvailabilityZones(zones("us-east-1a", "us-east-1b")); + * + * + * @author Adrian Cole + * @see + */ +public class DescribeAvailabilityZonesOptions extends BaseEC2RequestOptions { + + /** + * Availability Zone name. + */ + public DescribeAvailabilityZonesOptions zones(AvailabilityZone... zones) { + String[] zoneStrings = new String[zones.length]; + for (int i = 0; i < zoneStrings.length; i++) + zoneStrings[i] = zones[i].value(); + indexFormValuesWithPrefix("ZoneName", zoneStrings); + return this; + } + + public Set getZones() { + return getFormValuesWithKeysPrefixedBy("ZoneName."); + } + + public static class Builder { + + /** + * @see DescribeAvailabilityZonesOptions#zones(AvailabilityZone[] ) + */ + public static DescribeAvailabilityZonesOptions availabilityZones(AvailabilityZone... zones) { + DescribeAvailabilityZonesOptions options = new DescribeAvailabilityZonesOptions(); + return options.zones(zones); + } + + } +} diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeRegionsOptions.java b/aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeRegionsOptions.java new file mode 100644 index 0000000000..99bb92b70a --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/options/DescribeRegionsOptions.java @@ -0,0 +1,77 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.options; + +import java.util.Set; + +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.aws.ec2.options.internal.BaseEC2RequestOptions; + +/** + * Contains options supported in the Form API for the DescribeRegions operation.

+ * Usage

The recommended way to instantiate a DescribeRegionsOptions object is to statically + * import DescribeRegionsOptions.Builder.* and invoke a static creation method followed by an + * instance mutator (if needed): + *

+ * + * import static org.jclouds.aws.ec2.options.DescribeRegionsOptions.Builder.* + *

+ * EC2Client connection = // get connection + * Future> images = connection.getRegionsAndRegionsServices().describeRegions(regions("us-east-1a", "us-east-1b")); + * + * + * @author Adrian Cole + * @see + */ +public class DescribeRegionsOptions extends BaseEC2RequestOptions { + + /** + * Name of a Region. + */ + public DescribeRegionsOptions regions(Region... regions) { + String[] regionStrings = new String[regions.length]; + for (int i = 0; i < regionStrings.length; i++) + regionStrings[i] = regions[i].value(); + indexFormValuesWithPrefix("RegionName", regionStrings); + return this; + } + + public Set getZones() { + return getFormValuesWithKeysPrefixedBy("RegionName."); + } + + public static class Builder { + + /** + * @see DescribeRegionsOptions#regions(Region[] ) + */ + public static DescribeRegionsOptions regions(Region... regions) { + DescribeRegionsOptions options = new DescribeRegionsOptions(); + return options.regions(regions); + } + + } +} diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClient.java b/aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClient.java new file mode 100644 index 0000000000..5005e0976a --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClient.java @@ -0,0 +1,85 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.services; + +import static org.jclouds.aws.ec2.reference.EC2Parameters.ACTION; +import static org.jclouds.aws.ec2.reference.EC2Parameters.VERSION; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Future; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.jclouds.aws.ec2.EC2; +import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.aws.ec2.filters.FormSigner; +import org.jclouds.aws.ec2.functions.RegionToEndpoint; +import org.jclouds.aws.ec2.options.DescribeAvailabilityZonesOptions; +import org.jclouds.aws.ec2.options.DescribeRegionsOptions; +import org.jclouds.aws.ec2.xml.DescribeAvailabilityZonesResponseHandler; +import org.jclouds.aws.ec2.xml.DescribeRegionsResponseHandler; +import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; +import org.jclouds.rest.annotations.FormParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.VirtualHost; +import org.jclouds.rest.annotations.XMLResponseParser; + +/** + * Provides access to EC2 Availability Zones and Regions via their REST API. + *

+ * + * @author Adrian Cole + */ +@RequestFilters(FormSigner.class) +@FormParams(keys = VERSION, values = "2009-11-30") +@VirtualHost +public interface AvailabilityZoneAndRegionAsyncClient { + + /** + * @see AvailabilityZoneAndRegionClient#describeAvailabilityZonesInRegion + */ + @POST + @Path("/") + @FormParams(keys = ACTION, values = "DescribeAvailabilityZones") + @XMLResponseParser(DescribeAvailabilityZonesResponseHandler.class) + Future> describeAvailabilityZonesInRegion( + @EndpointParam(parser = RegionToEndpoint.class) Region region, + DescribeAvailabilityZonesOptions... options); + + /** + * @see AvailabilityZoneAndRegionClient#describeRegions + */ + @POST + @Endpoint(EC2.class) + @Path("/") + @FormParams(keys = ACTION, values = "DescribeRegions") + @XMLResponseParser(DescribeRegionsResponseHandler.class) + Future> describeRegions(DescribeRegionsOptions... options); + +} diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClient.java b/aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClient.java new file mode 100644 index 0000000000..1125bc93cf --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClient.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.services; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.aws.ec2.options.DescribeAvailabilityZonesOptions; +import org.jclouds.aws.ec2.options.DescribeRegionsOptions; +import org.jclouds.concurrent.Timeout; + +/** + * Provides EC2 Availability Zones and Regions services for EC2. + *

+ * + * @author Adrian Cole + */ +@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS) +public interface AvailabilityZoneAndRegionClient { + + /** + * Displays Availability Zones that are currently available to the account and their states. + * + * @see InstanceClient#runInstances + * @see #describeRegions + * + * @see + */ + Set describeAvailabilityZonesInRegion(Region region, + DescribeAvailabilityZonesOptions... options); + + /** + * Describes Regions that are currently available to the account. + * + * @see InstanceClient#runInstances + * @see #describeAvailabilityZones + * + * @see + */ + Map describeRegions(DescribeRegionsOptions... options); +} diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandler.java b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandler.java new file mode 100644 index 0000000000..791a45b640 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandler.java @@ -0,0 +1,110 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.xml; + +import java.util.Set; + +import javax.annotation.Resource; + +import org.jclouds.aws.ec2.domain.AvailabilityZone; +import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo.State; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.logging.Logger; +import org.xml.sax.Attributes; + +import com.google.common.collect.Sets; + +/** + * + * @author Adrian Cole + */ +public class DescribeAvailabilityZonesResponseHandler extends + ParseSax.HandlerWithResult> { + private StringBuilder currentText = new StringBuilder(); + + private Set availablilityZones = Sets.newLinkedHashSet(); + private AvailabilityZone zone; + @Resource + protected Logger logger = Logger.NULL; + private Region region; + private String zoneName; + private State zoneState; + private boolean inMessageSet; + private Set messages = Sets.newHashSet(); + + public Set getResult() { + return availablilityZones; + } + + public void startElement(String uri, String name, String qName, Attributes attrs) { + if (qName.equals("messageSet")) { + inMessageSet = true; + } + } + + public void endElement(String uri, String name, String qName) { + if (qName.equals("zoneName")) { + zoneName = currentText.toString().trim(); + try { + zone = AvailabilityZone.fromValue(zoneName); + } catch (IllegalArgumentException e) { + logger.warn(e, "unsupported region: %s", zoneName); + zone = AvailabilityZone.UNKNOWN; + } + } else if (qName.equals("regionName")) { + try { + region = Region.fromValue(currentText.toString().trim()); + } catch (IllegalArgumentException e) { + logger.warn(e, "unsupported region: %s", currentText.toString().trim()); + region = Region.UNKNOWN; + } + } else if (qName.equals("zoneState")) { + try { + zoneState = AvailabilityZoneInfo.State.fromValue(currentText.toString().trim()); + } catch (IllegalArgumentException e) { + logger.warn(e, "unsupported zoneState: %s", currentText.toString().trim()); + zoneState = AvailabilityZoneInfo.State.UNKNOWN; + } + } else if (qName.equals("message")) { + messages.add(currentText.toString().trim()); + } else if (qName.equals("messageSet")) { + inMessageSet = false; + } else if (qName.equals("item") && !inMessageSet) { + availablilityZones.add(new AvailabilityZoneInfo(zoneName, zone, zoneState, region, + messages)); + this.zone = null; + this.zoneName = null; + this.region = null; + this.zoneState = null; + this.messages = Sets.newHashSet(); + } + currentText = new StringBuilder(); + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } +} diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandler.java b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandler.java new file mode 100644 index 0000000000..4f62c2936e --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandler.java @@ -0,0 +1,75 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.xml; + +import java.net.URI; +import java.util.Map; + +import javax.annotation.Resource; + +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.logging.Logger; + +import com.google.common.collect.Maps; + +/** + * + * @author Adrian Cole + */ +public class DescribeRegionsResponseHandler extends ParseSax.HandlerWithResult> { + private StringBuilder currentText = new StringBuilder(); + + private Map regionEndpoints = Maps.newHashMap(); + private Region region; + private URI regionEndpoint; + @Resource + protected Logger logger = Logger.NULL; + + public Map getResult() { + return regionEndpoints; + } + + public void endElement(String uri, String name, String qName) { + if (qName.equals("regionName")) { + try { + region = Region.fromValue(currentText.toString().trim()); + } catch (IllegalArgumentException e) { + logger.warn(e, "unsupported region: %s", currentText.toString().trim()); + region = Region.UNKNOWN; + } + } else if (qName.equals("regionEndpoint")) { + regionEndpoint = URI.create(String.format("https://%s", currentText.toString().trim())); + } else if (qName.equals("item")) { + regionEndpoints.put(region, regionEndpoint); + this.region = null; + this.regionEndpoint = null; + } + currentText = new StringBuilder(); + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ContextBuilderTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ContextBuilderTest.java index a60e06d07e..665b92a69a 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ContextBuilderTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ContextBuilderTest.java @@ -54,7 +54,7 @@ public class EC2ContextBuilderTest { public void testNewBuilder() { EC2ContextBuilder builder = newBuilder(); assertEquals(builder.getProperties().getProperty(EC2Constants.PROPERTY_EC2_ENDPOINT), - "http://ec2.amazonaws.com"); + "https://ec2.amazonaws.com"); assertEquals(builder.getProperties().getProperty(PROPERTY_AWS_ACCESSKEYID), "id"); assertEquals(builder.getProperties().getProperty(PROPERTY_AWS_SECRETACCESSKEY), "secret"); } @@ -63,7 +63,7 @@ public class EC2ContextBuilderTest { RestContext context = newBuilder().buildContext(); assertEquals(context.getClass(), RestContextImpl.class); assertEquals(context.getAccount(), "id"); - assertEquals(context.getEndPoint(), URI.create("http://ec2.amazonaws.com")); + assertEquals(context.getEndPoint(), URI.create("https://ec2.amazonaws.com")); } public void testBuildInjector() { diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClientTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClientTest.java new file mode 100644 index 0000000000..8d2cc3c925 --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionAsyncClientTest.java @@ -0,0 +1,202 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.services; + +import static org.jclouds.aws.ec2.options.DescribeAvailabilityZonesOptions.Builder.availabilityZones; +import static org.jclouds.aws.ec2.options.DescribeRegionsOptions.Builder.regions; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.Map; + +import javax.inject.Singleton; + +import org.jclouds.aws.ec2.EC2; +import org.jclouds.aws.ec2.domain.AvailabilityZone; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.aws.ec2.filters.FormSigner; +import org.jclouds.aws.ec2.options.DescribeAvailabilityZonesOptions; +import org.jclouds.aws.ec2.options.DescribeRegionsOptions; +import org.jclouds.aws.ec2.xml.DescribeAvailabilityZonesResponseHandler; +import org.jclouds.aws.ec2.xml.DescribeRegionsResponseHandler; +import org.jclouds.aws.reference.AWSConstants; +import org.jclouds.date.TimeStamp; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.logging.Logger; +import org.jclouds.logging.Logger.LoggerFactory; +import org.jclouds.rest.RestClientTest; +import org.jclouds.rest.internal.GeneratedHttpRequest; +import org.jclouds.rest.internal.RestAnnotationProcessor; +import org.jclouds.util.Jsr330; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.AbstractModule; +import com.google.inject.Module; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; + +/** + * Tests behavior of {@code AvailabilityZoneAndRegionAsyncClient} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ec2.AvailabilityZoneAndRegionAsyncClientTest") +public class AvailabilityZoneAndRegionAsyncClientTest extends + RestClientTest { + + public void testDescribeAvailabilityZones() throws SecurityException, NoSuchMethodException, + IOException { + Method method = AvailabilityZoneAndRegionAsyncClient.class.getMethod( + "describeAvailabilityZonesInRegion", Region.class, Array.newInstance( + DescribeAvailabilityZonesOptions.class, 0).getClass()); + GeneratedHttpRequest httpMethod = processor + .createRequest(method, Region.US_WEST_1); + + assertRequestLineEquals(httpMethod, "POST https://ec2.us-west-1.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual( + httpMethod, + "Content-Length: 51\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-west-1.amazonaws.com\n"); + assertPayloadEquals(httpMethod, "Version=2009-11-30&Action=DescribeAvailabilityZones"); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeAvailabilityZonesResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testDescribeAvailabilityZonesOptions() throws SecurityException, + NoSuchMethodException, IOException { + Method method = AvailabilityZoneAndRegionAsyncClient.class.getMethod( + "describeAvailabilityZonesInRegion", Region.class, Array.newInstance( + DescribeAvailabilityZonesOptions.class, 0).getClass()); + GeneratedHttpRequest httpMethod = processor + .createRequest(method, Region.US_EAST_1, availabilityZones( + AvailabilityZone.US_EAST_1A, AvailabilityZone.US_EAST_1B)); + + assertRequestLineEquals(httpMethod, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual( + httpMethod, + "Content-Length: 95\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.us-east-1.amazonaws.com\n"); + assertPayloadEquals(httpMethod, + "Version=2009-11-30&Action=DescribeAvailabilityZones&ZoneName.1=us-east-1a&ZoneName.2=us-east-1b"); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeAvailabilityZonesResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testDescribeRegions() throws SecurityException, NoSuchMethodException, IOException { + Method method = AvailabilityZoneAndRegionAsyncClient.class.getMethod("describeRegions", Array + .newInstance(DescribeRegionsOptions.class, 0).getClass()); + GeneratedHttpRequest httpMethod = processor + .createRequest(method); + + assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 41\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n"); + assertPayloadEquals(httpMethod, "Version=2009-11-30&Action=DescribeRegions"); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeRegionsResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testDescribeRegionsOptions() throws SecurityException, NoSuchMethodException, + IOException { + Method method = AvailabilityZoneAndRegionAsyncClient.class.getMethod("describeRegions", Array + .newInstance(DescribeRegionsOptions.class, 0).getClass()); + GeneratedHttpRequest httpMethod = processor + .createRequest(method, regions(Region.US_EAST_1, Region.US_WEST_1)); + + assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 87\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n"); + assertPayloadEquals(httpMethod, + "Version=2009-11-30&Action=DescribeRegions&RegionName.1=us-east-1&RegionName.2=us-west-1"); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeRegionsResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + @Override + protected void checkFilters(GeneratedHttpRequest httpMethod) { + assertEquals(httpMethod.getFilters().size(), 1); + assertEquals(httpMethod.getFilters().get(0).getClass(), FormSigner.class); + } + + @Override + protected TypeLiteral> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + + @Override + protected Module createModule() { + return new AbstractModule() { + @Override + protected void configure() { + bind(URI.class).annotatedWith(EC2.class).toInstance( + URI.create("https://ec2.amazonaws.com")); + bindConstant().annotatedWith(Jsr330.named(AWSConstants.PROPERTY_AWS_ACCESSKEYID)).to( + "user"); + bindConstant().annotatedWith(Jsr330.named(AWSConstants.PROPERTY_AWS_SECRETACCESSKEY)) + .to("key"); + bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() { + public Logger getLogger(String category) { + return Logger.NULL; + } + }); + } + + @SuppressWarnings("unused") + @Provides + @TimeStamp + String provide() { + return "2009-11-08T15:54:08.897Z"; + } + + @SuppressWarnings("unused") + @Singleton + @Provides + Map provideMap() { + return ImmutableMap. of(Region.DEFAULT, URI.create("https://booya"), + Region.EU_WEST_1, URI.create("https://ec2.eu-west-1.amazonaws.com"), + Region.US_EAST_1, URI.create("https://ec2.us-east-1.amazonaws.com"), + Region.US_WEST_1, URI.create("https://ec2.us-west-1.amazonaws.com")); + } + }; + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClientLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClientLiveTest.java new file mode 100644 index 0000000000..a2b11e12c8 --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/services/AvailabilityZoneAndRegionClientLiveTest.java @@ -0,0 +1,115 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.services; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.aws.ec2.options.DescribeAvailabilityZonesOptions.Builder.availabilityZones; +import static org.jclouds.aws.ec2.options.DescribeRegionsOptions.Builder.regions; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.net.URI; +import java.util.Iterator; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.Map.Entry; + +import org.jclouds.aws.ec2.EC2AsyncClient; +import org.jclouds.aws.ec2.EC2Client; +import org.jclouds.aws.ec2.EC2ContextFactory; +import org.jclouds.aws.ec2.domain.AvailabilityZone; +import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.rest.RestContext; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * Tests behavior of {@code AvailabilityZoneAndRegionClient} + * + * @author Adrian Cole + */ +@Test(groups = "live", sequential = true, testName = "ec2.AvailabilityZoneAndRegionClientLiveTest") +public class AvailabilityZoneAndRegionClientLiveTest { + + private AvailabilityZoneAndRegionClient client; + private RestContext context; + + @BeforeGroups(groups = { "live" }) + public void setupClient() { + String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user"); + String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key"); + + context = EC2ContextFactory.createContext(user, password, new Log4JLoggingModule()); + client = context.getApi().getAvailabilityZoneAndRegionServices(); + } + + public void testDescribeAvailabilityZones() { + for (Region region : ImmutableSet.of(Region.DEFAULT, Region.EU_WEST_1, Region.US_EAST_1, + Region.US_WEST_1)) { + SortedSet allResults = Sets.newTreeSet(client + .describeAvailabilityZonesInRegion(region)); + assertNotNull(allResults); + assert allResults.size() >= 2 : allResults.size(); + Iterator iterator = allResults.iterator(); + AvailabilityZone id1 = iterator.next().getZone(); + AvailabilityZone id2 = iterator.next().getZone(); + SortedSet twoResults = Sets.newTreeSet(client + .describeAvailabilityZonesInRegion(region, availabilityZones(id1, id2))); + assertNotNull(twoResults); + assertEquals(twoResults.size(), 2); + iterator = twoResults.iterator(); + assertEquals(iterator.next().getZone(), id1); + assertEquals(iterator.next().getZone(), id2); + } + } + + public void testDescribeRegions() { + SortedMap allResults = Maps.newTreeMap(); + allResults.putAll(client.describeRegions()); + assertNotNull(allResults); + assert allResults.size() >= 2 : allResults.size(); + Iterator> iterator = allResults.entrySet().iterator(); + Region r1 = iterator.next().getKey(); + Region r2 = iterator.next().getKey(); + SortedMap twoResults = Maps.newTreeMap(); + twoResults.putAll(client.describeRegions(regions(r1, r2))); + assertNotNull(twoResults); + assertEquals(twoResults.size(), 2); + iterator = twoResults.entrySet().iterator(); + assertEquals(iterator.next().getKey(), r1); + assertEquals(iterator.next().getKey(), r2); + } + + @AfterTest + public void shutdown() { + context.close(); + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandlerTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandlerTest.java new file mode 100644 index 0000000000..085fcb0c0b --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAvailabilityZonesResponseHandlerTest.java @@ -0,0 +1,69 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.xml; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; +import java.util.Set; + +import org.jclouds.aws.ec2.domain.AvailabilityZone; +import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +/** + * Tests behavior of {@code DescribeAvailabilityZonesResponseHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ec2.DescribeAvailabilityZonesResponseHandlerTest") +public class DescribeAvailabilityZonesResponseHandlerTest extends BaseHandlerTest { + + public void testApplyInputStream() { + + InputStream is = getClass().getResourceAsStream("/ec2/availabilityZones.xml"); + + Set expected = ImmutableSet. of( + new AvailabilityZoneInfo("us-east-1a", AvailabilityZone.US_EAST_1A, + AvailabilityZoneInfo.State.AVAILABLE, Region.US_EAST_1, ImmutableSet + . of()), new AvailabilityZoneInfo("us-east-1b", + AvailabilityZone.US_EAST_1B, AvailabilityZoneInfo.State.AVAILABLE, + Region.US_EAST_1, ImmutableSet. of()), new AvailabilityZoneInfo( + "us-east-1c", AvailabilityZone.US_EAST_1C, + AvailabilityZoneInfo.State.AVAILABLE, Region.US_EAST_1, ImmutableSet + . of("our service is awesome")), new AvailabilityZoneInfo( + "us-east-1d", AvailabilityZone.US_EAST_1D, + AvailabilityZoneInfo.State.UNKNOWN, Region.US_EAST_1, ImmutableSet + . of())); + Set result = factory.create( + injector.getInstance(DescribeAvailabilityZonesResponseHandler.class)).parse(is); + + assertEquals(result, expected); + } + +} \ No newline at end of file diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandlerTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandlerTest.java new file mode 100644 index 0000000000..64753a9b8e --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeRegionsResponseHandlerTest.java @@ -0,0 +1,96 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.xml; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; +import java.net.URI; +import java.util.Map; + +import org.jclouds.aws.ec2.EC2; +import org.jclouds.aws.ec2.domain.Region; +import org.jclouds.http.functions.BaseHandlerTest; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.http.functions.config.ParserModule; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; + +/** + * Tests behavior of {@code RegionEndpointHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ec2.RegionEndpointHandlerTest") +public class DescribeRegionsResponseHandlerTest extends BaseHandlerTest { + @BeforeTest + @Override + protected void setUpInjector() { + injector = Guice.createInjector(new ParserModule(), new AbstractModule() { + + @Override + protected void configure() { + bind(URI.class).annotatedWith(EC2.class).toInstance(URI.create("https://booya")); + } + + }); + factory = injector.getInstance(ParseSax.Factory.class); + assert factory != null; + } + + public void testApplyInputStream() { + + InputStream is = getClass().getResourceAsStream("/ec2/regionEndpoints.xml"); + + Map expected = ImmutableMap. of(Region.EU_WEST_1, URI + .create("https://ec2.eu-west-1.amazonaws.com"), Region.US_EAST_1, URI + .create("https://ec2.us-east-1.amazonaws.com"), Region.US_WEST_1, URI + .create("https://ec2.us-west-1.amazonaws.com")); + + Map result = factory.create( + injector.getInstance(DescribeRegionsResponseHandler.class)).parse(is); + + assertEquals(result, expected); + } + + public void testUnsupportedAdditionalRegionDoesntBreak() { + + InputStream is = getClass().getResourceAsStream("/ec2/regionEndpoints-additional.xml"); + + Map expected = ImmutableMap. of(Region.UNKNOWN, URI + .create("https://ec2.jp-west-1.amazonaws.com"), Region.EU_WEST_1, URI + .create("https://ec2.eu-west-1.amazonaws.com"), Region.US_EAST_1, URI + .create("https://ec2.us-east-1.amazonaws.com"), Region.US_WEST_1, URI + .create("https://ec2.us-west-1.amazonaws.com")); + + Map result = factory.create( + injector.getInstance(DescribeRegionsResponseHandler.class)).parse(is); + + assertEquals(result, expected); + } +} diff --git a/aws/core/src/test/resources/ec2/availabilityZones.xml b/aws/core/src/test/resources/ec2/availabilityZones.xml new file mode 100644 index 0000000000..be08a7a062 --- /dev/null +++ b/aws/core/src/test/resources/ec2/availabilityZones.xml @@ -0,0 +1,35 @@ + + + ec786fbb-338a-4f6f-a479-293773911366 + + + us-east-1a + available + us-east-1 + + + + us-east-1b + available + us-east-1 + + + + us-east-1c + available + us-east-1 + + + our service is awesome + + + + + us-east-1d + downlikeaclown + us-east-1 + + + + \ No newline at end of file diff --git a/aws/core/src/test/resources/ec2/regionEndpoints-additional.xml b/aws/core/src/test/resources/ec2/regionEndpoints-additional.xml new file mode 100644 index 0000000000..38e27f6baa --- /dev/null +++ b/aws/core/src/test/resources/ec2/regionEndpoints-additional.xml @@ -0,0 +1,22 @@ + + + 2bffb2f8-3b03-4be9-92bd-a35b27a2f51a + + + eu-west-1 + ec2.eu-west-1.amazonaws.com + + + us-east-1 + ec2.us-east-1.amazonaws.com + + + us-west-1 + ec2.us-west-1.amazonaws.com + + + jp-west-1 + ec2.jp-west-1.amazonaws.com + + + \ No newline at end of file diff --git a/aws/core/src/test/resources/ec2/regionEndpoints.xml b/aws/core/src/test/resources/ec2/regionEndpoints.xml new file mode 100644 index 0000000000..3849b8e6e6 --- /dev/null +++ b/aws/core/src/test/resources/ec2/regionEndpoints.xml @@ -0,0 +1,18 @@ + + + 2bffb2f8-3b03-4be9-92bd-a35b27a2f51a + + + eu-west-1 + ec2.eu-west-1.amazonaws.com + + + us-east-1 + ec2.us-east-1.amazonaws.com + + + us-west-1 + ec2.us-west-1.amazonaws.com + + + \ No newline at end of file diff --git a/azure/src/main/java/org/jclouds/azure/storage/blob/AzureBlobUtil.java b/azure/src/main/java/org/jclouds/azure/storage/blob/AzureBlobUtil.java index 21601921f5..cfa22ddae8 100644 --- a/azure/src/main/java/org/jclouds/azure/storage/blob/AzureBlobUtil.java +++ b/azure/src/main/java/org/jclouds/azure/storage/blob/AzureBlobUtil.java @@ -33,7 +33,7 @@ import org.jclouds.azure.storage.filters.SharedKeyAuthentication; import org.jclouds.azure.storage.reference.AzureStorageHeaders; import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404; import org.jclouds.http.functions.ParseContentMD5FromHeaders; -import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.RequestFilters; @@ -58,6 +58,6 @@ public interface AzureBlobUtil { @ResponseParser(ParseContentMD5FromHeaders.class) @ExceptionParser(ThrowKeyNotFoundOn404.class) @Path("{key}") - byte[] getMD5(@Endpoint URI container, @PathParam("key") String key); + byte[] getMD5(@EndpointParam URI container, @PathParam("key") String key); } diff --git a/core/src/main/java/org/jclouds/compute/NodeService.java b/core/src/main/java/org/jclouds/compute/NodeService.java new file mode 100644 index 0000000000..4047a9e741 --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/NodeService.java @@ -0,0 +1,67 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute; + +import java.util.SortedSet; + +import org.jclouds.compute.domain.CreateNodeResponse; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeIdentity; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Size; + +/** + * + * @author Ivan Meredith + * @author Adrian Cole + */ +public interface NodeService { + + /** + * List all nodes available to the current user + */ + SortedSet listNode(); + + /** + * Find all nodes matching the specified name + */ + SortedSet getNodeByName(String name); + + /** + * Create a new node given the name, image, and size. + * + */ + CreateNodeResponse createNode(String name, Image image, Size size); + + /** + * destroy the node. + */ + void destroyNode(String id); + + /** + * Find a node by its id + */ + NodeMetadata getNodeMetadata(String id); + +} diff --git a/core/src/main/java/org/jclouds/compute/NodeServiceFactory.java b/core/src/main/java/org/jclouds/compute/NodeServiceFactory.java new file mode 100644 index 0000000000..a06550b808 --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/NodeServiceFactory.java @@ -0,0 +1,59 @@ +package org.jclouds.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.Properties; + +import javax.inject.Inject; + +import org.jclouds.domain.Credentials; +import org.jclouds.http.HttpPropertiesBuilder; +import org.jclouds.rest.RestContextBuilder; + +import com.google.inject.Module; + +/** + * + * @author Adrian Cole + */ +public class NodeServiceFactory { + private final Properties properties; + + @Inject + public NodeServiceFactory(Properties properties) { + this.properties = properties; + } + + public NodeService create(URI provider, Module... modules) { + return create(provider, Credentials.parse(provider), modules); + } + + @SuppressWarnings("unchecked") + public NodeService create(URI provider, Credentials creds, Module... modules) { + String hint = checkNotNull(provider.getHost(), "host"); + String account = checkNotNull(creds.account, "account"); + String key = creds.key; + String propertiesBuilderKey = String.format("%s.propertiesbuilder", hint); + String propertiesBuilderClassName = checkNotNull( + properties.getProperty(propertiesBuilderKey), propertiesBuilderKey); + + String contextBuilderKey = String.format("%s.contextbuilder", hint); + String contextBuilderClassName = checkNotNull(properties.getProperty(contextBuilderKey), + contextBuilderKey); + + try { + Class propertiesBuilderClass = (Class) Class + .forName(propertiesBuilderClassName); + Class> contextBuilderClass = (Class>) Class + .forName(contextBuilderClassName); + + HttpPropertiesBuilder builder = propertiesBuilderClass.getConstructor(String.class, + String.class).newInstance(account, key); + return contextBuilderClass.getConstructor(Properties.class).newInstance(builder.build()) + .withModules(modules).buildInjector().getInstance(NodeService.class); + } catch (Exception e) { + throw new RuntimeException("error instantiating " + contextBuilderClassName, e); + } + } +} diff --git a/core/src/main/java/org/jclouds/compute/domain/CreateNodeResponse.java b/core/src/main/java/org/jclouds/compute/domain/CreateNodeResponse.java new file mode 100644 index 0000000000..18b91358ee --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/CreateNodeResponse.java @@ -0,0 +1,36 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain; + +import org.jclouds.domain.Credentials; + +/** + * @author Adrian Cole + * @author Ivan Meredith + */ +public interface CreateNodeResponse extends NodeMetadata { + + Credentials getCredentials(); + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/compute/domain/Image.java.new b/core/src/main/java/org/jclouds/compute/domain/Image.java.new new file mode 100644 index 0000000000..20d328ef5e --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/Image.java.new @@ -0,0 +1,51 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain; + +import java.util.Map; + +/** + * Configured operating system used to start nodes. + * + * @author Adrian Cole + */ +public interface Image { + /** + * Unique ID provided by the provider (ami-abcd1234, etc) + * + */ + String getId(); + + /** + * Name provided by the provider (Ubuntu 8.1) + * + */ + String getName(); + + /** + * Other variables present that the provider supports + */ + Map getExtra(); + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/compute/domain/NodeIdentity.java b/core/src/main/java/org/jclouds/compute/domain/NodeIdentity.java new file mode 100644 index 0000000000..0fc1756997 --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/NodeIdentity.java @@ -0,0 +1,49 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain; + +import org.jclouds.compute.domain.internal.NodeIdentityImpl; + +import com.google.inject.ImplementedBy; + +/** + * @author Ivan Meredith + * @author Adrian Cole + */ +@ImplementedBy(NodeIdentityImpl.class) +public interface NodeIdentity extends Comparable { + + /** + * unique id of the server. potentially generated by the service. + * + */ + public String getId(); + + /** + * user defined name of the server. + * + */ + public String getName(); + +} diff --git a/core/src/main/java/org/jclouds/compute/domain/NodeMetadata.java b/core/src/main/java/org/jclouds/compute/domain/NodeMetadata.java new file mode 100644 index 0000000000..cb34ca35a1 --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/NodeMetadata.java @@ -0,0 +1,49 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain; + +import java.net.InetAddress; +import java.util.Map; +import java.util.SortedSet; + +/** + * @author Adrian Cole + * @author Ivan Meredith + */ +public interface NodeMetadata extends NodeIdentity { + NodeState getState(); + + SortedSet getPublicAddresses(); + + SortedSet getPrivateAddresses(); + + int getLoginPort(); + + LoginType getLoginType(); + + /** + * Other variables present that the provider supports + */ + Map getExtra(); +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/compute/domain/NodeState.java b/core/src/main/java/org/jclouds/compute/domain/NodeState.java new file mode 100644 index 0000000000..531809d39c --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/NodeState.java @@ -0,0 +1,26 @@ +package org.jclouds.compute.domain; + +/** + * Indicates the status of a node + * + * @author Adrian Cole + */ +public enum NodeState { + /** + * The node is in transition + */ + PENDING, + /** + * The node is not running + */ + TERMINATED, + /** + * The node is deployed, but suspended + */ + SUSPENDED, + /** + * The node is available for requests + */ + RUNNING; + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/compute/domain/Profile.java.new b/core/src/main/java/org/jclouds/compute/domain/Profile.java.new new file mode 100644 index 0000000000..022826fcef --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/Profile.java.new @@ -0,0 +1,33 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain; + +/** + * @author Adrian Cole + */ +public interface Profile { + Image getImage(); + + Size getSize(); +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/compute/domain/Size.java b/core/src/main/java/org/jclouds/compute/domain/Size.java new file mode 100644 index 0000000000..9f276b7deb --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/Size.java @@ -0,0 +1,79 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain; + +import java.util.Map; + +/** + * Configured operating system used to start nodes. + * + * @author Adrian Cole + */ +public interface Size { + /** + * Unique ID provided by the provider (m1.small, etc) + * + */ + String getId(); + + /** + * Name provided by the provider (Small CPU, etc) + * + */ + String getName(); + + /** + * Amount of virtual or physical cores provided + */ + Integer getCores(); + + /** + * Amount of RAM provided in MB (256M, 1740) + */ + Long getRam(); + + /** + * Amount of boot disk provided in GB (200) + */ + Long getDisk(); + + /** + * Amount of total transfer bandwidth in GB + */ + Long getBandwidth(); + + /** + * + * Hourly price of this server in USD, estimated if monthly. + * + * @return + */ + Float getPrice(); + + /** + * Other variables present that the provider supports + */ + Map getExtra(); + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/compute/domain/internal/NodeIdentityImpl.java b/core/src/main/java/org/jclouds/compute/domain/internal/NodeIdentityImpl.java new file mode 100644 index 0000000000..8dc2375b99 --- /dev/null +++ b/core/src/main/java/org/jclouds/compute/domain/internal/NodeIdentityImpl.java @@ -0,0 +1,96 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.compute.domain.internal; + +import org.jclouds.compute.domain.NodeIdentity; + +/** + * @author Adrian Cole + * @author Ivan Meredith + */ +public class NodeIdentityImpl implements NodeIdentity { + + private final String id; + private final String name; + + public NodeIdentityImpl(String id, String name) { + this.id = id; + this.name = name; + } + + /** + * {@inheritDoc} + */ + public String getId() { + return id; + } + + /** + * {@inheritDoc} + */ + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + public int compareTo(NodeIdentity o) { + if (getName() == null) + return -1; + return (this == o) ? 0 : getName().compareTo(o.getName()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((name == null) ? 0 : name.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; + NodeIdentityImpl other = (NodeIdentityImpl) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + +} diff --git a/core/src/main/java/org/jclouds/rest/RestContextBuilder.java b/core/src/main/java/org/jclouds/rest/RestContextBuilder.java index 298bd3d904..d005b0c9d7 100755 --- a/core/src/main/java/org/jclouds/rest/RestContextBuilder.java +++ b/core/src/main/java/org/jclouds/rest/RestContextBuilder.java @@ -141,7 +141,6 @@ public abstract class RestContextBuilder { public boolean apply(Module input) { return input.getClass().isAnnotationPresent(RequiresHttp.class); } - })) { modules.add(new RestModule()); } diff --git a/core/src/main/java/org/jclouds/rest/annotations/Endpoint.java b/core/src/main/java/org/jclouds/rest/annotations/Endpoint.java index 9481e9fa92..5b6e021c61 100644 --- a/core/src/main/java/org/jclouds/rest/annotations/Endpoint.java +++ b/core/src/main/java/org/jclouds/rest/annotations/Endpoint.java @@ -24,7 +24,6 @@ package org.jclouds.rest.annotations; import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -37,11 +36,8 @@ import java.lang.annotation.Target; * * @author Adrian Cole */ -@Target( { TYPE, METHOD, PARAMETER }) +@Target( { TYPE, METHOD }) @Retention(RUNTIME) public @interface Endpoint { - public static @interface NONE { - } - - Class value() default NONE.class; + Class value(); } diff --git a/core/src/main/java/org/jclouds/rest/annotations/EndpointParam.java b/core/src/main/java/org/jclouds/rest/annotations/EndpointParam.java new file mode 100644 index 0000000000..36d7391796 --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/annotations/EndpointParam.java @@ -0,0 +1,59 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.rest.annotations; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.net.URI; + +import javax.inject.Singleton; +import javax.ws.rs.PathParam; + +import com.google.common.base.Function; + +/** + * Extracts the endpoint of a parameter from an object. + * + * @see PathParam + * @author Adrian Cole + */ +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface EndpointParam { + @Singleton + public static class ReturnSame implements Function { + + @Override + public URI apply(Object from) { + // TODO check arg; + return (URI) from; + } + + } + + Class> parser() default ReturnSame.class; +} diff --git a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java index 5e453eb181..4101cea4ce 100755 --- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java +++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java @@ -25,7 +25,6 @@ package org.jclouds.rest.internal; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; import java.io.InputStream; import java.lang.annotation.Annotation; @@ -79,6 +78,7 @@ import org.jclouds.rest.Binder; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.FormParams; import org.jclouds.rest.annotations.Headers; @@ -129,6 +129,7 @@ public class RestAnnotationProcessor { private final Map>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class); private final Map>> methodToIndexOfParamToHostPrefixParamAnnotations = createMethodToIndexOfParamToAnnotation(HostPrefixParam.class); private final Map>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class); + private final Map>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class); private final Map>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class); private final Map>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class); private final Map>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class); @@ -212,7 +213,8 @@ public class RestAnnotationProcessor { } @VisibleForTesting - public Function createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(Method method) { + public Function createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation( + Method method) { ExceptionParser annotation = method.getAnnotation(ExceptionParser.class); if (annotation != null) { return injector.getInstance(annotation.value()); @@ -252,6 +254,7 @@ public class RestAnnotationProcessor { methodToIndexOfParamToFormParamAnnotations.get(method).get(index); methodToIndexOfParamToQueryParamAnnotations.get(method).get(index); methodToIndexOfParamToEndpointAnnotations.get(method).get(index); + methodToIndexOfParamToEndpointParamAnnotations.get(method).get(index); methodToIndexOfParamToPathParamAnnotations.get(method).get(index); methodToIndexOfParamToPostParamAnnotations.get(method).get(index); methodToIndexOfParamToParamParserAnnotations.get(method).get(index); @@ -581,22 +584,16 @@ public class RestAnnotationProcessor { @VisibleForTesting URI getEndpointInParametersOrNull(Method method, Object... args) { - Map> map = indexWithOnlyOneAnnotation(method, "@Endpoint", - methodToIndexOfParamToEndpointAnnotations); + Map> map = indexWithOnlyOneAnnotation(method, "@EndpointParam", + methodToIndexOfParamToEndpointParamAnnotations); if (map.size() == 1 && args.length > 0) { - Endpoint annotation = (Endpoint) map.values().iterator().next().iterator().next(); + EndpointParam annotation = (EndpointParam) map.values().iterator().next().iterator() + .next(); int index = map.keySet().iterator().next(); - checkState( - annotation.value() == Endpoint.NONE.class, - String - .format( - "@Endpoint annotation at index %d on method %s should not have a value() except Endpoint.NONE ", - index, method)); + Function parser = injector.getInstance(annotation.parser()); Object arg = checkNotNull(args[index], String.format("argument at index %d on method %s", index, method)); - checkArgument(arg instanceof URI, String.format( - "argument at index %d must be a URI for method %s", index, method)); - return (URI) arg; + return parser.apply(arg); } return null; } @@ -1094,14 +1091,8 @@ public class RestAnnotationProcessor { Endpoint annotation; if (method.isAnnotationPresent(Endpoint.class)) { annotation = method.getAnnotation(Endpoint.class); - checkState(annotation.value() != Endpoint.NONE.class, String.format( - "@Endpoint annotation at method %s must have a value() of valid Qualifier", - method)); } else if (declaring.isAnnotationPresent(Endpoint.class)) { annotation = declaring.getAnnotation(Endpoint.class); - checkState(annotation.value() != Endpoint.NONE.class, String.format( - "@Endpoint annotation at type %s must have a value() of valid Qualifier", - declaring)); } else { throw new IllegalStateException( "There must be an @Endpoint annotation on parameter, method or type: " diff --git a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java index 836743900a..f9ba4f088e 100755 --- a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java +++ b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java @@ -83,6 +83,7 @@ import org.jclouds.logging.Logger.LoggerFactory; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.FormParams; import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.HostPrefixParam; @@ -311,7 +312,7 @@ public class RestAnnotationProcessorTest { } @POST - public void foo(@Endpoint URI endpoint) { + public void foo(@EndpointParam URI endpoint) { } } diff --git a/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/PCSAsyncClient.java b/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/PCSAsyncClient.java index e210f663e6..54663f61ae 100644 --- a/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/PCSAsyncClient.java +++ b/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/PCSAsyncClient.java @@ -52,6 +52,7 @@ import org.jclouds.mezeo.pcs2.xml.ContainerHandler; import org.jclouds.mezeo.pcs2.xml.FileHandler; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.RequestFilters; @@ -90,7 +91,7 @@ public interface PCSAsyncClient { @GET @XMLResponseParser(ContainerHandler.class) @Headers(keys = "X-Cloud-Depth", values = "2") - Future list(@Endpoint URI container); + Future list(@EndpointParam URI container); /** * @see PCSAsyncClient#createContainer @@ -105,7 +106,7 @@ public interface PCSAsyncClient { */ @POST @Path("/contents") - Future createContainer(@Endpoint URI parent, + Future createContainer(@EndpointParam URI parent, @BinderParam(BindContainerNameToXmlPayload.class) String container); /** @@ -113,14 +114,14 @@ public interface PCSAsyncClient { */ @DELETE @ExceptionParser(ReturnVoidOnNotFoundOr404.class) - Future deleteContainer(@Endpoint URI container); + Future deleteContainer(@EndpointParam URI container); /** * @see PCSAsyncClient#uploadFile */ @POST @Path("/contents") - Future uploadFile(@Endpoint URI container, + Future uploadFile(@EndpointParam URI container, @BinderParam(BindPCSFileToMultipartForm.class) PCSFile object); /** @@ -128,7 +129,7 @@ public interface PCSAsyncClient { */ @POST @Path("/contents") - Future createFile(@Endpoint URI container, + Future createFile(@EndpointParam URI container, @BinderParam(BindFileInfoToXmlPayload.class) PCSFile object); /** @@ -136,7 +137,7 @@ public interface PCSAsyncClient { */ @PUT @Path("/content") - Future uploadBlock(@Endpoint URI file, + Future uploadBlock(@EndpointParam URI file, @BinderParam(BindDataToPayload.class) PCSFile object, PutBlockOptions... options); /** @@ -144,7 +145,7 @@ public interface PCSAsyncClient { */ @DELETE @ExceptionParser(ReturnVoidOnNotFoundOr404.class) - Future deleteFile(@Endpoint URI file); + Future deleteFile(@EndpointParam URI file); /** * @see PCSAsyncClient#downloadFile @@ -152,7 +153,7 @@ public interface PCSAsyncClient { @GET @ExceptionParser(ThrowKeyNotFoundOn404.class) @Path("/content") - Future downloadFile(@Endpoint URI file); + Future downloadFile(@EndpointParam URI file); /** * @see PCSAsyncClient#getFileInfo @@ -161,14 +162,14 @@ public interface PCSAsyncClient { @ExceptionParser(ThrowKeyNotFoundOn404.class) @XMLResponseParser(FileHandler.class) @Headers(keys = "X-Cloud-Depth", values = "2") - Future getFileInfo(@Endpoint URI file); + Future getFileInfo(@EndpointParam URI file); /** * @see PCSAsyncClient#putMetadataItem */ @PUT @Path("/metadata/{key}") - Future putMetadataItem(@Endpoint URI resource, @PathParam("key") String key, + Future putMetadataItem(@EndpointParam URI resource, @PathParam("key") String key, @BinderParam(BindToStringPayload.class) String value); /** @@ -177,6 +178,6 @@ public interface PCSAsyncClient { @GET @ResponseParser(AddMetadataItemIntoMap.class) @Path("/metadata/{key}") - Future addMetadataItemToMap(@Endpoint URI resource, @PathParam("key") String key, + Future addMetadataItemToMap(@EndpointParam URI resource, @PathParam("key") String key, Map map); } diff --git a/nirvanix/sdn/core/src/main/java/org/jclouds/nirvanix/sdn/SDNAsyncClient.java b/nirvanix/sdn/core/src/main/java/org/jclouds/nirvanix/sdn/SDNAsyncClient.java index 5d95c40d54..2b5853394f 100644 --- a/nirvanix/sdn/core/src/main/java/org/jclouds/nirvanix/sdn/SDNAsyncClient.java +++ b/nirvanix/sdn/core/src/main/java/org/jclouds/nirvanix/sdn/SDNAsyncClient.java @@ -44,6 +44,7 @@ import org.jclouds.nirvanix.sdn.functions.ParseUploadInfoFromJsonResponse; import org.jclouds.nirvanix.sdn.reference.SDNQueryParams; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.OverrideRequestFilters; import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.RequestFilters; @@ -80,7 +81,7 @@ public interface SDNAsyncClient { */ @POST @Path("/Upload.ashx") - Future upload(@Endpoint URI endpoint, + Future upload(@EndpointParam URI endpoint, @QueryParam(SDNQueryParams.UPLOADTOKEN) String uploadToken, @QueryParam(SDNQueryParams.DESTFOLDERPATH) String folderPath, @BinderParam(BindBlobToMultipartForm.class) Blob blob); diff --git a/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/AddSessionTokenToRequestTest.java b/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/AddSessionTokenToRequestTest.java index 4bb9c155cb..e3ac80974a 100755 --- a/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/AddSessionTokenToRequestTest.java +++ b/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/AddSessionTokenToRequestTest.java @@ -39,7 +39,7 @@ import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.Logger; import org.jclouds.logging.Logger.LoggerFactory; import org.jclouds.nirvanix.sdn.SessionToken; -import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.config.RestModule; import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RuntimeDelegateImpl; @@ -62,7 +62,7 @@ public class AddSessionTokenToRequestTest { private static interface TestService { @POST - public void foo(@Endpoint URI endpoint); + public void foo(@EndpointParam URI endpoint); } @DataProvider diff --git a/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/InsertUserContextIntoPathTest.java b/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/InsertUserContextIntoPathTest.java index 9a403f9e22..d539fb4943 100644 --- a/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/InsertUserContextIntoPathTest.java +++ b/nirvanix/sdn/core/src/test/java/org/jclouds/nirvanix/sdn/filters/InsertUserContextIntoPathTest.java @@ -40,7 +40,7 @@ import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.Logger; import org.jclouds.logging.Logger.LoggerFactory; import org.jclouds.nirvanix.sdn.reference.SDNConstants; -import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.config.RestModule; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.RestAnnotationProcessor; @@ -66,7 +66,7 @@ public class InsertUserContextIntoPathTest { private static interface TestService { @POST - public void foo(@Endpoint URI endpoint); + public void foo(@EndpointParam URI endpoint); } public void testRequestInvalid() {