completed route53 zone commands

This commit is contained in:
adriancole 2013-01-28 11:51:57 -08:00
parent 037eff184b
commit a827a481b9
21 changed files with 656 additions and 318 deletions

View File

@ -42,7 +42,7 @@ public interface Route53Api {
*
* @param changeID
* The ID of the change batch request.
* @return nulll, if not found
* @return null, if not found
*/
Change getChange(String changeID);

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.route53.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
@ -28,51 +30,6 @@ import com.google.common.base.Objects;
* @author Adrian Cole
*/
public final class Change {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().from(this);
}
public final static class Builder {
private String id;
private Status status;
private Date submittedAt;
/**
* @see Change#getId()
*/
public Builder id(String id) {
this.id = id;
return this;
}
/**
* @see Change#getStatus()
*/
public Builder status(Status status) {
this.status = status;
return this;
}
/**
* @see Change#getSubmittedAt()
*/
public Builder submittedAt(Date submittedAt) {
this.submittedAt = submittedAt;
return this;
}
public Change build() {
return new Change(id, status, submittedAt);
}
public Builder from(Change in) {
return this.id(in.id).status(in.status).submittedAt(in.submittedAt);
}
}
private final String id;
private final Status status;
@ -135,17 +92,18 @@ public final class Change {
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
if (obj == null || getClass() != obj.getClass())
return false;
if (getClass() != obj.getClass())
return false;
Change other = (Change) obj;
return Objects.equal(this.id, other.id);
Change other = Change.class.cast(obj);
return equal(this.id, other.id);
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("id", id).add("status", status).add("submittedAt", submittedAt)
.toString();
return toStringHelper(this).add("id", id).add("status", status).add("submittedAt", submittedAt).toString();
}
public static Change create(String id, Status status, Date submittedAt) {
return new Change(id, status, submittedAt);
}
}

View File

@ -0,0 +1,87 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.route53.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
/**
*
* @author Adrian Cole
*/
public final class NewZone {
private final ZoneAndNameServers zone;
private final Change change;
private NewZone(ZoneAndNameServers zone, Change change) {
this.zone = checkNotNull(zone, "zone");
this.change = checkNotNull(change, "change of %s", zone);
}
/**
* @see ZoneAndNameServers#getZone()
*/
public Zone getZone() {
return zone.getZone();
}
/**
* @see ZoneAndNameServers#getNameServers()
*/
public ImmutableList<String> getNameServers() {
return zone.getNameServers();
}
/**
* the zone creation event
*/
public Change getChange() {
return change;
}
@Override
public int hashCode() {
return Objects.hashCode(zone);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
NewZone that = NewZone.class.cast(obj);
return equal(this.zone, that.zone);
}
@Override
public String toString() {
return toStringHelper("").add("zone", zone.getZone()).add("nameServers", zone.getNameServers())
.add("change", change).toString();
}
public static NewZone create(ZoneAndNameServers zone, Change change) {
return new NewZone(zone, change);
}
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.route53.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
@ -28,6 +30,76 @@ import com.google.common.base.Optional;
* @author Adrian Cole
*/
public final class Zone {
private final String id;
private final String name;
private final String callerReference;
private final int resourceRecordSetCount;
private final Optional<String> comment;
private Zone(String id, String name, String callerReference, int resourceRecordSetCount, Optional<String> comment) {
this.id = checkNotNull(id, "id");
this.name = checkNotNull(name, "name");
this.callerReference = checkNotNull(callerReference, "callerReference for %s", name);
this.resourceRecordSetCount = checkNotNull(resourceRecordSetCount, "resourceRecordSetCount for %s", name);
this.comment = checkNotNull(comment, "comment for %s", comment);
}
/**
* The ID of the hosted zone.
*/
public String getId() {
return id;
}
/**
* The name of the domain.
*/
public String getName() {
return name;
}
/**
* A unique string that identifies the request to create the hosted zone.
*/
public String getCallerReference() {
return callerReference;
}
/**
* A percentage value that indicates the size of the policy in packed form.
*/
public int getResourceRecordSetCount() {
return resourceRecordSetCount;
}
public Optional<String> getComment() {
return comment;
}
@Override
public int hashCode() {
return Objects.hashCode(id, name, callerReference);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
Zone other = Zone.class.cast(obj);
return equal(this.id, other.id) && equal(this.name, other.name)
&& equal(this.callerReference, other.callerReference);
}
@Override
public String toString() {
return toStringHelper(this).omitNullValues().add("id", id).add("name", name)
.add("callerReference", callerReference).add("resourceRecordSetCount", resourceRecordSetCount)
.add("comment", comment.orNull()).toString();
}
public static Builder builder() {
return new Builder();
}
@ -92,76 +164,4 @@ public final class Zone {
.resourceRecordSetCount(in.resourceRecordSetCount).comment(in.comment.orNull());
}
}
private final String id;
private final String name;
private final String callerReference;
private final int resourceRecordSetCount;
private final Optional<String> comment;
private Zone(String id, String name, String callerReference, int resourceRecordSetCount,
Optional<String> comment) {
this.id = checkNotNull(id, "id");
this.name = checkNotNull(name, "name");
this.callerReference = checkNotNull(callerReference, "callerReference for %s", name);
this.resourceRecordSetCount = checkNotNull(resourceRecordSetCount, "resourceRecordSetCount for %s", name);
this.comment = checkNotNull(comment, "comment for %s", comment);
}
/**
* The ID of the hosted zone.
*/
public String getId() {
return id;
}
/**
* The name of the domain.
*/
public String getName() {
return name;
}
/**
* A unique string that identifies the request to create the hosted zone.
*/
public String getCallerReference() {
return callerReference;
}
/**
* A percentage value that indicates the size of the policy in packed form.
*/
public int getResourceRecordSetCount() {
return resourceRecordSetCount;
}
public Optional<String> getComment() {
return comment;
}
@Override
public int hashCode() {
return Objects.hashCode(id, name, callerReference);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Zone other = (Zone) obj;
return Objects.equal(this.id, other.id) && Objects.equal(this.name, other.name)
&& Objects.equal(this.callerReference, other.callerReference);
}
@Override
public String toString() {
return Objects.toStringHelper(this).omitNullValues().add("id", id).add("name", name)
.add("callerReference", callerReference).add("resourceRecordSetCount", resourceRecordSetCount)
.add("comment", comment.orNull()).toString();
}
}

View File

@ -18,67 +18,23 @@
*/
package org.jclouds.route53.domain;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableList;
/**
*
* @author Adrian Cole
*/
public final class ZoneAndNameServers {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().from(this);
}
public final static class Builder {
private Zone zone;
private ImmutableSet.Builder<String> nameServers = ImmutableSet.<String> builder();
/**
* @see ZoneAndNameServers#getZone()
*/
public Builder zone(Zone zone) {
this.zone = zone;
return this;
}
/**
* @see ZoneAndNameServers#getNameServers()
*/
public Builder nameServers(Iterable<String> nameServers) {
this.nameServers = ImmutableSet.<String> builder().addAll(checkNotNull(nameServers, "nameServers"));
return this;
}
/**
* @see ZoneAndNameServers#getNameServers()
*/
public Builder addNameServer(String nameServer) {
this.nameServers.add(checkNotNull(nameServer, "nameServer"));
return this;
}
public ZoneAndNameServers build() {
return new ZoneAndNameServers(zone, nameServers.build());
}
public Builder from(ZoneAndNameServers in) {
return this.zone(in.zone).nameServers(in.nameServers);
}
}
private final Zone zone;
private final ImmutableSet<String> nameServers;
private final ImmutableList<String> nameServers;
private ZoneAndNameServers(Zone zone, ImmutableSet<String> nameServers) {
private ZoneAndNameServers(Zone zone, ImmutableList<String> nameServers) {
this.zone = checkNotNull(zone, "zone");
this.nameServers = checkNotNull(nameServers, "nameServers for %s", zone);
}
@ -93,7 +49,7 @@ public final class ZoneAndNameServers {
/**
* the authoritative name servers for the hosted zone
*/
public Set<String> getNameServers() {
public ImmutableList<String> getNameServers() {
return nameServers;
}
@ -106,16 +62,18 @@ public final class ZoneAndNameServers {
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
if (obj == null || getClass() != obj.getClass())
return false;
if (getClass() != obj.getClass())
return false;
ZoneAndNameServers that = (ZoneAndNameServers) obj;
return Objects.equal(this.zone, that.zone) && Objects.equal(this.nameServers, that.nameServers);
ZoneAndNameServers that = ZoneAndNameServers.class.cast(obj);
return equal(this.zone, that.zone) && equal(this.nameServers, that.nameServers);
}
@Override
public String toString() {
return Objects.toStringHelper("").add("zone", zone).add("nameServers", nameServers).toString();
return toStringHelper("").add("zone", zone).add("nameServers", nameServers).toString();
}
public static ZoneAndNameServers create(Zone zone, Iterable<String> nameServers) {
return new ZoneAndNameServers(zone, ImmutableList.<String> copyOf(checkNotNull(nameServers, "nameServers")));
}
}

View File

@ -24,31 +24,49 @@ import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.route53.domain.Change;
import org.jclouds.route53.domain.Change.Status;
import org.jclouds.route53.domain.NewZone;
import org.jclouds.route53.domain.Zone;
import org.jclouds.route53.domain.ZoneAndNameServers;
import org.jclouds.route53.options.ListZonesOptions;
/**
* @see ZoneAsyncApi
* @see <a href="http://docs.aws.amazon.com/Route53/latest/APIReference/ActionsOnHostedZones.html" />
* @see <a href=
* "http://docs.aws.amazon.com/Route53/latest/APIReference/ActionsOnHostedZones.html"
* />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ZoneApi {
/**
* Retrieves information about the specified zone, including its nameserver configuration
* This action creates a new hosted zone.
*
* <h4>Note</h4>
*
* You cannot create a hosted zone for a top-level domain (TLD).
*
* @param name
* Name of the zone to get information about.
* @return null if not found
* The name of the domain. ex. {@code www.example.com.} The
* trailing dot is optional.
* @param callerReference
* A unique string that identifies the request and allows safe
* retries. ex. {@code MyDNSMigration_01}
* @return the new zone in progress, in {@link Status#PENDING}.
*/
@Nullable
ZoneAndNameServers get(String name);
NewZone createWithReference(String name, String callerReference);
/**
* Lists the zones that have the specified path prefix. If there are none, the action returns an
* empty list.
* like {@link #createWithReference(String, String)}, except you can specify
* a comment.
*/
NewZone createWithReferenceAndComment(String name, String callerReference, String comment);
/**
* Lists the zones that have the specified path prefix. If there are none,
* the action returns an empty list.
*
* <br/>
* You can paginate the results using the {@link ListZonesOptions parameter}
@ -61,11 +79,32 @@ public interface ZoneApi {
IterableWithMarker<Zone> list(ListZonesOptions options);
/**
* Lists the zones that have the specified path prefix. If there are none, the action returns an
* empty list.
* Lists the zones that have the specified path prefix. If there are none,
* the action returns an empty list.
*
* @return the response object
*/
PagedIterable<Zone> list();
/**
* Retrieves information about the specified zone, including its nameserver
* configuration
*
* @param id
* id of the zone to get information about. ex
* {@code Z1PA6795UKMFR9}
* @return null if not found
*/
@Nullable
ZoneAndNameServers get(String id);
/**
* This action deletes a hosted zone.
*
* @param id
* id of the zone to delete. ex {@code Z1PA6795UKMFR9}
* @return null if not found or the change in progress
*/
@Nullable
Change delete(String id);
}

View File

@ -18,24 +18,35 @@
*/
package org.jclouds.route53.features;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
import javax.inject.Named;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.route53.domain.Change;
import org.jclouds.route53.domain.NewZone;
import org.jclouds.route53.domain.Zone;
import org.jclouds.route53.domain.ZoneAndNameServers;
import org.jclouds.route53.filters.RestAuthentication;
import org.jclouds.route53.functions.ZonesToPagedIterable;
import org.jclouds.route53.options.ListZonesOptions;
import org.jclouds.route53.xml.ChangeHandler;
import org.jclouds.route53.xml.CreateHostedZoneResponseHandler;
import org.jclouds.route53.xml.GetHostedZoneResponseHandler;
import org.jclouds.route53.xml.ListHostedZonesResponseHandler;
@ -52,16 +63,29 @@ import com.google.common.util.concurrent.ListenableFuture;
@VirtualHost
@Path("/{jclouds.api-version}")
public interface ZoneAsyncApi {
/**
* @see ZoneApi#createWithReference
*/
@Named("CreateHostedZone")
@POST
@Produces(APPLICATION_XML)
@Path("/hostedzone")
@Payload("<CreateHostedZoneRequest xmlns=\"https://route53.amazonaws.com/doc/2012-02-29/\"><Name>{name}</Name><CallerReference>{callerReference}</CallerReference></CreateHostedZoneRequest>")
@XMLResponseParser(CreateHostedZoneResponseHandler.class)
ListenableFuture<NewZone> createWithReference(@PayloadParam("name") String name,
@PayloadParam("callerReference") String callerReference);
/**
* @see ZoneApi#get()
* @see ZoneApi#createWithReferenceAndComment
*/
@Named("GetHostedZone")
@GET
@Path("{zoneId}")
@XMLResponseParser(GetHostedZoneResponseHandler.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<ZoneAndNameServers> get(@PathParam("zoneId") String zoneId);
@Named("CreateHostedZone")
@POST
@Produces(APPLICATION_XML)
@Path("/hostedzone")
@Payload("<CreateHostedZoneRequest xmlns=\"https://route53.amazonaws.com/doc/2012-02-29/\"><Name>{name}</Name><CallerReference>{callerReference}</CallerReference><HostedZoneConfig><Comment>{comment}</Comment></HostedZoneConfig></CreateHostedZoneRequest>")
@XMLResponseParser(CreateHostedZoneResponseHandler.class)
ListenableFuture<NewZone> createWithReferenceAndComment(@PayloadParam("name") String name,
@PayloadParam("callerReference") String callerReference, @PayloadParam("comment") String comment);
/**
* @see ZoneApi#list()
@ -82,4 +106,23 @@ public interface ZoneAsyncApi {
@XMLResponseParser(ListHostedZonesResponseHandler.class)
ListenableFuture<IterableWithMarker<Zone>> list(ListZonesOptions options);
/**
* @see ZoneApi#get()
*/
@Named("GetHostedZone")
@GET
@Path("/hostedzone/{zoneId}")
@XMLResponseParser(GetHostedZoneResponseHandler.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<ZoneAndNameServers> get(@PathParam("zoneId") String zoneId);
/**
* @see ZoneApi#delete()
*/
@Named("DeleteHostedZone")
@DELETE
@Path("/hostedzone/{zoneId}")
@XMLResponseParser(ChangeHandler.class)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Change> delete(@PathParam("zoneId") String zoneId);
}

View File

@ -18,13 +18,17 @@
*/
package org.jclouds.route53.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import java.util.Date;
import javax.inject.Inject;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.route53.domain.Change;
import org.jclouds.route53.domain.Change.Status;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
/**
* @see <a href=
@ -42,25 +46,34 @@ public class ChangeHandler extends ParseSax.HandlerForGeneratedRequestWithResult
}
private StringBuilder currentText = new StringBuilder();
private Change.Builder builder = Change.builder();
private String id;
private Status status;
private Date submittedAt;
@Override
public Change getResult() {
try {
return builder.build();
return Change.create(id, status, submittedAt);
} finally {
builder = Change.builder();
id = null;
status = null;
submittedAt = null;
}
}
@Override
public void startElement(String url, String name, String qName, Attributes attributes) {
}
@Override
public void endElement(String uri, String name, String qName) {
if (qName.equals("Id")) {
builder.id(SaxUtils.currentOrNull(currentText));
id = currentOrNull(currentText).replace("/change/", "");
} else if (qName.equals("Status")) {
builder.status(Status.fromValue(SaxUtils.currentOrNull(currentText)));
status = Status.fromValue(currentOrNull(currentText));
} else if (qName.equals("SubmittedAt")) {
builder.submittedAt(dateService.iso8601DateParse(SaxUtils.currentOrNull(currentText)));
submittedAt = dateService.iso8601DateParse(currentOrNull(currentText));
}
currentText = new StringBuilder();
}

View File

@ -0,0 +1,89 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.route53.xml;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.route53.domain.NewZone;
import org.jclouds.route53.domain.ZoneAndNameServers;
import org.xml.sax.Attributes;
import com.google.inject.Inject;
/**
* @see <a href=
* "http://docs.aws.amazon.com/Route53/latest/APIReference/API_CreateHostedZone.html"
* />
*
* @author Adrian Cole
*/
public class CreateHostedZoneResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<NewZone> {
private final GetHostedZoneResponseHandler zoneHandler;
private final ChangeHandler changeHandler;
private boolean inChange;
@Inject
public CreateHostedZoneResponseHandler(GetHostedZoneResponseHandler zoneHandler, ChangeHandler changeHandler) {
this.zoneHandler = zoneHandler;
this.changeHandler = changeHandler;
}
@Override
public NewZone getResult() {
ZoneAndNameServers zone = zoneHandler.getResult();
return NewZone.create(zone, changeHandler.getResult());
}
@Override
public void startElement(String url, String name, String qName, Attributes attributes) {
if (equalsOrSuffix(qName, "ChangeInfo")) {
inChange = true;
}
if (inChange) {
changeHandler.startElement(url, name, qName, attributes);
} else {
zoneHandler.startElement(url, name, qName, attributes);
}
}
@Override
public void endElement(String uri, String name, String qName) {
if (inChange) {
if (qName.equals("ChangeInfo")) {
inChange = false;
} else {
changeHandler.endElement(uri, name, qName);
}
} else {
zoneHandler.endElement(uri, name, qName);
}
}
@Override
public void characters(char ch[], int start, int length) {
if (inChange) {
changeHandler.characters(ch, start, length);
} else {
zoneHandler.characters(ch, start, length);
}
}
}

View File

@ -18,12 +18,16 @@
*/
package org.jclouds.route53.xml;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.route53.domain.ZoneAndNameServers;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.route53.domain.Zone;
import org.jclouds.route53.domain.ZoneAndNameServers;
import org.xml.sax.Attributes;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.inject.Inject;
/**
@ -38,9 +42,12 @@ public class GetHostedZoneResponseHandler extends ParseSax.HandlerForGeneratedRe
private final ZoneHandler zoneHandler;
private StringBuilder currentText = new StringBuilder();
private ZoneAndNameServers.Builder builder = ZoneAndNameServers.builder();
private boolean inZone;
private Zone zone;
private Builder<String> nameServers = ImmutableList.<String> builder();
@Inject
public GetHostedZoneResponseHandler(ZoneHandler zoneHandler) {
this.zoneHandler = zoneHandler;
@ -49,15 +56,16 @@ public class GetHostedZoneResponseHandler extends ParseSax.HandlerForGeneratedRe
@Override
public ZoneAndNameServers getResult() {
try {
return builder.build();
return ZoneAndNameServers.create(zone, nameServers.build());
} finally {
builder = ZoneAndNameServers.builder();
zone = null;
nameServers = ImmutableList.<String> builder();
}
}
@Override
public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
if (SaxUtils.equalsOrSuffix(qName, "HostedZone")) {
public void startElement(String url, String name, String qName, Attributes attributes) {
if (equalsOrSuffix(qName, "HostedZone")) {
inZone = true;
}
if (inZone) {
@ -66,16 +74,16 @@ public class GetHostedZoneResponseHandler extends ParseSax.HandlerForGeneratedRe
}
@Override
public void endElement(String uri, String name, String qName) throws SAXException {
public void endElement(String uri, String name, String qName) {
if (inZone) {
if (qName.equals("HostedZone")) {
inZone = false;
builder.zone(zoneHandler.getResult());
zone = zoneHandler.getResult();
} else {
zoneHandler.endElement(uri, name, qName);
}
} else if (qName.equals("NameServer")) {
builder.addNameServer(SaxUtils.currentOrNull(currentText));
nameServers.add(currentOrNull(currentText));
}
currentText = new StringBuilder();

View File

@ -18,13 +18,14 @@
*/
package org.jclouds.route53.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.route53.domain.Zone;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
@ -52,9 +53,6 @@ public class ListHostedZonesResponseHandler extends
this.zoneHandler = zoneHandler;
}
/**
* {@inheritDoc}
*/
@Override
public IterableWithMarker<Zone> getResult() {
try {
@ -64,12 +62,9 @@ public class ListHostedZonesResponseHandler extends
}
}
/**
* {@inheritDoc}
*/
@Override
public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
if (SaxUtils.equalsOrSuffix(qName, "HostedZones")) {
public void startElement(String url, String name, String qName, Attributes attributes) {
if (equalsOrSuffix(qName, "HostedZones")) {
inZones = true;
}
if (inZones) {
@ -77,11 +72,8 @@ public class ListHostedZonesResponseHandler extends
}
}
/**
* {@inheritDoc}
*/
@Override
public void endElement(String uri, String name, String qName) throws SAXException {
public void endElement(String uri, String name, String qName) {
if (inZones) {
if (qName.equals("HostedZones")) {
inZones = false;
@ -91,15 +83,12 @@ public class ListHostedZonesResponseHandler extends
zoneHandler.endElement(uri, name, qName);
}
} else if (qName.equals("NextMarker")) {
afterMarker = SaxUtils.currentOrNull(currentText);
afterMarker = currentOrNull(currentText);
}
currentText = new StringBuilder();
}
/**
* {@inheritDoc}
*/
@Override
public void characters(char ch[], int start, int length) {
if (inZones) {
@ -108,5 +97,4 @@ public class ListHostedZonesResponseHandler extends
currentText.append(ch, start, length);
}
}
}

View File

@ -22,6 +22,7 @@ import static org.jclouds.util.SaxUtils.currentOrNull;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.route53.domain.Zone;
import org.xml.sax.Attributes;
/**
*
@ -32,9 +33,6 @@ public class ZoneHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Z
private StringBuilder currentText = new StringBuilder();
private Zone.Builder builder = Zone.builder();
/**
* {@inheritDoc}
*/
@Override
public Zone getResult() {
try {
@ -44,10 +42,14 @@ public class ZoneHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Z
}
}
@Override
public void startElement(String url, String name, String qName, Attributes attributes) {
}
@Override
public void endElement(String uri, String name, String qName) {
if (qName.equals("Id")) {
builder.id(currentOrNull(currentText));
builder.id(currentOrNull(currentText).replace("/hostedzone/", ""));
} else if (qName.equals("Name")) {
builder.name(currentOrNull(currentText));
} else if (qName.equals("CallerReference")) {
@ -64,5 +66,4 @@ public class ZoneHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Z
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -27,6 +27,8 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.route53.Route53Api;
import org.jclouds.route53.internal.BaseRoute53ApiExpectTest;
import org.jclouds.route53.parse.CreateHostedZoneResponseTest;
import org.jclouds.route53.parse.GetChangeResponseTest;
import org.jclouds.route53.parse.GetHostedZoneResponseTest;
import org.jclouds.route53.parse.ListHostedZonesResponseTest;
import org.testng.annotations.Test;
@ -38,9 +40,45 @@ import com.google.common.collect.ImmutableSet;
*/
@Test(groups = "unit", testName = "ZoneApiExpectTest")
public class ZoneApiExpectTest extends BaseRoute53ApiExpectTest {
HttpRequest createWithReference = HttpRequest.builder().method("POST")
.endpoint("https://route53.amazonaws.com/2012-02-29/hostedzone")
.addHeader("Host", "route53.amazonaws.com")
.addHeader("Date", "Mon, 21 Jan 02013 19:29:03 -0800")
.addHeader("X-Amzn-Authorization",
"AWS3-HTTPS AWSAccessKeyId=identity,Algorithm=HmacSHA256,Signature=pylxNiLcrsjNRZOsxyT161JCwytVPHyc2rFfmNCuZKI=")
.payload(
payloadFromStringWithContentType(
"<CreateHostedZoneRequest xmlns=\"https://route53.amazonaws.com/doc/2012-02-29/\"><Name>jclouds.org.</Name><CallerReference>expect</CallerReference></CreateHostedZoneRequest>",
"application/xml")).build();
HttpResponse createResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/new_zone.xml", "text/xml")).build();
public void testCreateWithReferenceWhenResponseIs2xx() {
Route53Api success = requestSendsResponse(createWithReference, createResponse);
assertEquals(success.getZoneApi().createWithReference("jclouds.org.", "expect").toString(),
new CreateHostedZoneResponseTest().expected().toString());
}
HttpRequest createWithReferenceAndComment = HttpRequest.builder().method("POST")
.endpoint("https://route53.amazonaws.com/2012-02-29/hostedzone")
.addHeader("Host", "route53.amazonaws.com")
.addHeader("Date", "Mon, 21 Jan 02013 19:29:03 -0800")
.addHeader("X-Amzn-Authorization",
"AWS3-HTTPS AWSAccessKeyId=identity,Algorithm=HmacSHA256,Signature=pylxNiLcrsjNRZOsxyT161JCwytVPHyc2rFfmNCuZKI=")
.payload(
payloadFromStringWithContentType(
"<CreateHostedZoneRequest xmlns=\"https://route53.amazonaws.com/doc/2012-02-29/\"><Name>jclouds.org.</Name><CallerReference>expect</CallerReference><HostedZoneConfig><Comment>comment</Comment></HostedZoneConfig></CreateHostedZoneRequest>",
"application/xml")).build();
public void testCreateWithReferenceAndCommentWhenResponseIs2xx() {
Route53Api success = requestSendsResponse(createWithReferenceAndComment, createResponse);
assertEquals(success.getZoneApi().createWithReferenceAndComment("jclouds.org.", "expect", "comment").toString(),
new CreateHostedZoneResponseTest().expected().toString());
}
HttpRequest get = HttpRequest.builder().method("GET")
.endpoint("https://route53.amazonaws.com/2012-02-29//hostedzone/Z1XTHCPEFRWV1X")
.endpoint("https://route53.amazonaws.com/2012-02-29/hostedzone/Z1XTHCPEFRWV1X")
.addHeader("Host", "route53.amazonaws.com")
.addHeader("Date", "Mon, 21 Jan 02013 19:29:03 -0800")
.addHeader("X-Amzn-Authorization",
@ -51,16 +89,16 @@ public class ZoneApiExpectTest extends BaseRoute53ApiExpectTest {
.payload(payloadFromResourceWithContentType("/hosted_zone.xml", "text/xml")).build();
public void testGetWhenResponseIs2xx() {
Route53Api apiWhenExist = requestSendsResponse(get, getResponse);
assertEquals(apiWhenExist.getZoneApi().get("/hostedzone/Z1XTHCPEFRWV1X").toString(), new GetHostedZoneResponseTest().expected()
Route53Api success = requestSendsResponse(get, getResponse);
assertEquals(success.getZoneApi().get("Z1XTHCPEFRWV1X").toString(), new GetHostedZoneResponseTest().expected()
.toString());
}
HttpResponse notFound = HttpResponse.builder().statusCode(404).build();
public void testGetWhenResponseIs404() {
Route53Api apiWhenDontExist = requestSendsResponse(get, notFound);
assertNull(apiWhenDontExist.getZoneApi().get("/hostedzone/Z1XTHCPEFRWV1X"));
Route53Api fail = requestSendsResponse(get, notFound);
assertNull(fail.getZoneApi().get("Z1XTHCPEFRWV1X"));
}
HttpRequest list = HttpRequest.builder().method("GET")
@ -75,16 +113,16 @@ public class ZoneApiExpectTest extends BaseRoute53ApiExpectTest {
.payload(payloadFromResourceWithContentType("/hosted_zones.xml", "text/xml")).build();
public void testListWhenResponseIs2xx() {
Route53Api apiWhenExist = requestSendsResponse(list, listResponse);
assertEquals(apiWhenExist.getZoneApi().list().get(0).toString(), new ListHostedZonesResponseTest().expected()
Route53Api success = requestSendsResponse(list, listResponse);
assertEquals(success.getZoneApi().list().get(0).toString(), new ListHostedZonesResponseTest().expected()
.toString());
}
// TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testListWhenResponseIs404() {
Route53Api apiWhenDontExist = requestSendsResponse(list, notFound);
assertEquals(apiWhenDontExist.getZoneApi().list().get(0).toImmutableSet(), ImmutableSet.of());
Route53Api fail = requestSendsResponse(list, notFound);
assertEquals(fail.getZoneApi().list().get(0).toImmutableSet(), ImmutableSet.of());
}
HttpRequest listWithOptions = HttpRequest.builder().method("GET")
@ -101,13 +139,33 @@ public class ZoneApiExpectTest extends BaseRoute53ApiExpectTest {
new ListHostedZonesResponseTest().expected().toString());
}
public void testList2PagesWhenResponseIs2xx() {
HttpResponse noMore = HttpResponse.builder().statusCode(200)
.payload(payloadFromStringWithContentType("<ListHostedZonesResponse />", "text/xml")).build();
Route53Api apiWhenExist = requestsSendResponses(list, listResponse, listWithOptions, noMore);
assertEquals(apiWhenExist.getZoneApi().list().concat().toString(), new ListHostedZonesResponseTest().expected()
Route53Api success = requestsSendResponses(list, listResponse, listWithOptions, noMore);
assertEquals(success.getZoneApi().list().concat().toString(), new ListHostedZonesResponseTest().expected()
.toString());
}
HttpRequest delete = HttpRequest.builder().method("DELETE")
.endpoint("https://route53.amazonaws.com/2012-02-29/hostedzone/Z1XTHCPEFRWV1X")
.addHeader("Host", "route53.amazonaws.com")
.addHeader("Date", "Mon, 21 Jan 02013 19:29:03 -0800")
.addHeader("X-Amzn-Authorization",
"AWS3-HTTPS AWSAccessKeyId=identity,Algorithm=HmacSHA256,Signature=pylxNiLcrsjNRZOsxyT161JCwytVPHyc2rFfmNCuZKI=")
.build();
HttpResponse deleteResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/change.xml", "text/xml")).build();
public void testDeleteWhenResponseIs2xx() {
Route53Api success = requestSendsResponse(delete, deleteResponse);
assertEquals(success.getZoneApi().delete("Z1XTHCPEFRWV1X").toString(), new GetChangeResponseTest().expected().toString());
}
public void testDeleteWhenResponseIs404() {
Route53Api fail = requestSendsResponse(delete, notFound);
assertNull(fail.getZoneApi().delete("Z1XTHCPEFRWV1X"));
}
}

View File

@ -19,14 +19,28 @@
package org.jclouds.route53.features;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.jclouds.route53.domain.Change.Status.INSYNC;
import static org.jclouds.route53.domain.Change.Status.PENDING;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.util.Date;
import java.util.logging.Logger;
import org.jclouds.JcloudsVersion;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.route53.domain.Change;
import org.jclouds.route53.domain.NewZone;
import org.jclouds.route53.domain.Zone;
import org.jclouds.route53.internal.BaseRoute53ApiLiveTest;
import org.jclouds.route53.options.ListZonesOptions;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
@ -34,12 +48,24 @@ import com.google.common.collect.Iterables;
*/
@Test(groups = "live", testName = "ZoneApiLiveTest")
public class ZoneApiLiveTest extends BaseRoute53ApiLiveTest {
private Predicate<Change> inSync;
@BeforeClass(groups = "live")
@Override
public void setupContext() {
super.setupContext();
inSync = new RetryablePredicate<Change>(new Predicate<Change>() {
public boolean apply(Change input) {
return context.getApi().getChange(input.getId()).getStatus() == INSYNC;
}
}, 600, 1, 5, SECONDS);
}
private void checkZone(Zone zone) {
checkNotNull(zone.getId(), "Id cannot be null for a Zone.");
checkNotNull(zone.getName(), "Id cannot be null for a Zone.");
checkNotNull(zone.getCallerReference(), "CallerReference cannot be null for a Zone.");
checkNotNull(zone.getComment(), "While Comment can be null for a Zone, its Optional wrapper cannot.");
checkNotNull(zone.getId(), "Id cannot be null for a Zone %s", zone);
checkNotNull(zone.getName(), "Id cannot be null for a Zone %s", zone);
checkNotNull(zone.getCallerReference(), "CallerReference cannot be null for a Zone %s", zone);
checkNotNull(zone.getComment(), "While Comment can be null for a Zone, its Optional wrapper cannot %s", zone);
}
@Test
@ -52,7 +78,7 @@ public class ZoneApiLiveTest extends BaseRoute53ApiLiveTest {
if (Iterables.size(response) > 0) {
Zone zone = response.iterator().next();
Assert.assertEquals(api().get(zone.getId()).getZone(), zone);
assertEquals(api().get(zone.getId()).getZone(), zone);
}
// Test with a Marker, even if it's null
@ -62,6 +88,38 @@ public class ZoneApiLiveTest extends BaseRoute53ApiLiveTest {
}
}
@Test
public void testGetZoneWhenNotFound() {
assertNull(api().get("AAAAAAAAAAAAAAAA"));
}
@Test
public void testDeleteZoneWhenNotFound() {
assertNull(api().delete("AAAAAAAAAAAAAAAA"));
}
@Test
public void testCreateAndDeleteZone() {
String name = System.getProperty("user.name").replace('.', '-') + ".zone.route53test.jclouds.org.";
String nonce = name + " @ " + new Date();
String comment = name + " for " + JcloudsVersion.get();
NewZone newZone = api().createWithReferenceAndComment(name, nonce, comment);
Logger.getAnonymousLogger().info("created zone: " + newZone);
try {
checkZone(newZone.getZone());
assertEquals(newZone.getChange().getStatus(), PENDING, "invalid status on zone " + newZone);
assertTrue(newZone.getNameServers().size() > 0, "no name servers for zone " + newZone);
assertEquals(newZone.getZone().getName(), name);
assertEquals(newZone.getZone().getCallerReference(), nonce);
assertEquals(newZone.getZone().getComment().get(), comment);
assertTrue(inSync.apply(newZone.getChange()), "zone didn't sync " + newZone);
} finally {
Change delete = api().delete(newZone.getZone().getId());
assertTrue(inSync.apply(delete), "delete didn't sync " + delete);
}
}
protected ZoneApi api() {
return context.getApi().getZoneApi();
}

View File

@ -1,38 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.route53.internal;
import java.util.Properties;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.route53.Route53AsyncApi;
import com.google.common.base.Function;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
public class BaseRoute53AsyncApiExpectTest extends BaseRoute53ExpectTest<Route53AsyncApi> {
public Route53AsyncApi createApi(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
return createInjector(fn, module, props).getInstance(Route53AsyncApi.class);
}
}

View File

@ -0,0 +1,51 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.route53.parse;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.route53.domain.NewZone;
import org.jclouds.route53.xml.CreateHostedZoneResponseHandler;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "CreateHostedZoneResponseTest")
public class CreateHostedZoneResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/new_zone.xml");
NewZone expected = expected();
CreateHostedZoneResponseHandler handler = injector.getInstance(CreateHostedZoneResponseHandler.class);
NewZone result = factory.create(handler).parse(is);
assertEquals(result, expected);
}
public NewZone expected() {
return NewZone.create(new GetHostedZoneResponseTest().expected(), new GetChangeResponseTest().expected());
}
}

View File

@ -21,6 +21,7 @@ package org.jclouds.route53.parse;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.Date;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.functions.BaseHandlerTest;
@ -50,11 +51,8 @@ public class GetChangeResponseTest extends BaseHandlerTest {
}
public Change expected() {
return Change.builder()
.id("C2682N5HXP0BZ4")
.status(Status.INSYNC)
.submittedAt(new SimpleDateFormatDateService().iso8601DateParse("2011-09-10T01:36:41.958Z"))
.build();
Date submittedAt = new SimpleDateFormatDateService().iso8601DateParse("2011-09-10T01:36:41.958Z");
return Change.create("C2682N5HXP0BZ4", Status.INSYNC, submittedAt);
}
}

View File

@ -28,6 +28,8 @@ import org.jclouds.route53.domain.ZoneAndNameServers;
import org.jclouds.route53.xml.GetHostedZoneResponseHandler;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* @author Adrian Cole
*/
@ -47,15 +49,15 @@ public class GetHostedZoneResponseTest extends BaseHandlerTest {
}
public ZoneAndNameServers expected() {
return ZoneAndNameServers.builder()
.addNameServer("ns-1638.awsdns-12.co.uk")
.addNameServer("ns-144.awsdns-18.com")
.addNameServer("ns-781.awsdns-33.net")
.addNameServer("ns-1478.awsdns-56.org")
.zone(Zone.builder()
.id("/hostedzone/Z21DW1QVGID6NG")
.name("example.com.")
.callerReference("a_unique_reference")
.comment("Migrate an existing domain to Route 53").build()).build();
return ZoneAndNameServers.create(Zone.builder()
.id("Z21DW1QVGID6NG")
.name("example.com.")
.callerReference("a_unique_reference")
.comment("Migrate an existing domain to Route 53").build(),
ImmutableList.<String> builder()
.add("ns-1638.awsdns-12.co.uk")
.add("ns-144.awsdns-18.com")
.add("ns-781.awsdns-33.net")
.add("ns-1478.awsdns-56.org").build());
}
}

View File

@ -54,13 +54,13 @@ public class ListHostedZonesResponseTest extends BaseHandlerTest {
return IterableWithMarkers.from(
ImmutableSet.of(
Zone.builder()
.id("/hostedzone/Z21DW1QVGID6NG")
.id("Z21DW1QVGID6NG")
.name("example.com.")
.callerReference("a_unique_reference")
.resourceRecordSetCount(17)
.comment("Migrate an existing domain to Route 53").build(),
Zone.builder()
.id("/hostedzone/Z2682N5HXP0BZ4")
.id("Z2682N5HXP0BZ4")
.name("example2.com.")
.callerReference("a_unique_reference2")
.resourceRecordSetCount(117)

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<GetChangeResponse xmlns="https://route53.amazonaws.com/doc/2012-02-29/">
<ChangeInfo>
<Id>C2682N5HXP0BZ4</Id>
<Id>/change/C2682N5HXP0BZ4</Id>
<Status>INSYNC</Status>
<SubmittedAt>2011-09-10T01:36:41.958Z</SubmittedAt>
</ChangeInfo>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<CreateHostedZoneResponse
xmlns="https://route53.amazonaws.com/doc/2012-02-29/">
<HostedZone>
<Id>/hostedzone/Z21DW1QVGID6NG</Id>
<Name>example.com.</Name>
<CallerReference>a_unique_reference</CallerReference>
<Config>
<Comment>Migrate an existing domain to Route 53</Comment>
</Config>
</HostedZone>
<ChangeInfo>
<Id>C2682N5HXP0BZ4</Id>
<Status>INSYNC</Status>
<SubmittedAt>2011-09-10T01:36:41.958Z</SubmittedAt>
</ChangeInfo>
<DelegationSet>
<NameServers>
<NameServer>ns-1638.awsdns-12.co.uk</NameServer>
<NameServer>ns-144.awsdns-18.com</NameServer>
<NameServer>ns-781.awsdns-33.net</NameServer>
<NameServer>ns-1478.awsdns-56.org</NameServer>
</NameServers>
</DelegationSet>
</CreateHostedZoneResponse>