diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/UltraDNSWSApi.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/UltraDNSWSApi.java
index 827038d621..c302348f49 100644
--- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/UltraDNSWSApi.java
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/UltraDNSWSApi.java
@@ -19,6 +19,7 @@
package org.jclouds.ultradns.ws;
import java.io.Closeable;
+import java.util.Map;
import javax.inject.Named;
import javax.ws.rs.POST;
@@ -30,6 +31,9 @@ import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.ultradns.ws.domain.Account;
+import org.jclouds.ultradns.ws.domain.Region;
+import org.jclouds.ultradns.ws.features.DirectionalGroupApi;
+import org.jclouds.ultradns.ws.features.DirectionalPoolApi;
import org.jclouds.ultradns.ws.features.ResourceRecordApi;
import org.jclouds.ultradns.ws.features.RoundRobinPoolApi;
import org.jclouds.ultradns.ws.features.TaskApi;
@@ -37,6 +41,7 @@ import org.jclouds.ultradns.ws.features.TrafficControllerPoolApi;
import org.jclouds.ultradns.ws.features.ZoneApi;
import org.jclouds.ultradns.ws.filters.SOAPWrapWithPasswordAuth;
import org.jclouds.ultradns.ws.xml.AccountHandler;
+import org.jclouds.ultradns.ws.xml.RegionListHandler;
/**
* Provides access to Neustar UltraDNS via the SOAP API
@@ -58,13 +63,22 @@ public interface UltraDNSWSApi extends Closeable {
Account getCurrentAccount();
/**
- * Provides synchronous access to Zone features.
+ * Lists the directional regions available in the account.
+ */
+ @Named("getAvailableRegions")
+ @POST
+ @XMLResponseParser(RegionListHandler.class)
+ @Payload("")
+ Map getRegionsById();
+
+ /**
+ * Provides access to Zone features.
*/
@Delegate
ZoneApi getZoneApi();
/**
- * Provides synchronous access to Resource Record features.
+ * Provides access to Resource Record features.
*
* @param zoneName
* zoneName including a trailing dot
@@ -73,7 +87,7 @@ public interface UltraDNSWSApi extends Closeable {
ResourceRecordApi getResourceRecordApiForZone(@PayloadParam("zoneName") String zoneName);
/**
- * Provides synchronous access to Round Robin Pool features.
+ * Provides access to Round Robin Pool features.
*
* @param zoneName
* zoneName including a trailing dot
@@ -82,7 +96,7 @@ public interface UltraDNSWSApi extends Closeable {
RoundRobinPoolApi getRoundRobinPoolApiForZone(@PayloadParam("zoneName") String zoneName);
/**
- * Provides synchronous access to Traffic Controller Pool features.
+ * Provides access to Traffic Controller Pool features.
*
* @param zoneName
* zoneName including a trailing dot
@@ -91,7 +105,25 @@ public interface UltraDNSWSApi extends Closeable {
TrafficControllerPoolApi getTrafficControllerPoolApiForZone(@PayloadParam("zoneName") String zoneName);
/**
- * Provides synchronous access to Task features.
+ * Provides access to Account-Level Directional Group features.
+ *
+ * @param accountId
+ * id of the account where the groups live.
+ */
+ @Delegate
+ DirectionalGroupApi getDirectionalGroupApiForAccount(@PayloadParam("accountId") String accountId);
+
+ /**
+ * Provides access to Directional Pool features.
+ *
+ * @param zoneName
+ * zoneName including a trailing dot
+ */
+ @Delegate
+ DirectionalPoolApi getDirectionalPoolApiForZone(@PayloadParam("zoneName") String zoneName);
+
+ /**
+ * Provides access to Task features.
*/
@Delegate
TaskApi getTaskApi();
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/binders/DirectionalGroupCoordinatesToXML.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/binders/DirectionalGroupCoordinatesToXML.java
new file mode 100644
index 0000000000..729fee5aa4
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/binders/DirectionalGroupCoordinatesToXML.java
@@ -0,0 +1,46 @@
+/**
+ * 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.ultradns.ws.binders;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.UriTemplates;
+import org.jclouds.rest.Binder;
+import org.jclouds.ultradns.ws.domain.DirectionalGroupCoordinates;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class DirectionalGroupCoordinatesToXML implements Binder {
+ private static final String TEMPLATE = "{groupName}{recordName}{zoneName}{recordType}";
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public R bindToRequest(R request, Object in) {
+ DirectionalGroupCoordinates group = DirectionalGroupCoordinates.class.cast(in);
+ ImmutableMap variables = ImmutableMap. builder()
+ .put("zoneName", group.getZoneName())
+ .put("recordName", group.getRecordName())
+ .put("recordType", group.getRecordType())
+ .put("groupName", group.getGroupName()).build();
+ return (R) request.toBuilder().payload(UriTemplates.expand(TEMPLATE, variables)).build();
+ }
+}
\ No newline at end of file
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/config/UltraDNSWSHttpApiModule.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/config/UltraDNSWSHttpApiModule.java
index 9c23387cd1..1a4d83e730 100644
--- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/config/UltraDNSWSHttpApiModule.java
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/config/UltraDNSWSHttpApiModule.java
@@ -28,6 +28,7 @@ import org.jclouds.rest.config.HttpApiModule;
import org.jclouds.ultradns.ws.UltraDNSWSApi;
import org.jclouds.ultradns.ws.handlers.UltraDNSWSErrorHandler;
+
/**
* Configures the UltraDNSWS connection.
*
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/AccountLevelGroup.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/AccountLevelGroup.java
new file mode 100644
index 0000000000..8776c6d2bf
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/AccountLevelGroup.java
@@ -0,0 +1,141 @@
+/**
+ * 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.ultradns.ws.domain;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.ultradns.ws.domain.DirectionalPool.Type;
+
+import com.google.common.base.Objects;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public final class AccountLevelGroup {
+
+ private final String id;
+ private final String name;
+ private final Type type;
+ private final int recordCount;
+
+ private AccountLevelGroup(String id, String name, Type type, int recordCount) {
+ this.id = checkNotNull(id, "id");
+ this.name = checkNotNull(name, "name of %s", id);
+ this.type = checkNotNull(type, "type of %s", id);
+ this.recordCount = recordCount;
+ checkArgument(recordCount >= 0, "recordCount of %s must be >= 0", id);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public int getRecordCount() {
+ return recordCount;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(id, name, type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AccountLevelGroup that = AccountLevelGroup.class.cast(obj);
+ return Objects.equal(this.id, that.id) && Objects.equal(this.name, that.name)
+ && Objects.equal(this.type, that.type);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).omitNullValues().add("id", id).add("name", name).add("type", type)
+ .add("recordCount", recordCount).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String id;
+ private String name;
+ private Type type;
+ private int recordCount = -1;
+
+ /**
+ * @see AccountLevelGroup#getId()
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * @see AccountLevelGroup#getName()
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * @see AccountLevelGroup#getType()
+ */
+ public Builder type(Type type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * @see AccountLevelGroup#getRecordCount()
+ */
+ public Builder recordCount(int recordCount) {
+ this.recordCount = recordCount;
+ return this;
+ }
+
+ public AccountLevelGroup build() {
+ return new AccountLevelGroup(id, name, type, recordCount);
+ }
+
+ public Builder from(AccountLevelGroup in) {
+ return this.id(in.id).name(in.name).type(in.type).recordCount(in.recordCount);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroup.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroup.java
new file mode 100644
index 0000000000..7caaf52d0c
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroup.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * 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.ultradns.ws.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;
+
+/**
+ * @author Adrian Cole
+ */
+public class DirectionalGroup {
+ private final String id;
+ private final String name;
+
+ private DirectionalGroup(String id, String name) {
+ this.id = checkNotNull(id, "id");
+ this.name = checkNotNull(name, "name");
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(id, name);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ DirectionalGroup that = DirectionalGroup.class.cast(obj);
+ return equal(this.id, that.id) && equal(this.name, that.name);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).omitNullValues().add("id", id).add("name", name).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String id;
+ private String name;
+
+ /**
+ * @see DirectionalGroup#getId()
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * @see DirectionalGroup#getName()
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public DirectionalGroup build() {
+ return new DirectionalGroup(id, name);
+ }
+
+ public Builder from(DirectionalGroup in) {
+ return id(in.id).name(in.name);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroupCoordinates.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroupCoordinates.java
new file mode 100644
index 0000000000..ecd607584f
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroupCoordinates.java
@@ -0,0 +1,156 @@
+/**
+ * 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.ultradns.ws.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+
+/**
+ * @author Adrian Cole
+ */
+public class DirectionalGroupCoordinates {
+
+ private final String zoneName;
+ private final String recordName;
+ private final int recordType;
+ private final String groupName;
+
+ private DirectionalGroupCoordinates(String zoneName, String recordName, int recordType, String groupName) {
+ this.zoneName = checkNotNull(zoneName, "zoneName");
+ this.recordName = checkNotNull(recordName, "recordName");
+ checkArgument(recordType >= 0, "recordType of %s must be >= 0", recordName);
+ this.recordType = recordType;
+ this.groupName = checkNotNull(groupName, "groupName");
+ }
+
+ /**
+ * the {@link DirectionalRecordDetail#getZoneName() name} of the zone.
+ */
+ public String getZoneName() {
+ return zoneName;
+ }
+
+ /**
+ * the {@link DirectionalRecordDetail#getName() dname} of the record.
+ */
+ public String getRecordName() {
+ return recordName;
+ }
+
+ /**
+ * the {@link DirectionalRecord#getType() recordType} of the record.
+ *
+ * @see DirectionalRecordDetail#getRecord()
+ */
+ public int getRecordType() {
+ return recordType;
+ }
+
+ /**
+ * the {@link DirectionalGroup#getName() name} of the directional group.
+ *
+ * @see DirectionalRecordDetail#getGroup()
+ * @see DirectionalRecordDetail#getGeolocationGroup()
+ * @see DirectionalRecordDetail#getSourceIpGroup()
+ */
+ public String getGroupName() {
+ return groupName;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(zoneName, recordName, recordType, groupName);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ DirectionalGroupCoordinates that = DirectionalGroupCoordinates.class.cast(obj);
+ return equal(this.zoneName, that.zoneName) && equal(this.recordName, that.recordName)
+ && equal(this.recordType, that.recordType) && equal(this.groupName, that.groupName);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("zoneName", zoneName).add("recordName", recordName).add("recordType", recordType)
+ .add("groupName", groupName).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String zoneName;
+ private String recordName;
+ private int recordType = -1;
+ private String groupName;
+
+ /**
+ * @see DirectionalGroupCoordinates#getZoneName()
+ */
+ public Builder zoneName(String zoneName) {
+ this.zoneName = zoneName;
+ return this;
+ }
+
+ /**
+ * @see DirectionalGroupCoordinates#getRecordName()
+ */
+ public Builder recordName(String recordName) {
+ this.recordName = recordName;
+ return this;
+ }
+
+ /**
+ * @see DirectionalGroupCoordinates#getRecordType()
+ */
+ public Builder recordType(int recordType) {
+ this.recordType = recordType;
+ return this;
+ }
+
+ /**
+ * @see DirectionalGroupCoordinates#getGroupName()
+ */
+ public Builder groupName(String groupName) {
+ this.groupName = groupName;
+ return this;
+ }
+
+ public DirectionalGroupCoordinates build() {
+ return new DirectionalGroupCoordinates(zoneName, recordName, recordType, groupName);
+ }
+
+ public Builder from(DirectionalGroupCoordinates in) {
+ return zoneName(in.zoneName).recordName(in.zoneName).recordType(in.recordType).groupName(in.groupName);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroupNameAndRegions.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroupNameAndRegions.java
new file mode 100644
index 0000000000..9c7b55f8bb
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalGroupNameAndRegions.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * 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.ultradns.ws.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.ForwardingSet;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A region is a set of territory names.
+ *
+ * @author Adrian Cole
+ */
+public class DirectionalGroupNameAndRegions extends ForwardingSet {
+
+ private final String name;
+ private final Set regions;
+
+ private DirectionalGroupNameAndRegions(String name, Set regions) {
+ this.name = checkNotNull(name, "name");
+ this.regions = checkNotNull(regions, "regions of %s", name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set getRegions() {
+ return regions;
+ }
+
+ @Override
+ protected Set delegate() {
+ return regions;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, regions);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ DirectionalGroupNameAndRegions that = DirectionalGroupNameAndRegions.class.cast(obj);
+ return equal(this.name, that.name) && equal(this.regions, that.regions);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("name", name).add("regions", regions).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String name;
+ private ImmutableSet.Builder regions = ImmutableSet. builder();
+
+ /**
+ * @see DirectionalGroupNameAndRegions#getName()
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * adds to current regions
+ *
+ * @see DirectionalGroupNameAndRegions#getRegions()
+ */
+ public Builder addRegion(Region region) {
+ this.regions.add(region);
+ return this;
+ }
+
+ /**
+ * replaces current regions
+ *
+ * @see DirectionalGroupNameAndRegions#getRegions()
+ */
+ public Builder regions(Iterable regions) {
+ this.regions = ImmutableSet. builder().addAll(regions);
+ return this;
+ }
+
+ public DirectionalGroupNameAndRegions build() {
+ return new DirectionalGroupNameAndRegions(name, regions.build());
+ }
+
+ public Builder from(DirectionalGroupNameAndRegions in) {
+ return name(in.getName()).regions(in.getRegions());
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalPool.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalPool.java
new file mode 100644
index 0000000000..7941e143ca
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalPool.java
@@ -0,0 +1,190 @@
+/**
+ * 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.ultradns.ws.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+
+/**
+ * Records are resolved in consideration of the location of the requestor.
+ *
+ * @author Adrian Cole
+ */
+public final class DirectionalPool {
+
+ private final String zoneId;
+ private final String id;
+ private final Optional description;
+ private final String dname;
+ private final Type type;
+ private final TieBreak tieBreak;
+
+ private DirectionalPool(String zoneId, String id, Optional description, String dname, Type type,
+ TieBreak tieBreak) {
+ this.zoneId = checkNotNull(zoneId, "zoneId");
+ this.id = checkNotNull(id, "id");
+ this.description = checkNotNull(description, "description for %s", id);
+ this.dname = checkNotNull(dname, "dname for %s", id);
+ this.type = type;
+ this.tieBreak = tieBreak;
+ }
+
+ public String getZoneId() {
+ return zoneId;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * The dname of the pool. ex. {@code jclouds.org.}
+ */
+ public String getName() {
+ return dname;
+ }
+
+ /**
+ * The description of the pool. ex. {@code My Pool}
+ */
+ public Optional getDescription() {
+ return description;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * if {@link #getType} is {@link Type#MIXED}, this can be
+ * {@link TieBreak#SOURCEIP} or {@link TieBreak#GEOLOCATION}, otherwise
+ * {@link TieBreak#GEOLOCATION}
+ */
+ public TieBreak getTieBreak() {
+ return tieBreak;
+ }
+
+ public static enum Type {
+ GEOLOCATION, SOURCEIP, MIXED;
+ }
+
+ public static enum TieBreak {
+ GEOLOCATION, SOURCEIP;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(zoneId, id, description, dname);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DirectionalPool that = DirectionalPool.class.cast(obj);
+ return Objects.equal(this.zoneId, that.zoneId) && Objects.equal(this.id, that.id)
+ && Objects.equal(this.description, that.description) && Objects.equal(this.dname, that.dname);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).omitNullValues().add("zoneId", zoneId).add("id", id).add("name", dname)
+ .add("description", description.orNull()).add("type", type).add("tieBreak", tieBreak).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String zoneId;
+ private String id;
+ private Optional description = Optional.absent();
+ private String dname;
+ private Type type = Type.GEOLOCATION;
+ private TieBreak tieBreak = TieBreak.GEOLOCATION;
+
+ /**
+ * @see DirectionalPool#getZoneId()
+ */
+ public Builder zoneId(String zoneId) {
+ this.zoneId = zoneId;
+ return this;
+ }
+
+ /**
+ * @see DirectionalPool#getId()
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * @see DirectionalPool#getName()
+ */
+ public Builder name(String dname) {
+ this.dname = dname;
+ return this;
+ }
+
+ /**
+ * @see DirectionalPool#getDescription()
+ */
+ public Builder description(String description) {
+ this.description = Optional.fromNullable(description);
+ return this;
+ }
+
+ /**
+ * @see DirectionalPool#getType()
+ */
+ public Builder type(Type type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * @see DirectionalPool#getTieBreak()
+ */
+ public Builder tieBreak(TieBreak tieBreak) {
+ this.tieBreak = tieBreak;
+ return this;
+ }
+
+ public DirectionalPool build() {
+ return new DirectionalPool(zoneId, id, description, dname, type, tieBreak);
+ }
+
+ public Builder from(DirectionalPool in) {
+ return this.zoneId(in.zoneId).id(in.id).description(in.description.orNull()).name(in.dname).type(in.type)
+ .tieBreak(in.tieBreak);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecord.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecord.java
new file mode 100644
index 0000000000..2dcdbbac66
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecord.java
@@ -0,0 +1,174 @@
+/**
+ * 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.ultradns.ws.domain;
+
+import static com.google.common.base.Functions.toStringFunction;
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+
+import java.util.List;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * @author Adrian Cole
+ */
+public class DirectionalRecord {
+ private final String type;
+ private final int ttl;
+ private final boolean noResponseRecord;
+ private final List infoValues;
+
+ private DirectionalRecord(String type, int ttl, boolean noResponseRecord, List infoValues) {
+ this.type = checkNotNull(type, "type");
+ checkArgument(ttl >= 0, "ttl must be >= 0");
+ this.ttl = ttl;
+ this.noResponseRecord = noResponseRecord;
+ this.infoValues = checkNotNull(infoValues, "infoValues");
+ }
+
+ /**
+ * the type. ex. {@code A}
+ */
+ public String getType() {
+ return type;
+ }
+
+ public int getTTL() {
+ return ttl;
+ }
+
+ /**
+ * true if blocks traffic from specified regions by returning No Error, No
+ * Response.
+ */
+ public boolean isNoResponseRecord() {
+ return noResponseRecord;
+ }
+
+ /**
+ * {@link #getType() type}-specific binary values.
+ */
+ public List getRData() {
+ return infoValues;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(noResponseRecord, type, ttl, infoValues);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ DirectionalRecord that = DirectionalRecord.class.cast(obj);
+ return equal(this.type, that.type) && equal(this.ttl, that.ttl)
+ && equal(this.noResponseRecord, that.noResponseRecord) && equal(this.infoValues, that.infoValues);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("type", type).add("ttl", ttl).add("noResponseRecord", noResponseRecord)
+ .add("infoValues", infoValues).toString();
+ }
+
+ public static Builder drBuilder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return drBuilder().from(this);
+ }
+
+ public final static class Builder {
+ private String type;
+ private int ttl = -1;
+ private boolean noResponseRecord;
+ private ImmutableList.Builder infoValues = ImmutableList. builder();
+
+ /**
+ * @see DirectionalRecord#getType()
+ */
+ public Builder type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecord#getTTL()
+ */
+ public Builder ttl(int ttl) {
+ this.ttl = ttl;
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecord#isNoResponseRecord()
+ */
+ public Builder noResponseRecord(boolean noResponseRecord) {
+ this.noResponseRecord = noResponseRecord;
+ return this;
+ }
+
+ /**
+ * adds to current values
+ *
+ * @see DirectionalRecord#getRData()
+ */
+ public Builder infoValue(Object infoValue) {
+ this.infoValues.add(infoValue.toString());
+ return this;
+ }
+
+ /**
+ * replaces current values
+ *
+ * @see DirectionalRecord#getRData()
+ */
+ public Builder rdata(Object infoValue) {
+ this.infoValues = ImmutableList. builder().add(infoValue.toString());
+ return this;
+ }
+
+ /**
+ * replaces current values
+ *
+ * @see DirectionalRecord#getRData()
+ */
+ public Builder rdata(Iterable> infoValues) {
+ this.infoValues = ImmutableList. builder().addAll(transform(infoValues, toStringFunction()));
+ return this;
+ }
+
+ public DirectionalRecord build() {
+ return new DirectionalRecord(type, ttl, noResponseRecord, infoValues.build());
+ }
+
+ public Builder from(DirectionalRecord in) {
+ return type(in.type).ttl(in.ttl).noResponseRecord(in.noResponseRecord).rdata(in.infoValues);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecordDetail.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecordDetail.java
new file mode 100644
index 0000000000..ecd9456843
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecordDetail.java
@@ -0,0 +1,203 @@
+/**
+ * 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.ultradns.ws.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.base.Optional;
+
+/**
+ * @author Adrian Cole
+ */
+public class DirectionalRecordDetail {
+
+ private final String zoneName;
+ private final String name;
+ private final String id;
+ private final Optional group;
+ private final Optional geolocationGroup;
+ private final Optional sourceIpGroup;
+ private final DirectionalRecord record;
+
+ private DirectionalRecordDetail(String zoneName, String name, String id,
+ Optional geolocationGroup, Optional group,
+ Optional sourceIpGroup, DirectionalRecord record) {
+ this.zoneName = checkNotNull(zoneName, "zoneName");
+ this.name = checkNotNull(name, "name");
+ this.id = checkNotNull(id, "id");
+ this.group = checkNotNull(group, "group of %s/%s/%s", zoneName, name, id);
+ this.geolocationGroup = checkNotNull(geolocationGroup, "geolocationGroup of %s/%s/%s", zoneName, name, id);
+ this.sourceIpGroup = checkNotNull(sourceIpGroup, "sourceIpGroup of %s/%s/%s", zoneName, name, id);
+ this.record = checkNotNull(record, "record of %s/%s/%s", zoneName, name, id);
+ }
+
+ public String getZoneName() {
+ return zoneName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * group containing all regions that you have not specifically configured in {@link #getGeolocationGroup()}
+ */
+ public Optional getGroup() {
+ return group;
+ }
+
+ /**
+ * group containing territories.
+ */
+ public Optional getGeolocationGroup() {
+ return geolocationGroup;
+ }
+
+ /**
+ * group containing IPV4 or IPV6 ranges.
+ */
+ public Optional getSourceIpGroup() {
+ return sourceIpGroup;
+ }
+
+ public DirectionalRecord getRecord() {
+ return record;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(zoneName, name, id);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ DirectionalRecordDetail that = DirectionalRecordDetail.class.cast(obj);
+ return equal(this.zoneName, that.zoneName) && equal(this.name, that.name) && equal(this.id, that.id);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).omitNullValues().add("zoneName", zoneName).add("name", name).add("id", id)
+ .add("group", group.orNull()).add("geolocationGroup", geolocationGroup.orNull())
+ .add("sourceIpGroup", sourceIpGroup.orNull()).add("record", record).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String zoneName;
+ private String name;
+ private String id;
+ private Optional group = Optional.absent();
+ private Optional geolocationGroup = Optional.absent();
+ private Optional sourceIpGroup = Optional.absent();
+ private DirectionalRecord record;
+
+ /**
+ * @see DirectionalRecordDetail#getZoneName()
+ */
+ public Builder zoneName(String zoneName) {
+ this.zoneName = zoneName;
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getName()
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getId()
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getGroup()
+ */
+ public Builder group(DirectionalGroup group) {
+ this.group = Optional.fromNullable(group);
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getGeolocationGroup()
+ */
+ public Builder geolocationGroup(DirectionalGroup geolocationGroup) {
+ this.geolocationGroup = Optional.fromNullable(geolocationGroup);
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getSourceIpGroup()
+ */
+ public Builder sourceIpGroup(DirectionalGroup sourceIpGroup) {
+ this.sourceIpGroup = Optional.fromNullable(sourceIpGroup);
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getRecord()
+ */
+ public Builder record(DirectionalRecord record) {
+ this.record = record;
+ return this;
+ }
+
+ /**
+ * @see DirectionalRecordDetail#getRecord()
+ */
+ public Builder record(DirectionalRecord.Builder record) {
+ this.record = record.build();
+ return this;
+ }
+
+ public DirectionalRecordDetail build() {
+ return new DirectionalRecordDetail(zoneName, name, id, group, geolocationGroup, sourceIpGroup, record);
+ }
+
+ public Builder from(DirectionalRecordDetail in) {
+ return this.zoneName(in.zoneName).name(in.name).id(in.id).group(in.group.orNull())
+ .geolocationGroup(in.geolocationGroup.orNull()).sourceIpGroup(in.sourceIpGroup.orNull())
+ .record(in.record);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecordType.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecordType.java
new file mode 100644
index 0000000000..97b4b6bfcd
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/DirectionalRecordType.java
@@ -0,0 +1,62 @@
+/**
+ * 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.ultradns.ws.domain;
+
+/**
+ * currently supported {@link ResourceRecord#getType() types} for directional
+ * groups.
+ *
+ * @author Adrian Cole
+ */
+public enum DirectionalRecordType {
+ // A/CNAME
+ IPV4(1),
+
+ // AAAA/CNAME
+ IPV6(28),
+
+ TXT(16),
+
+ SRV(33),
+
+ PTR(12),
+
+ RP(17),
+
+ HINFO(13),
+
+ NAPTR(35),
+
+ MX(15);
+
+ private final int code;
+
+ private DirectionalRecordType(int code) {
+ this.code = code;
+ }
+
+ /**
+ * The {@link ResourceRecord#getType() type} that can be used in directional
+ * groups.
+ */
+ public int getCode() {
+ return code;
+ }
+
+}
\ No newline at end of file
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/Region.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/Region.java
new file mode 100644
index 0000000000..23ea0fd7cf
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/Region.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * 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.ultradns.ws.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.ForwardingSet;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A region is a set of territory names.
+ *
+ * @author Adrian Cole
+ */
+public class Region extends ForwardingSet {
+
+ private final String name;
+ private final Set territoryNames;
+
+ private Region(String name, Set territoryNames) {
+ this.name = checkNotNull(name, "name");
+ this.territoryNames = checkNotNull(territoryNames, "territoryNames of %s", name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set getTerritoryNames() {
+ return territoryNames;
+ }
+
+ @Override
+ protected Set delegate() {
+ return territoryNames;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, territoryNames);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ Region that = Region.class.cast(obj);
+ return equal(this.name, that.name) && equal(this.territoryNames, that.territoryNames);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("name", name).add("territoryNames", territoryNames).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private String name;
+ private ImmutableSet.Builder territoryNames = ImmutableSet. builder();
+
+ /**
+ * @see Region#getName()
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * adds to current territoryNames
+ *
+ * @see Region#getTerritoryNames()
+ */
+ public Builder addTerritoryName(String territoryName) {
+ this.territoryNames.add(territoryName);
+ return this;
+ }
+
+ /**
+ * replaces current territoryNames
+ *
+ * @see Region#getTerritoryNames()
+ */
+ public Builder territoryNames(Iterable territoryNames) {
+ this.territoryNames = ImmutableSet. builder().addAll(territoryNames);
+ return this;
+ }
+
+ public Region build() {
+ return new Region(name, territoryNames.build());
+ }
+
+ public Builder from(Region in) {
+ return name(in.getName()).territoryNames(in.getTerritoryNames());
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecord.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecord.java
index 08dc6738c2..65850cc74e 100644
--- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecord.java
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecord.java
@@ -92,7 +92,7 @@ public class ResourceRecord {
@Override
public String toString() {
- return toStringHelper("").omitNullValues().add("dName", dName).add("type", type).add("ttl", ttl)
+ return toStringHelper(this).omitNullValues().add("dName", dName).add("type", type).add("ttl", ttl)
.add("infoValues", infoValues).toString();
}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecordMetadata.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecordMetadata.java
index af9bf39b6e..b98ac37e28 100644
--- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecordMetadata.java
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/ResourceRecordMetadata.java
@@ -93,7 +93,7 @@ public class ResourceRecordMetadata {
@Override
public String toString() {
- return toStringHelper("").omitNullValues().add("zoneId", zoneId).add("guid", guid).add("zoneName", zoneName)
+ return toStringHelper(this).omitNullValues().add("zoneId", zoneId).add("guid", guid).add("zoneName", zoneName)
.add("created", created).add("modified", modified).add("record", record).toString();
}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/DirectionalGroupApi.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/DirectionalGroupApi.java
new file mode 100644
index 0000000000..70e1436a94
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/DirectionalGroupApi.java
@@ -0,0 +1,135 @@
+/**
+ * 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.ultradns.ws.features;
+
+import javax.inject.Named;
+import javax.ws.rs.POST;
+
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.ultradns.ws.binders.DirectionalGroupCoordinatesToXML;
+import org.jclouds.ultradns.ws.domain.AccountLevelGroup;
+import org.jclouds.ultradns.ws.domain.DirectionalGroup;
+import org.jclouds.ultradns.ws.domain.DirectionalGroupCoordinates;
+import org.jclouds.ultradns.ws.domain.DirectionalGroupNameAndRegions;
+import org.jclouds.ultradns.ws.domain.DirectionalRecordDetail;
+import org.jclouds.ultradns.ws.filters.SOAPWrapWithPasswordAuth;
+import org.jclouds.ultradns.ws.xml.AccountLevelGroupsHandler;
+import org.jclouds.ultradns.ws.xml.DirectionalGroupNameAndRegionsHandler;
+import org.jclouds.ultradns.ws.xml.DirectionalRecordDetailListHandler;
+import org.jclouds.ultradns.ws.xml.ItemListHandler;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * @see
+ * @see
+ * @author Adrian Cole
+ */
+@RequestFilters(SOAPWrapWithPasswordAuth.class)
+@VirtualHost
+public interface DirectionalGroupApi {
+
+ /**
+ * returns the regions and name of the specified directional group or null,
+ * if not found.
+ *
+ * @param groupId
+ * the {@link DirectionalGroup#getId() id} of the group
+ */
+ @Named("getDirectionalDNSGroupDetails")
+ @POST
+ @XMLResponseParser(DirectionalGroupNameAndRegionsHandler.class)
+ @Fallback(NullOnNotFoundOr404.class)
+ @Payload("{GroupId}")
+ @Nullable
+ DirectionalGroupNameAndRegions get(@PayloadParam("GroupId") String groupId);
+
+ /**
+ * Returns all account-level groups.
+ *
+ */
+ @Named("getAccountLevelDirectionalGroupsOfZone")
+ @POST
+ @XMLResponseParser(AccountLevelGroupsHandler.class)
+ @Payload("{accountId}")
+ FluentIterable listAccountLevelGroups();
+
+ /**
+ * Returns all the directional pool records in the account-level group.
+ *
+ * @param groupId
+ * the id of the account-level group containing the records.
+ * @throws ResourceNotFoundException
+ * if the group doesn't exist
+ */
+ @Named("getDirectionalDNSRecordsForAcctLvlGroup")
+ @POST
+ @XMLResponseParser(DirectionalRecordDetailListHandler.class)
+ @Payload("{groupId}")
+ FluentIterable listRecordsByAccountLevelGroup(
+ @PayloadParam("groupId") String groupId) throws ResourceNotFoundException;
+
+ /**
+ * Returns directional group names visible to the account for the fully
+ * qualified {@link hostName} and {@link rrType}
+ *
+ * @param accountId
+ * the account where the groups exist
+ * @param hostName
+ * fully qualified hostname including the trailing dot.
+ * @param rrType
+ * type value, with special casing: for {@code A} or {@code CNAME}
+ * of ipv4 hosts, this is {@code 1}; for {@code AAAA} or
+ * {@code CNAME} of ipv4 hosts, this is {@code 28}
+ * @return empty if there are not groups for the specified host and type
+ */
+ @Named("getAvailableGroups")
+ @POST
+ @XMLResponseParser(ItemListHandler.class)
+ @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+ @Payload("{hostName}{rrType}{accountId}")
+ FluentIterable listGroupNamesByRecordNameAndType(
+ @PayloadParam("hostName") String hostName, @PayloadParam("rrType") int rrType);
+
+ /**
+ * Returns all the directional pool records in the pool-level group.
+ *
+ * @param group
+ * the zone, record name, record type, and group name
+ * @throws ResourceNotFoundException
+ * if the group doesn't exist
+ */
+ @Named("getDirectionalDNSRecordsForGroup")
+ @POST
+ @XMLResponseParser(DirectionalRecordDetailListHandler.class)
+ @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+ FluentIterable listRecordsByGroupCoordinates(
+ @BinderParam(DirectionalGroupCoordinatesToXML.class) DirectionalGroupCoordinates group)
+ throws ResourceNotFoundException;
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/DirectionalPoolApi.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/DirectionalPoolApi.java
new file mode 100644
index 0000000000..59ed329c8c
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/DirectionalPoolApi.java
@@ -0,0 +1,84 @@
+/**
+ * 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.ultradns.ws.features;
+
+import javax.inject.Named;
+import javax.ws.rs.POST;
+
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.ultradns.ws.domain.DirectionalPool;
+import org.jclouds.ultradns.ws.domain.DirectionalRecordDetail;
+import org.jclouds.ultradns.ws.filters.SOAPWrapWithPasswordAuth;
+import org.jclouds.ultradns.ws.xml.DirectionalPoolListHandler;
+import org.jclouds.ultradns.ws.xml.DirectionalRecordDetailListHandler;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * @see
+ * @see
+ * @author Adrian Cole
+ */
+@RequestFilters(SOAPWrapWithPasswordAuth.class)
+@VirtualHost
+public interface DirectionalPoolApi {
+
+ /**
+ * Returns all directional pools in the zone.
+ *
+ * @throws ResourceNotFoundException
+ * if the zone doesn't exist
+ */
+ @Named("getDirectionalPoolsOfZone")
+ @POST
+ @XMLResponseParser(DirectionalPoolListHandler.class)
+ @Payload("{zoneName}")
+ FluentIterable list() throws ResourceNotFoundException;
+
+ /**
+ * Returns all the directional pool records in the zone with the fully
+ * qualified {@link hostName} and {@link rrType}
+ *
+ * @param hostName
+ * fully qualified hostname including the trailing dot.
+ * @param rrType
+ * type value, with special casing: for {@code A} or {@code CNAME}
+ * of ipv4 hosts, this is {@code 1}; for {@code AAAA} or
+ * {@code CNAME} of ipv4 hosts, this is {@code 28}
+ * @return empty if there are not pools for the specified host or no records
+ * exist for the type.
+ * @throws ResourceNotFoundException
+ * if the zone doesn't exist
+ */
+ @Named("getDirectionalDNSRecordsForHost")
+ @POST
+ @XMLResponseParser(DirectionalRecordDetailListHandler.class)
+ @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+ @Payload("{zoneName}{hostName}{poolRecordType}")
+ FluentIterable listRecordsByNameAndType(
+ @PayloadParam("hostName") String dname, @PayloadParam("poolRecordType") int type)
+ throws ResourceNotFoundException;
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/handlers/UltraDNSWSErrorHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/handlers/UltraDNSWSErrorHandler.java
index 3a598084c8..e541901c2c 100644
--- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/handlers/UltraDNSWSErrorHandler.java
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/handlers/UltraDNSWSErrorHandler.java
@@ -95,6 +95,10 @@ public class UltraDNSWSErrorHandler implements HttpErrorHandler {
* Resource record exists with the same name and type.
*/
static final int RESOURCE_RECORD_ALREADY_EXISTS = 2111;
+ /**
+ * No Pool or Multiple pools of same type exists for the PoolName
+ */
+ static final int DIRECTIONAL_POOL_NOT_FOUND = 2142;
/**
* Account not found in the system.
*/
@@ -111,6 +115,10 @@ public class UltraDNSWSErrorHandler implements HttpErrorHandler {
* Pool Record does not exist.
*/
static final int POOL_RECORD_NOT_FOUND = 3101;
+ /**
+ * Group does not exist.
+ */
+ static final int GROUP_NOT_FOUND = 4003;
}
private Exception refineException(UltraDNSWSResponseException exception) {
@@ -125,7 +133,9 @@ public class UltraDNSWSErrorHandler implements HttpErrorHandler {
case RESOURCE_RECORD_NOT_FOUND:
case ACCOUNT_NOT_FOUND:
case POOL_NOT_FOUND:
+ case DIRECTIONAL_POOL_NOT_FOUND:
case POOL_RECORD_NOT_FOUND:
+ case GROUP_NOT_FOUND:
return new ResourceNotFoundException(message, exception);
case ZONE_ALREADY_EXISTS:
case RESOURCE_RECORD_ALREADY_EXISTS:
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/AccountLevelGroupsHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/AccountLevelGroupsHandler.java
new file mode 100644
index 0000000000..4a6985c90a
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/AccountLevelGroupsHandler.java
@@ -0,0 +1,61 @@
+/**
+ * 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.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.cleanseAttributes;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import java.util.Map;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.ultradns.ws.domain.AccountLevelGroup;
+import org.jclouds.ultradns.ws.domain.DirectionalPool.Type;
+import org.xml.sax.Attributes;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class AccountLevelGroupsHandler extends
+ ParseSax.HandlerForGeneratedRequestWithResult> {
+
+ private final Builder groups = ImmutableSet. builder();
+
+ @Override
+ public FluentIterable getResult() {
+ return FluentIterable.from(groups.build());
+ }
+
+ @Override
+ public void startElement(String url, String name, String qName, Attributes attrs) {
+ if (equalsOrSuffix(qName, "AccountLevelGroups")) {
+ Map attributes = cleanseAttributes(attrs);
+ groups.add(AccountLevelGroup.builder()
+ .id(attributes.get("GroupId"))
+ .name(attributes.get("GroupName"))
+ .type(Type.valueOf(attributes.get("GroupType")))
+ .recordCount(Integer.parseInt(attributes.get("RecordsCount")))
+ .build());
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalGroupNameAndRegionsHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalGroupNameAndRegionsHandler.java
new file mode 100644
index 0000000000..800a9bd16f
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalGroupNameAndRegionsHandler.java
@@ -0,0 +1,56 @@
+/**
+ * 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.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.ultradns.ws.domain.DirectionalGroupNameAndRegions;
+import org.jclouds.ultradns.ws.domain.DirectionalGroupNameAndRegions.Builder;
+import org.jclouds.ultradns.ws.domain.Region;
+import org.xml.sax.Attributes;
+
+import com.google.common.base.Splitter;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class DirectionalGroupNameAndRegionsHandler extends ParseSax.HandlerForGeneratedRequestWithResult {
+
+ private final Builder group = DirectionalGroupNameAndRegions.builder();
+
+ @Override
+ public DirectionalGroupNameAndRegions getResult() {
+ return group.build();
+ }
+
+ @Override
+ public void startElement(String url, String name, String qName, Attributes attrs) {
+ if (equalsOrSuffix(qName, "DirectionalDNSGroupDetail")) {
+ group.name(attrs.getValue("GroupName"));
+ } else if (equalsOrSuffix(qName, "RegionForNewGroups")) {
+ Iterable territories = Splitter.on(';').split(attrs.getValue("TerritoryName"));
+ Region region = Region.builder()
+ .name(attrs.getValue("RegionName"))
+ .territoryNames(territories).build();
+ group.addRegion(region);
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalPoolListHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalPoolListHandler.java
new file mode 100644
index 0000000000..70c271802d
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalPoolListHandler.java
@@ -0,0 +1,71 @@
+/**
+ * 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.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.cleanseAttributes;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import java.util.Map;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.ultradns.ws.domain.DirectionalPool;
+import org.jclouds.ultradns.ws.domain.DirectionalPool.TieBreak;
+import org.jclouds.ultradns.ws.domain.DirectionalPool.Type;
+import org.xml.sax.Attributes;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class DirectionalPoolListHandler extends ParseSax.HandlerForGeneratedRequestWithResult> {
+
+ private final Builder pools = ImmutableSet. builder();
+
+ @Override
+ public FluentIterable getResult() {
+ return FluentIterable.from(pools.build());
+ }
+
+ @Override
+ public void startElement(String url, String name, String qName, Attributes attrs) {
+ if (equalsOrSuffix(qName, "DirectionalPoolData")) {
+ Map attributes = cleanseAttributes(attrs);
+
+ DirectionalPool.Builder pool = DirectionalPool.builder()
+ .zoneId(attributes.get("Zoneid"))
+ .id(attributes.get("dirpoolid"))
+ .name(attributes.get("Pooldname"))
+ .description(attributes.get("Description"));
+
+ String type = attributes.get("DirPoolType");
+ if (type != null)
+ pool.type(Type.valueOf(type));
+
+ String tieBreak = attributes.get("TieBreak");
+ if (tieBreak != null)
+ pool.tieBreak(TieBreak.valueOf(tieBreak));
+
+ pools.add(pool.build());
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalRecordDetailHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalRecordDetailHandler.java
new file mode 100644
index 0000000000..7c967aaa2f
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalRecordDetailHandler.java
@@ -0,0 +1,90 @@
+/**
+ * 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.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.cleanseAttributes;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import java.util.Map;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.ultradns.ws.domain.DirectionalGroup;
+import org.jclouds.ultradns.ws.domain.DirectionalRecord;
+import org.jclouds.ultradns.ws.domain.DirectionalRecordDetail;
+import org.xml.sax.Attributes;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class DirectionalRecordDetailHandler extends
+ ParseSax.HandlerForGeneratedRequestWithResult {
+
+ private DirectionalRecordDetail.Builder drd = DirectionalRecordDetail.builder();
+ private DirectionalRecord.Builder dr = DirectionalRecord.drBuilder();
+
+ private String zoneName;
+ private String dname;
+
+ @Override
+ public DirectionalRecordDetail getResult() {
+ try {
+ return drd.record(dr.build()).build();
+ } finally {
+ drd = DirectionalRecordDetail.builder().zoneName(zoneName).name(dname);
+ dr = DirectionalRecord.drBuilder();
+ }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attrs) {
+ Map attributes = cleanseAttributes(attrs);
+ if (attributes.containsKey("ZoneName")) {
+ zoneName = attributes.get("ZoneName");
+ dname = attributes.get("DName");
+ drd.zoneName(zoneName).name(dname);
+ }
+ if (attributes.containsKey("DirPoolRecordId")) {
+ drd.id(attributes.get("DirPoolRecordId"));
+ }
+ if (attributes.containsKey("GroupId")) {
+ drd.group(DirectionalGroup.builder()
+ .id(attributes.get("GroupId"))
+ .name(attributes.get("GroupName")).build());
+ }
+ if (attributes.containsKey("GeolocationGroupId")) {
+ drd.geolocationGroup(DirectionalGroup.builder()
+ .id(attributes.get("GeolocationGroupId"))
+ .name(attributes.get("GeolocationGroupName")).build());
+ }
+ if (attributes.containsKey("SourceIPGroupId")) {
+ drd.sourceIpGroup(DirectionalGroup.builder()
+ .id(attributes.get("SourceIPGroupId"))
+ .name(attributes.get("SourceIPGroupName")).build());
+ }
+ if (attributes.containsKey("recordType")) {
+ dr.type(attributes.get("recordType"));
+ dr.ttl(Integer.parseInt(attributes.get("TTL")));
+ dr.noResponseRecord("true".equalsIgnoreCase(attributes.get("noResponseRecord")));
+ }
+ if (equalsOrSuffix(qName, "InfoValues")) {
+ dr.rdata(attributes.values());
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalRecordDetailListHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalRecordDetailListHandler.java
new file mode 100644
index 0000000000..76cc2e8d84
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/DirectionalRecordDetailListHandler.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.ultradns.ws.domain.DirectionalRecordDetail;
+import org.xml.sax.Attributes;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.inject.Inject;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class DirectionalRecordDetailListHandler extends
+ ParseSax.HandlerForGeneratedRequestWithResult> {
+
+ private final DirectionalRecordDetailHandler directionalRecordHandler;
+
+ private final Builder drs = ImmutableSet. builder();
+
+ @Inject
+ public DirectionalRecordDetailListHandler(DirectionalRecordDetailHandler directionalRecordHandler) {
+ this.directionalRecordHandler = directionalRecordHandler;
+ }
+
+ @Override
+ public FluentIterable getResult() {
+ return FluentIterable.from(drs.build());
+ }
+
+ @Override
+ public void startElement(String url, String name, String qName, Attributes attributes) {
+ directionalRecordHandler.startElement(url, name, qName, attributes);
+ }
+
+ @Override
+ public void endElement(String uri, String name, String qName) {
+ if (equalsOrSuffix(qName, "DirectionalDNSRecordDetail")) {
+ drs.add(directionalRecordHandler.getResult());
+ }
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/ItemListHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/ItemListHandler.java
new file mode 100644
index 0000000000..4b0b99d1fc
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/ItemListHandler.java
@@ -0,0 +1,57 @@
+/**
+ * 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.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import org.jclouds.http.functions.ParseSax;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class ItemListHandler extends ParseSax.HandlerForGeneratedRequestWithResult> {
+
+ private StringBuilder currentText = new StringBuilder();
+
+ private Builder items = ImmutableSet. builder();
+
+ @Override
+ public FluentIterable getResult() {
+ return FluentIterable.from(items.build());
+ }
+
+ @Override
+ public void endElement(String uri, String name, String qName) {
+ if (equalsOrSuffix(qName, "item")) {
+ items.add(currentOrNull(currentText));
+ }
+ currentText = new StringBuilder();
+ }
+
+ @Override
+ public void characters(char ch[], int start, int length) {
+ currentText.append(ch, start, length);
+ }
+}
diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/RegionListHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/RegionListHandler.java
new file mode 100644
index 0000000000..6c47f3bf3e
--- /dev/null
+++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/RegionListHandler.java
@@ -0,0 +1,59 @@
+/**
+ * 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.ultradns.ws.xml;
+
+import static org.jclouds.util.SaxUtils.cleanseAttributes;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import java.util.Map;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.ultradns.ws.domain.Region;
+import org.xml.sax.Attributes;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class RegionListHandler extends ParseSax.HandlerForGeneratedRequestWithResult