diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Address.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Address.java
new file mode 100644
index 000000000000..b30293fb6d48
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Address.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Objects;
+
+/**
+ * A Google Compute Engine address. With Compute Engine you can create static external IP addresses
+ * that are assigned to your project and persist until you explicitly release them. A region address
+ * can be assigned to a Compute Engine instance or to a regional forwarding rule. Compute Engine
+ * also allows you to create global addresses that are used for global forwarding rules. Both global
+ * addresses and global forwarding rules can only be used for HTTP load balancing. {@code Address}
+ * adds a layer of service-related functionality over {@link AddressInfo}. Objects of this class are
+ * immutable. To get an {@code Address} object with the most recent information use {@link #reload}.
+ *
+ * @see
+ * Static external IP addresses
+ * @see HTTP Load Balancing
+ */
+public class Address extends AddressInfo {
+
+ private static final long serialVersionUID = 3457542817554062712L;
+
+ private final ComputeOptions options;
+ private transient Compute compute;
+
+ /**
+ * A builder for {@code Address} objects.
+ */
+ public static class Builder extends AddressInfo.Builder {
+
+ private final Compute compute;
+ private final AddressInfo.BuilderImpl infoBuilder;
+
+ Builder(Compute compute, AddressId addressId) {
+ this.compute = compute;
+ this.infoBuilder = new AddressInfo.BuilderImpl();
+ this.infoBuilder.addressId(addressId);
+ }
+
+ Builder(Address address) {
+ this.compute = address.compute;
+ this.infoBuilder = new AddressInfo.BuilderImpl(address);
+ }
+
+ @Override
+ public Builder address(String address) {
+ infoBuilder.address(address);
+ return this;
+ }
+
+ @Override
+ Builder creationTimestamp(Long creationTimestamp) {
+ infoBuilder.creationTimestamp(creationTimestamp);
+ return this;
+ }
+
+ @Override
+ public Builder description(String description) {
+ infoBuilder.description(description);
+ return this;
+ }
+
+ @Override
+ Builder id(String id) {
+ infoBuilder.id(id);
+ return this;
+ }
+
+ @Override
+ public Builder addressId(AddressId addressId) {
+ infoBuilder.addressId(addressId);
+ return this;
+ }
+
+ @Override
+ Builder status(Status status) {
+ infoBuilder.status(status);
+ return this;
+ }
+
+ @Override
+ Builder usage(Usage usage) {
+ infoBuilder.usage(usage);
+ return this;
+ }
+
+ @Override
+ public Address build() {
+ return new Address(compute, infoBuilder);
+ }
+ }
+
+ Address(Compute compute, AddressInfo.BuilderImpl infoBuilder) {
+ super(infoBuilder);
+ this.compute = checkNotNull(compute);
+ this.options = compute.options();
+ }
+
+ /**
+ * Checks if this address exists.
+ *
+ * @return {@code true} if this address exists, {@code false} otherwise
+ * @throws ComputeException upon failure
+ */
+ public boolean exists() {
+ return reload(Compute.AddressOption.fields()) != null;
+ }
+
+ /**
+ * Fetches the current address' latest information. Returns {@code null} if the address does not
+ * exist.
+ *
+ * @param options address options
+ * @return an {@code Address} object with latest information or {@code null} if not found
+ * @throws ComputeException upon failure
+ */
+ public Address reload(Compute.AddressOption... options) {
+ return compute.get(addressId(), options);
+ }
+
+ /**
+ * Deletes this address.
+ *
+ * @return an {@code Operation} object if delete request was successfully sent, {@code null} if
+ * the address was not found
+ * @throws ComputeException upon failure
+ */
+ public Operation delete(Compute.OperationOption... options) {
+ return compute.delete(addressId(), options);
+ }
+
+ /**
+ * Returns the address's {@code Compute} object used to issue requests.
+ */
+ public Compute compute() {
+ return compute;
+ }
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ return obj instanceof Address
+ && Objects.equals(toPb(), ((Address) obj).toPb())
+ && Objects.equals(options, ((Address) obj).options);
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(super.hashCode(), options);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ this.compute = options.service();
+ }
+
+ static Address fromPb(Compute compute, com.google.api.services.compute.model.Address addressPb) {
+ return new Address(compute, new AddressInfo.BuilderImpl(addressPb));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressId.java
new file mode 100644
index 000000000000..c418ec2ae1ba
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressId.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+/**
+ * Base class for Google Compute Engine address identities.
+ */
+public abstract class AddressId extends ResourceId {
+
+ private static final long serialVersionUID = 147328216049936438L;
+
+ private final String address;
+
+ /**
+ * Possible types for a Google Compute Engine address identity.
+ */
+ enum Type {
+ /**
+ * Global static external IP addresses can be assigned to global forwarding rules.
+ */
+ GLOBAL,
+
+ /**
+ * Region static external IP addresses can be assigned to instances and region forwarding rules.
+ */
+ REGION
+ }
+
+ AddressId(String project, String address) {
+ super(project);
+ this.address = checkNotNull(address);
+ }
+
+ /**
+ * Returns the type of this address identity.
+ */
+ public abstract Type type();
+
+ /**
+ * Returns the name of the address resource. The name must be 1-63 characters long and comply with
+ * RFC1035. Specifically, the name must match the regular expression
+ * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter,
+ * and all following characters must be a dash, lowercase letter, or digit, except the last
+ * character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public String address() {
+ return address;
+ }
+
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return super.toStringHelper().add("address", address);
+ }
+
+ @Override
+ final int baseHashCode() {
+ return Objects.hash(super.baseHashCode(), address);
+ }
+
+ @Override
+ final boolean baseEquals(ResourceId resourceId) {
+ return resourceId instanceof AddressId
+ && super.baseEquals(resourceId)
+ && Objects.equals(address, ((AddressId) resourceId).address);
+ }
+
+ @Override
+ abstract AddressId setProjectId(String projectId);
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressInfo.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressInfo.java
new file mode 100644
index 000000000000..249f8462d401
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressInfo.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.services.compute.model.Address;
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A Google Compute Engine address. With Compute Engine you can create static external IP addresses
+ * that are assigned to your project and persist until you explicitly release them. A region address
+ * can be assigned to a Compute Engine instance or to a regional forwarding rule. To create a region
+ * address, use a {@link RegionAddressId} identity. Compute Engine also allows you to create global
+ * addresses that are used for global forwarding rules. Both global addresses and global forwarding
+ * rules can only be used for HTTP load balancing. To create a global address, use a
+ * {@link GlobalAddressId} identity.
+ *
+ * @see
+ * Static external IP addresses
+ * @see HTTP Load Balancing
+ */
+public class AddressInfo implements Serializable {
+
+ static final Function
FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public AddressInfo apply(Address pb) {
+ return AddressInfo.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public Address apply(AddressInfo addressInfo) {
+ return addressInfo.toPb();
+ }
+ };
+
+ private static final long serialVersionUID = 7678434703520207500L;
+ private static final DateTimeFormatter TIMESTAMP_FORMATTER = ISODateTimeFormat.dateTime();
+
+ private final String address;
+ private final Long creationTimestamp;
+ private final String description;
+ private final String id;
+ private final AddressId addressId;
+ private final Status status;
+ private final Usage usage;
+
+ /**
+ * The status of the address.
+ */
+ public enum Status {
+
+ /**
+ * The address is reserved for the project and is available for use.
+ */
+ RESERVED,
+
+ /**
+ * The address is currently being used and thus not available.
+ */
+ IN_USE
+ }
+
+ /**
+ * Base class for a Google Compute Engine address's usage information. Implementations of this
+ * class represent different possible usages of a Compute Engine address. {@link InstanceUsage}
+ * contains information for region addresses assigned to a Google Compute Engine instance.
+ * {@link RegionForwardingUsage} contains information for region addresses assigned to one or more
+ * region forwarding rules. {@link GlobalForwardingUsage} contains information for global
+ * addresses assigned to one or more global forwarding rules.
+ */
+ public abstract static class Usage implements Serializable {
+
+ private static final long serialVersionUID = -5028609518171408695L;
+
+ Usage() {}
+
+ /**
+ * Returns the identities of resources currently using this address.
+ */
+ public abstract List extends ResourceId> users();
+
+ final boolean baseEquals(Usage usage) {
+ return Objects.equals(toPb(), usage.toPb());
+ }
+
+ Address toPb() {
+ return new Address().setUsers(Lists.transform(users(), new Function() {
+ @Override
+ public String apply(ResourceId resourceId) {
+ return resourceId.selfLink();
+ }
+ }));
+ }
+
+ @SuppressWarnings("unchecked")
+ static T fromPb(Address addressPb) {
+ String url = addressPb.getUsers().get(0);
+ if (InstanceId.matchesUrl(url)) {
+ return (T) InstanceUsage.fromPb(addressPb);
+ } else if (RegionForwardingRuleId.matchesUrl(url)) {
+ return (T) RegionForwardingUsage.fromPb(addressPb);
+ } else if (GlobalForwardingRuleId.matchesUrl(url)) {
+ return (T) GlobalForwardingUsage.fromPb(addressPb);
+ } else {
+ throw new IllegalArgumentException("Unexpected resource URL for address user");
+ }
+ }
+ }
+
+ /**
+ * Usage information for a Google Compute Engine region address assigned to a virtual machine
+ * instance.
+ */
+ public static final class InstanceUsage extends Usage {
+
+ private static final long serialVersionUID = -5028609518171408695L;
+
+ private final InstanceId instance;
+
+ InstanceUsage(InstanceId instance) {
+ this.instance = checkNotNull(instance);
+ }
+
+ /**
+ * Returns the identity of the instance using the address.
+ */
+ public InstanceId instance() {
+ return instance;
+ }
+
+ @Override
+ public List users() {
+ return ImmutableList.of(instance);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("instance", instance).toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof InstanceUsage && baseEquals((InstanceUsage) obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(instance);
+ }
+
+ @SuppressWarnings("unchecked")
+ static InstanceUsage fromPb(Address addressPb) {
+ return new InstanceUsage(InstanceId.fromUrl(addressPb.getUsers().get(0)));
+ }
+ }
+
+ /**
+ * Usage information for a Google Compute Engine region address assigned to one or more region
+ * forwarding rules.
+ */
+ public static final class RegionForwardingUsage extends Usage {
+
+ private static final long serialVersionUID = -4255145869626427363L;
+
+ private final List forwardingRules;
+
+ RegionForwardingUsage(List forwardingRules) {
+ this.forwardingRules = ImmutableList.copyOf(forwardingRules);
+ }
+
+ /**
+ * Returns a list of identities of region forwarding rules that are currently using the address.
+ */
+ public List forwardingRules() {
+ return forwardingRules;
+ }
+
+ @Override
+ public List users() {
+ return forwardingRules;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("forwardingRules", forwardingRules).toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof RegionForwardingUsage && baseEquals((RegionForwardingUsage) obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(forwardingRules);
+ }
+
+ @SuppressWarnings("unchecked")
+ static RegionForwardingUsage fromPb(Address addressPb) {
+ return new RegionForwardingUsage(
+ Lists.transform(addressPb.getUsers(), RegionForwardingRuleId.FROM_URL_FUNCTION));
+ }
+ }
+
+ /**
+ * Usage information for a Google Compute Engine global address assigned to one or more global
+ * forwarding rules.
+ */
+ public static final class GlobalForwardingUsage extends Usage {
+
+ private static final long serialVersionUID = -2974154224319117433L;
+
+ private final List forwardingRules;
+
+ GlobalForwardingUsage(List forwardingRules) {
+ this.forwardingRules = ImmutableList.copyOf(forwardingRules);
+ }
+
+ /**
+ * Returns a list of identities of global forwarding rules that are currently using the address.
+ */
+ public List forwardingRules() {
+ return forwardingRules;
+ }
+
+ @Override
+ public List users() {
+ return forwardingRules;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("forwardingRules", forwardingRules).toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof GlobalForwardingUsage && baseEquals((GlobalForwardingUsage) obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(forwardingRules);
+ }
+
+ @SuppressWarnings("unchecked")
+ static GlobalForwardingUsage fromPb(Address addressPb) {
+ return new GlobalForwardingUsage(
+ Lists.transform(addressPb.getUsers(), GlobalForwardingRuleId.FROM_URL_FUNCTION));
+ }
+ }
+
+ /**
+ * A builder for {@code AddressInfo} objects.
+ */
+ public abstract static class Builder {
+
+ /**
+ * Sets the actual IP address.
+ */
+ public abstract Builder address(String address);
+
+ abstract Builder creationTimestamp(Long creationTimestamp);
+
+ /**
+ * Sets an optional textual description of the address.
+ */
+ public abstract Builder description(String description);
+
+ abstract Builder id(String id);
+
+ public abstract Builder addressId(AddressId addressId);
+
+ abstract Builder status(Status status);
+
+ abstract Builder usage(Usage usage);
+
+ /**
+ * Creates an {@code AddressInfo} object.
+ */
+ public abstract AddressInfo build();
+ }
+
+ static final class BuilderImpl extends Builder {
+
+ private String address;
+ private Long creationTimestamp;
+ private String description;
+ private String id;
+ private AddressId addressId;
+ private Status status;
+ private Usage usage;
+
+ BuilderImpl() {}
+
+ BuilderImpl(AddressInfo addressInfo) {
+ this.address = addressInfo.address;
+ this.creationTimestamp = addressInfo.creationTimestamp;
+ this.description = addressInfo.description;
+ this.id = addressInfo.id;
+ this.addressId = addressInfo.addressId;
+ this.status = addressInfo.status;
+ this.usage = addressInfo.usage;
+ }
+
+ BuilderImpl(Address addressPb) {
+ if (RegionAddressId.matchesUrl(addressPb.getSelfLink())) {
+ addressId = RegionAddressId.fromUrl(addressPb.getSelfLink());
+ } else {
+ addressId = GlobalAddressId.fromUrl(addressPb.getSelfLink());
+ }
+ address = addressPb.getAddress();
+ if (addressPb.getCreationTimestamp() != null) {
+ creationTimestamp = TIMESTAMP_FORMATTER.parseMillis(addressPb.getCreationTimestamp());
+ }
+ description = addressPb.getDescription();
+ if (addressPb.getId() != null) {
+ id = addressPb.getId().toString();
+ }
+ if (addressPb.getStatus() != null) {
+ status = Status.valueOf(addressPb.getStatus());
+ }
+ if (addressPb.getUsers() != null && addressPb.getUsers().size() > 0) {
+ usage = Usage.fromPb(addressPb);
+ }
+ }
+
+ @Override
+ public BuilderImpl address(String address) {
+ this.address = address;
+ return this;
+ }
+
+ @Override
+ BuilderImpl creationTimestamp(Long creationTimestamp) {
+ this.creationTimestamp = creationTimestamp;
+ return this;
+ }
+
+ @Override
+ public BuilderImpl description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ @Override
+ BuilderImpl id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ @Override
+ public BuilderImpl addressId(AddressId addressId) {
+ this.addressId = checkNotNull(addressId);
+ return this;
+ }
+
+ @Override
+ BuilderImpl status(Status status) {
+ this.status = status;
+ return this;
+ }
+
+ @Override
+ BuilderImpl usage(Usage usage) {
+ this.usage = usage;
+ return this;
+ }
+
+ @Override
+ public AddressInfo build() {
+ return new AddressInfo(this);
+ }
+ }
+
+ AddressInfo(BuilderImpl builder) {
+ address = builder.address;
+ creationTimestamp = builder.creationTimestamp;
+ description = builder.description;
+ id = builder.id;
+ addressId = checkNotNull(builder.addressId);
+ status = builder.status;
+ usage = builder.usage;
+ }
+
+ /**
+ * Returns the static external IP address represented by this object.
+ */
+ public String address() {
+ return address;
+ }
+
+ /**
+ * Returns the creation timestamp in milliseconds since epoch.
+ */
+ public Long creationTimestamp() {
+ return creationTimestamp;
+ }
+
+ /**
+ * Returns an optional textual description of the address.
+ */
+ public String description() {
+ return description;
+ }
+
+ /**
+ * Returns the unique identifier for the address; defined by the service.
+ */
+ public String id() {
+ return id;
+ }
+
+ /**
+ * Returns the address identity. Returns {@link GlobalAddressId} for a global address, returns
+ * {@link RegionAddressId} for a region address.
+ */
+ @SuppressWarnings("unchecked")
+ public T addressId() {
+ return (T) addressId;
+ }
+
+ /**
+ * Returns the status of the address.
+ */
+ public Status status() {
+ return status;
+ }
+
+ /**
+ * Returns the usage information of the address. Returns an {@link InstanceUsage} object for
+ * region addresses that are assigned to VM instances. Returns a {@link RegionForwardingUsage}
+ * object for region addresses assigned to region forwarding rules. Returns a
+ * {@link GlobalForwardingUsage} object for global addresses assigned to global forwarding rules.
+ * Returns {@code null} if the address is not in use.
+ */
+ @SuppressWarnings("unchecked")
+ public T usage() {
+ return (T) usage;
+ }
+
+ /**
+ * Returns a builder for the {@code AddressInfo} object.
+ */
+ public Builder toBuilder() {
+ return new BuilderImpl(this);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("address", address)
+ .add("creationTimestamp", creationTimestamp)
+ .add("description", description)
+ .add("id", id)
+ .add("addressId", addressId)
+ .add("status", status)
+ .add("usage", usage)
+ .toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(address, creationTimestamp, description, id, addressId, status, usage);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null
+ && obj.getClass().equals(AddressInfo.class)
+ && Objects.equals(toPb(), ((AddressInfo) obj).toPb());
+ }
+
+ AddressInfo setProjectId(String projectId) {
+ if (addressId().project() != null) {
+ return this;
+ }
+ return toBuilder().addressId(addressId.setProjectId(projectId)).build();
+ }
+
+ Address toPb() {
+ Address addressPb = usage != null ? usage.toPb() : new Address();
+ addressPb.setAddress(address);
+ if (creationTimestamp != null) {
+ addressPb.setCreationTimestamp(TIMESTAMP_FORMATTER.print(creationTimestamp));
+ }
+ addressPb.setDescription(description);
+ if (id != null) {
+ addressPb.setId(new BigInteger(id));
+ }
+ addressPb.setName(addressId.address());
+ if (addressId.type() == AddressId.Type.REGION) {
+ addressPb.setRegion(this.addressId().regionId().selfLink());
+ }
+ if (status != null) {
+ addressPb.setStatus(status.name());
+ }
+ addressPb.setSelfLink(addressId.selfLink());
+ return addressPb;
+ }
+
+ /**
+ * Returns a builder for the {@code AddressInfo} object given it's identity.
+ */
+ public static Builder builder(AddressId addressId) {
+ return new BuilderImpl().addressId(addressId);
+ }
+
+ /**
+ * Returns an {@code AddressInfo} object for the provided identity.
+ */
+ public static AddressInfo of(AddressId addressId) {
+ return builder(addressId).build();
+ }
+
+ /**
+ * Returns an {@code AddressInfo} object for the provided name. The object corresponds to a global
+ * address.
+ */
+ public static AddressInfo of(String name) {
+ return of(GlobalAddressId.of(name));
+ }
+
+ /**
+ * Returns an {@code AddressInfo} object for the provided region identity and name. The object
+ * corresponds to a region address.
+ */
+ public static AddressInfo of(RegionId regionId, String name) {
+ return of(RegionAddressId.of(regionId, name));
+ }
+
+ /**
+ * Returns an {@code AddressInfo} object for the provided region and address names. The object
+ * corresponds to a region address.
+ */
+ public static AddressInfo of(String region, String name) {
+ return of(RegionAddressId.of(region, name));
+ }
+
+ static AddressInfo fromPb(Address addressPb) {
+ return new BuilderImpl(addressPb).build();
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java
index 8d707a598c32..815b5ebe49e6 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java
@@ -275,6 +275,253 @@ static String selector(OperationField... fields) {
}
}
+ /**
+ * Fields of a Compute Engine Address resource.
+ *
+ * @see Region
+ * Address Resource
+ * @see
+ * Global Address Resource
+ */
+ enum AddressField {
+ ADDRESS("address"),
+ CREATION_TIMESTAMP("creationTimestamp"),
+ DESCRIPTION("description"),
+ ID("id"),
+ NAME("name"),
+ REGION("region"),
+ SELF_LINK("selfLink"),
+ STATUS("status"),
+ USERS("users");
+
+ private final String selector;
+
+ AddressField(String selector) {
+ this.selector = selector;
+ }
+
+ public String selector() {
+ return selector;
+ }
+
+ static String selector(AddressField... fields) {
+ Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1);
+ fieldStrings.add(SELF_LINK.selector());
+ for (AddressField field : fields) {
+ fieldStrings.add(field.selector());
+ }
+ return Joiner.on(',').join(fieldStrings);
+ }
+ }
+
+ /**
+ * Fields of a Compute Engine Disk resource.
+ *
+ * @see Disk
+ * Resource
+ */
+ enum DiskField {
+ CREATION_TIMESTAMP("creationTimestamp"),
+ DESCRIPTION("description"),
+ ID("id"),
+ LAST_ATTACH_TIMESTAMP("lastAttachTimestamp"),
+ LAST_DETACH_TIMESTAMP("lastDetachTimestamp"),
+ LICENSES("licenses"),
+ NAME("name"),
+ OPTIONS("options"),
+ SELF_LINK("selfLink"),
+ SIZE_GB("sizeGb"),
+ SOURCE_IMAGE("sourceImage"),
+ SOURCE_IMAGE_ID("sourceImageId"),
+ SOURCE_SNAPSHOT("sourceSnapshot"),
+ SOURCE_SNAPSHOT_ID("sourceSnapshotId"),
+ STATUS("status"),
+ TYPE("type"),
+ USERS("users"),
+ ZONE("zone");
+
+ private final String selector;
+
+ DiskField(String selector) {
+ this.selector = selector;
+ }
+
+ public String selector() {
+ return selector;
+ }
+
+ static String selector(DiskField... fields) {
+ Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 4);
+ fieldStrings.add(SELF_LINK.selector());
+ fieldStrings.add(TYPE.selector());
+ fieldStrings.add(SOURCE_IMAGE.selector());
+ fieldStrings.add(SOURCE_SNAPSHOT.selector());
+ for (DiskField field : fields) {
+ fieldStrings.add(field.selector());
+ }
+ return Joiner.on(',').join(fieldStrings);
+ }
+ }
+
+ /**
+ * Fields of a Compute Engine Snapshot resource.
+ *
+ * @see
+ * Snapshot Resource
+ */
+ enum SnapshotField {
+ CREATION_TIMESTAMP("creationTimestamp"),
+ DESCRIPTION("description"),
+ DISK_SIZE_GB("diskSizeGb"),
+ ID("id"),
+ LICENSES("licenses"),
+ NAME("name"),
+ SELF_LINK("selfLink"),
+ SOURCE_DISK("sourceDisk"),
+ SOURCE_DISK_ID("sourceDiskId"),
+ STATUS("status"),
+ STORAGE_BYTES("storageBytes"),
+ STORAGE_BYTES_STATUS("storageBytesStatus");
+
+ private final String selector;
+
+ SnapshotField(String selector) {
+ this.selector = selector;
+ }
+
+ public String selector() {
+ return selector;
+ }
+
+ static String selector(SnapshotField... fields) {
+ Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1);
+ fieldStrings.add(SELF_LINK.selector());
+ for (SnapshotField field : fields) {
+ fieldStrings.add(field.selector());
+ }
+ return Joiner.on(',').join(fieldStrings);
+ }
+ }
+
+ /**
+ * Fields of a Compute Engine Image resource.
+ *
+ * @see Image
+ * Resource
+ */
+ enum ImageField {
+ ARCHIVE_SIZE_BYTES("archiveSizeBytes"),
+ CREATION_TIMESTAMP("creationTimestamp"),
+ DEPRECATED("deprecated"),
+ DESCRIPTION("description"),
+ DISK_SIZE_GB("diskSizeGb"),
+ ID("id"),
+ LICENSES("licenses"),
+ NAME("name"),
+ RAW_DISK("rawDisk"),
+ SELF_LINK("selfLink"),
+ SOURCE_DISK("sourceDisk"),
+ SOURCE_DISK_ID("sourceDiskId"),
+ SOURCE_TYPE("sourceType");
+
+ private final String selector;
+
+ ImageField(String selector) {
+ this.selector = selector;
+ }
+
+ public String selector() {
+ return selector;
+ }
+
+ static String selector(ImageField... fields) {
+ Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 3);
+ fieldStrings.add(SELF_LINK.selector());
+ fieldStrings.add(SOURCE_DISK.selector());
+ fieldStrings.add(RAW_DISK.selector());
+ for (ImageField field : fields) {
+ fieldStrings.add(field.selector());
+ }
+ return Joiner.on(',').join(fieldStrings);
+ }
+ }
+
+ /**
+ * Fields of a Compute Engine Subnetwork resource.
+ *
+ * @see
+ * Subnetwork Resource
+ */
+ enum SubnetworkField {
+ CREATION_TIMESTAMP("creationTimestamp"),
+ DESCRIPTION("description"),
+ GATEWAY_ADDRESS("gatewayAddress"),
+ ID("id"),
+ IP_CIDR_RANGE("ipCidrRange"),
+ NAME("name"),
+ NETWORK("network"),
+ REGION("region"),
+ SELF_LINK("selfLink");
+
+ private final String selector;
+
+ SubnetworkField(String selector) {
+ this.selector = selector;
+ }
+
+ public String selector() {
+ return selector;
+ }
+
+ static String selector(SubnetworkField... fields) {
+ Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1);
+ fieldStrings.add(SELF_LINK.selector());
+ for (SubnetworkField field : fields) {
+ fieldStrings.add(field.selector());
+ }
+ return Joiner.on(',').join(fieldStrings);
+ }
+ }
+
+ /**
+ * Fields of a Compute Engine Network resource.
+ *
+ * @see
+ * Network Resource
+ */
+ enum NetworkField {
+ IPV4_RANGE("IPv4Range"),
+ AUTO_CREATE_SUBNETWORKS("autoCreateSubnetworks"),
+ CREATION_TIMESTAMP("creationTimestamp"),
+ DESCRIPTION("description"),
+ GATEWAY_IPV4("gatewayIPv4"),
+ ID("id"),
+ NAME("name"),
+ SELF_LINK("selfLink"),
+ SUBNETWORKS("subnetworks");
+
+ private final String selector;
+
+ NetworkField(String selector) {
+ this.selector = selector;
+ }
+
+ public String selector() {
+ return selector;
+ }
+
+ static String selector(NetworkField... fields) {
+ Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 3);
+ fieldStrings.add(SELF_LINK.selector());
+ fieldStrings.add(IPV4_RANGE.selector());
+ fieldStrings.add(AUTO_CREATE_SUBNETWORKS.selector());
+ for (NetworkField field : fields) {
+ fieldStrings.add(field.selector());
+ }
+ return Joiner.on(',').join(fieldStrings);
+ }
+ }
+
/**
* Base class for list filters.
*/
@@ -540,6 +787,40 @@ public static OperationFilter notEquals(OperationField field, long value) {
}
}
+ /**
+ * Class for filtering address lists.
+ */
+ class AddressFilter extends ListFilter {
+
+ private static final long serialVersionUID = -227481644259653765L;
+
+ AddressFilter(AddressField field, ComparisonOperator operator, Object value) {
+ super(field.selector(), operator, value);
+ }
+
+ /**
+ * Returns an equals filter for the given field and string value. For string fields,
+ * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must
+ * match the entire field.
+ *
+ * @see RE2
+ */
+ public static AddressFilter equals(AddressField field, String value) {
+ return new AddressFilter(checkNotNull(field), ComparisonOperator.EQ, checkNotNull(value));
+ }
+
+ /**
+ * Returns a not-equals filter for the given field and string value. For string fields,
+ * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must
+ * match the entire field.
+ *
+ * @see RE2
+ */
+ public static AddressFilter notEquals(AddressField field, String value) {
+ return new AddressFilter(checkNotNull(field), ComparisonOperator.NE, checkNotNull(value));
+ }
+ }
+
/**
* Class for specifying disk type get options.
*/
@@ -590,7 +871,7 @@ public static DiskTypeListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing disk types.
*/
- public static DiskTypeListOption startPageToken(String pageToken) {
+ public static DiskTypeListOption pageToken(String pageToken) {
return new DiskTypeListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
@@ -635,7 +916,7 @@ public static DiskTypeAggregatedListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing disk types.
*/
- public static DiskTypeAggregatedListOption startPageToken(String pageToken) {
+ public static DiskTypeAggregatedListOption pageToken(String pageToken) {
return new DiskTypeAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
}
@@ -690,7 +971,7 @@ public static MachineTypeListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing machine types.
*/
- public static MachineTypeListOption startPageToken(String pageToken) {
+ public static MachineTypeListOption pageToken(String pageToken) {
return new MachineTypeListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
@@ -735,7 +1016,7 @@ public static MachineTypeAggregatedListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing machine types.
*/
- public static MachineTypeAggregatedListOption startPageToken(String pageToken) {
+ public static MachineTypeAggregatedListOption pageToken(String pageToken) {
return new MachineTypeAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
}
@@ -790,7 +1071,7 @@ public static RegionListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing regions.
*/
- public static RegionListOption startPageToken(String pageToken) {
+ public static RegionListOption pageToken(String pageToken) {
return new RegionListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
@@ -857,7 +1138,7 @@ public static ZoneListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing zones.
*/
- public static ZoneListOption startPageToken(String pageToken) {
+ public static ZoneListOption pageToken(String pageToken) {
return new ZoneListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
@@ -946,7 +1227,7 @@ public static OperationListOption pageSize(long pageSize) {
/**
* Returns an option to specify the page token from which to start listing operations.
*/
- public static OperationListOption startPageToken(String pageToken) {
+ public static OperationListOption pageToken(String pageToken) {
return new OperationListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
}
@@ -963,6 +1244,106 @@ public static OperationListOption fields(OperationField... fields) {
}
}
+ /**
+ * Class for specifying address get options.
+ */
+ class AddressOption extends Option {
+
+ private static final long serialVersionUID = -5755491818692494389L;
+
+ private AddressOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify the address' fields to be returned by the RPC call. If this
+ * option is not provided, all address' fields are returned. {@code AddressOption.fields} can be
+ * used to specify only the fields of interest. {@link Address#addressId()} is always
+ * returned, even if not specified.
+ */
+ public static AddressOption fields(AddressField... fields) {
+ return new AddressOption(ComputeRpc.Option.FIELDS, AddressField.selector(fields));
+ }
+ }
+
+ /**
+ * Class for specifying address list options.
+ */
+ class AddressListOption extends Option {
+
+ private static final long serialVersionUID = -4281322966374929346L;
+
+ private AddressListOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify a filter on the addresses being listed.
+ */
+ public static AddressListOption filter(AddressFilter filter) {
+ return new AddressListOption(ComputeRpc.Option.FILTER, filter.toPb());
+ }
+
+ /**
+ * Returns an option to specify the maximum number of addresses returned per page.
+ */
+ public static AddressListOption pageSize(long pageSize) {
+ return new AddressListOption(ComputeRpc.Option.MAX_RESULTS, pageSize);
+ }
+
+ /**
+ * Returns an option to specify the page token from which to start listing addresses.
+ */
+ public static AddressListOption pageToken(String pageToken) {
+ return new AddressListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
+ }
+
+ /**
+ * Returns an option to specify the address' fields to be returned by the RPC call. If this
+ * option is not provided, all address' fields are returned. {@code AddressListOption.fields}
+ * can be used to specify only the fields of interest. {@link Address#addressId()} is always
+ * returned, even if not specified.
+ */
+ public static AddressListOption fields(AddressField... fields) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("items(").append(AddressField.selector(fields)).append("),nextPageToken");
+ return new AddressListOption(ComputeRpc.Option.FIELDS, builder.toString());
+ }
+ }
+
+ /**
+ * Class for specifying address aggregated list options.
+ */
+ class AddressAggregatedListOption extends Option {
+
+ private static final long serialVersionUID = -95538941541279561L;
+
+ private AddressAggregatedListOption(ComputeRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify a filter on the addresses being listed.
+ */
+ public static AddressAggregatedListOption filter(AddressFilter filter) {
+ return new AddressAggregatedListOption(ComputeRpc.Option.FILTER, filter.toPb());
+ }
+
+ /**
+ * Returns an option to specify the maximum number of addresses returned per page.
+ */
+ public static AddressAggregatedListOption pageSize(long pageSize) {
+ return new AddressAggregatedListOption(ComputeRpc.Option.MAX_RESULTS, pageSize);
+ }
+
+ /**
+ * Returns an option to specify the page token from which to start listing addresses.
+ */
+ public static AddressAggregatedListOption pageToken(String pageToken) {
+ return new AddressAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken);
+ }
+ }
+
/**
* Returns the requested disk type or {@code null} if not found.
*
@@ -1099,4 +1480,49 @@ public static OperationListOption fields(OperationField... fields) {
* @throws ComputeException upon failure
*/
boolean delete(OperationId operation);
+
+ /**
+ * Returns the requested address or {@code null} if not found.
+ *
+ * @throws ComputeException upon failure
+ */
+ Address get(AddressId addressId, AddressOption... options);
+
+ /**
+ * Creates a new address.
+ *
+ * @return an operation for address' creation
+ * @throws ComputeException upon failure
+ */
+ Operation create(AddressInfo address, OperationOption... options);
+
+ /**
+ * Lists the global addresses.
+ *
+ * @throws ComputeException upon failure
+ */
+ Page listGlobalAddresses(AddressListOption... options);
+
+ /**
+ * Lists the region addresses for the provided region.
+ *
+ * @throws ComputeException upon failure
+ */
+ Page listRegionAddresses(String region, AddressListOption... options);
+
+ /**
+ * Lists all addresses.
+ *
+ * @throws ComputeException upon failure
+ */
+ Page listAddresses(AddressAggregatedListOption... options);
+
+ /**
+ * Deletes the requested address.
+ *
+ * @return an operation if the request was issued correctly, {@code null} if the address was not
+ * found
+ * @throws ComputeException upon failure
+ */
+ Operation delete(AddressId addressId, OperationOption... options);
}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java
index 5e6c4bc869a6..838816a035e0 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java
@@ -214,6 +214,65 @@ public Page nextPage() {
}
}
+ private static class GlobalAddressPageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = -3832055341507574454L;
+ private final Map requestOptions;
+ private final ComputeOptions serviceOptions;
+
+ GlobalAddressPageFetcher(ComputeOptions serviceOptions, String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ }
+
+ @Override
+ public Page nextPage() {
+ return listGlobalAddresses(serviceOptions, requestOptions);
+ }
+ }
+
+ private static class RegionAddressPageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = 7080596594494397027L;
+ private final Map requestOptions;
+ private final ComputeOptions serviceOptions;
+ private final String region;
+
+ RegionAddressPageFetcher(String region, ComputeOptions serviceOptions, String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ this.region = region;
+ }
+
+ @Override
+ public Page nextPage() {
+ return listRegionAddresses(region, serviceOptions, requestOptions);
+ }
+ }
+
+ private static class AggregatedAddressPageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = -5798942282919494950L;
+ private final Map requestOptions;
+ private final ComputeOptions serviceOptions;
+
+ AggregatedAddressPageFetcher(ComputeOptions serviceOptions, String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ }
+
+ @Override
+ public Page nextPage() {
+ return listAddresses(serviceOptions, requestOptions);
+ }
+ }
+
private final ComputeRpc computeRpc;
ComputeImpl(ComputeOptions options) {
@@ -555,6 +614,16 @@ public com.google.api.services.compute.model.Operation call() {
}
}
+ private static Function
+ operationFromPb(final ComputeOptions serviceOptions) {
+ return new Function() {
+ @Override
+ public Operation apply(com.google.api.services.compute.model.Operation operation) {
+ return Operation.fromPb(serviceOptions.service(), operation);
+ }
+ };
+ }
+
@Override
public Page listGlobalOperations(OperationListOption... options) {
return listGlobalOperations(options(), optionMap(options));
@@ -575,13 +644,7 @@ Iterable> call() {
String cursor = result.x();
Iterable operations = Iterables.transform(
result.y() == null ? ImmutableList.of()
- : result.y(),
- new Function() {
- @Override
- public Operation apply(com.google.api.services.compute.model.Operation operation) {
- return Operation.fromPb(serviceOptions.service(), operation);
- }
- });
+ : result.y(), operationFromPb(serviceOptions));
return new PageImpl<>(new GlobalOperationPageFetcher(serviceOptions, cursor, optionsMap),
cursor, operations);
} catch (RetryHelper.RetryHelperException e) {
@@ -609,13 +672,7 @@ Iterable> call() {
String cursor = result.x();
Iterable operations = Iterables.transform(
result.y() == null ? ImmutableList.of()
- : result.y(),
- new Function() {
- @Override
- public Operation apply(com.google.api.services.compute.model.Operation operation) {
- return Operation.fromPb(serviceOptions.service(), operation);
- }
- });
+ : result.y(), operationFromPb(serviceOptions));
return new PageImpl<>(new RegionOperationPageFetcher(region, serviceOptions, cursor,
optionsMap), cursor, operations);
} catch (RetryHelper.RetryHelperException e) {
@@ -643,13 +700,7 @@ Iterable> call() {
String cursor = result.x();
Iterable operations = Iterables.transform(
result.y() == null ? ImmutableList.of()
- : result.y(),
- new Function() {
- @Override
- public Operation apply(com.google.api.services.compute.model.Operation operation) {
- return Operation.fromPb(serviceOptions.service(), operation);
- }
- });
+ : result.y(), operationFromPb(serviceOptions));
return new PageImpl<>(new ZoneOperationPageFetcher(zone, serviceOptions, cursor, optionsMap),
cursor, operations);
} catch (RetryHelper.RetryHelperException e) {
@@ -684,6 +735,185 @@ public Boolean call() {
}
}
+ @Override
+ public Address get(final AddressId addressId, AddressOption... options) {
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Address answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Address call() {
+ switch (addressId.type()) {
+ case REGION:
+ RegionAddressId regionAddressId = (RegionAddressId) addressId;
+ return computeRpc.getRegionAddress(regionAddressId.region(),
+ regionAddressId.address(), optionsMap);
+ case GLOBAL:
+ return computeRpc.getGlobalAddress(addressId.address(), optionsMap);
+ default:
+ throw new IllegalArgumentException("Unexpected address identity type");
+ }
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Address.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Operation create(final AddressInfo address, OperationOption... options) {
+ final com.google.api.services.compute.model.Address addressPb =
+ address.setProjectId(options().projectId()).toPb();
+ final Map optionsMap = optionMap(options);
+ try {
+ return Operation.fromPb(this,
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Operation call() {
+ switch (address.addressId().type()) {
+ case REGION:
+ RegionAddressId regionAddressId = address.addressId();
+ return computeRpc.createRegionAddress(regionAddressId.region(), addressPb,
+ optionsMap);
+ case GLOBAL:
+ return computeRpc.createGlobalAddress(addressPb, optionsMap);
+ default:
+ throw new IllegalArgumentException("Unexpected address identity type");
+ }
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER));
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ private static Function addressFromPb(
+ final ComputeOptions serviceOptions) {
+ return new Function() {
+ @Override
+ public Address apply(com.google.api.services.compute.model.Address address) {
+ return Address.fromPb(serviceOptions.service(), address);
+ }
+ };
+ }
+
+ @Override
+ public Page listGlobalAddresses(AddressListOption... options) {
+ return listGlobalAddresses(options(), optionMap(options));
+ }
+
+ private static Page listGlobalAddresses(final ComputeOptions serviceOptions,
+ final Map optionsMap) {
+ try {
+ ComputeRpc.Tuple> result =
+ runWithRetries(new Callable>>() {
+ @Override
+ public ComputeRpc.Tuple> call() {
+ return serviceOptions.rpc().listGlobalAddresses(optionsMap);
+ }
+ }, serviceOptions.retryParams(), EXCEPTION_HANDLER);
+ String cursor = result.x();
+ Iterable operations = Iterables.transform(
+ result.y() == null ? ImmutableList.of()
+ : result.y(), addressFromPb(serviceOptions));
+ return new PageImpl<>(new GlobalAddressPageFetcher(serviceOptions, cursor, optionsMap),
+ cursor, operations);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Page listRegionAddresses(String region, AddressListOption... options) {
+ return listRegionAddresses(region, options(), optionMap(options));
+ }
+
+ private static Page listRegionAddresses(final String region,
+ final ComputeOptions serviceOptions, final Map optionsMap) {
+ try {
+ ComputeRpc.Tuple> result =
+ runWithRetries(new Callable>>() {
+ @Override
+ public ComputeRpc.Tuple> call() {
+ return serviceOptions.rpc().listRegionAddresses(region, optionsMap);
+ }
+ }, serviceOptions.retryParams(), EXCEPTION_HANDLER);
+ String cursor = result.x();
+ Iterable operations = Iterables.transform(
+ result.y() == null ? ImmutableList.of()
+ : result.y(), addressFromPb(serviceOptions));
+ return new PageImpl<>(new RegionAddressPageFetcher(region, serviceOptions, cursor,
+ optionsMap), cursor, operations);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Page listAddresses(AddressAggregatedListOption... options) {
+ return listAddresses(options(), optionMap(options));
+ }
+
+ private static Page listAddresses(final ComputeOptions serviceOptions,
+ final Map optionsMap) {
+ try {
+ ComputeRpc.Tuple> result =
+ runWithRetries(new Callable>>() {
+ @Override
+ public ComputeRpc.Tuple> call() {
+ return serviceOptions.rpc().listAddresses(optionsMap);
+ }
+ }, serviceOptions.retryParams(), EXCEPTION_HANDLER);
+ String cursor = result.x();
+ Iterable operations = Iterables.transform(
+ result.y() == null ? ImmutableList.of()
+ : result.y(),
+ new Function() {
+ @Override
+ public Address apply(com.google.api.services.compute.model.Address address) {
+ return Address.fromPb(serviceOptions.service(), address);
+ }
+ });
+ return new PageImpl<>(new AggregatedAddressPageFetcher(serviceOptions, cursor,
+ optionsMap), cursor, operations);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Operation delete(final AddressId addressId, OperationOption... options) {
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.compute.model.Operation answer =
+ runWithRetries(new Callable() {
+ @Override
+ public com.google.api.services.compute.model.Operation call() {
+ switch (addressId.type()) {
+ case REGION:
+ RegionAddressId regionAddressId = (RegionAddressId) addressId;
+ return computeRpc.deleteRegionAddress(regionAddressId.region(),
+ regionAddressId.address(), optionsMap);
+ case GLOBAL:
+ return computeRpc.deleteGlobalAddress(addressId.address(), optionsMap);
+ default:
+ throw new IllegalArgumentException("Unexpected address identity type");
+ }
+ }
+ }, options().retryParams(), EXCEPTION_HANDLER);
+ return answer == null ? null : Operation.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw ComputeException.translateAndThrow(e);
+ }
+ }
+
private Map optionMap(Option... options) {
Map optionMap = Maps.newEnumMap(ComputeRpc.Option.class);
for (Option option : options) {
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java
index 0991a9d5d666..f6c8342a0f1c 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java
@@ -137,7 +137,7 @@ public DiskTypeId diskTypeId() {
}
/**
- * Returns an unique identifier for the disk type; defined by the service.
+ * Returns the unique identifier for the disk type; defined by the service.
*/
public String id() {
return id;
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java
index cdf1fd42eedc..039565ec827f 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java
@@ -28,7 +28,7 @@
/**
* Identity for a Google Compute Engine disk type.
*/
-public final class DiskTypeId extends ZoneResourceId {
+public final class DiskTypeId extends ResourceId {
static final Function FROM_URL_FUNCTION = new Function() {
@Override
@@ -43,14 +43,16 @@ public String apply(DiskTypeId diskTypeId) {
}
};
- private static final String REGEX = ZoneResourceId.REGEX + "diskTypes/([^/]+)";
+ private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/diskTypes/([^/]+)";
private static final Pattern PATTERN = Pattern.compile(REGEX);
private static final long serialVersionUID = 7337881474103686219L;
+ private final String zone;
private final String diskType;
private DiskTypeId(String project, String zone, String diskType) {
- super(project, zone);
+ super(project);
+ this.zone = checkNotNull(zone);
this.diskType = checkNotNull(diskType);
}
@@ -61,26 +63,47 @@ public String diskType() {
return diskType;
}
+ /**
+ * Returns the name of the zone this disk type belongs to.
+ */
+ public String zone() {
+ return zone;
+ }
+
+ /**
+ * Returns the identity of the zone this disk type belongs to.
+ */
+ public ZoneId zoneId() {
+ return ZoneId.of(project(), zone);
+ }
+
@Override
public String selfLink() {
- return super.selfLink() + "/diskTypes/" + diskType;
+ return super.selfLink() + "/zones/" + zone + "/diskTypes/" + diskType;
}
@Override
MoreObjects.ToStringHelper toStringHelper() {
- return super.toStringHelper().add("diskType", diskType);
+ return super.toStringHelper().add("zone", zone).add("diskType", diskType);
}
@Override
public int hashCode() {
- return Objects.hash(super.baseHashCode(), diskType);
+ return Objects.hash(super.baseHashCode(), zone, diskType);
}
@Override
public boolean equals(Object obj) {
- return obj instanceof DiskTypeId
- && baseEquals((DiskTypeId) obj)
- && Objects.equals(diskType, ((DiskTypeId) obj).diskType);
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof DiskTypeId)) {
+ return false;
+ }
+ DiskTypeId other = (DiskTypeId) obj;
+ return baseEquals(other)
+ && Objects.equals(zone, other.zone)
+ && Objects.equals(diskType, other.diskType);
}
@Override
@@ -88,7 +111,7 @@ DiskTypeId setProjectId(String projectId) {
if (project() != null) {
return this;
}
- return DiskTypeId.of(projectId, zone(), diskType);
+ return DiskTypeId.of(projectId, zone, diskType);
}
/**
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ForwardingRuleId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ForwardingRuleId.java
new file mode 100644
index 000000000000..546dcf596246
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ForwardingRuleId.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+/**
+ * Base class for Google Compute Engine forwarding rule identities.
+ */
+public abstract class ForwardingRuleId extends ResourceId {
+
+ private static final long serialVersionUID = -4352410760458355391L;
+
+ private final String rule;
+
+ ForwardingRuleId(String project, String rule) {
+ super(project);
+ this.rule = checkNotNull(rule);
+ }
+
+ /**
+ * Possible types for a Google Compute Engine forwarding rule identity.
+ */
+ enum Type {
+ /**
+ * Global forwarding rules are used to forward traffic to the correct load balancer for HTTP(S)
+ * load balancing.
+ */
+ GLOBAL,
+
+ /**
+ * Region forwarding rules are used to forward traffic to the correct pool of target virtual
+ * machines.
+ */
+ REGION
+ }
+
+ /**
+ * Returns the type of this forwarding rule identity.
+ */
+ public abstract Type type();
+
+ /**
+ * Returns the name of the forwarding rule. The forwarding rule name must be 1-63 characters long
+ * and comply with RFC1035. Specifically, the name must match the regular expression
+ * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter,
+ * and all following characters must be a dash, lowercase letter, or digit, except the last
+ * character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public String rule() {
+ return rule;
+ }
+
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return super.toStringHelper().add("rule", rule);
+ }
+
+ @Override
+ final int baseHashCode() {
+ return Objects.hash(super.baseHashCode(), rule);
+ }
+
+ @Override
+ final boolean baseEquals(ResourceId resourceId) {
+ return resourceId instanceof ForwardingRuleId
+ && super.baseEquals(resourceId)
+ && Objects.equals(rule, ((ForwardingRuleId) resourceId).rule);
+ }
+
+ @Override
+ abstract ForwardingRuleId setProjectId(String projectId);
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalAddressId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalAddressId.java
new file mode 100644
index 000000000000..dcda73ac7370
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalAddressId.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Identity for a Google Compute Engine global address.
+ */
+public final class GlobalAddressId extends AddressId {
+
+ private static final String REGEX = ResourceId.REGEX + "global/addresses/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = -2950815290049218593L;
+
+ private GlobalAddressId(String project, String address) {
+ super(project, address);
+ }
+
+ @Override
+ public Type type() {
+ return Type.GLOBAL;
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/global/addresses/" + address();
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof GlobalAddressId && baseEquals((GlobalAddressId) obj);
+ }
+
+ @Override
+ GlobalAddressId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return GlobalAddressId.of(projectId, address());
+ }
+
+ /**
+ * Returns an address identity given the address name. The address name must be 1-63 characters
+ * long and comply with RFC1035. Specifically, the name must match the regular expression
+ * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter,
+ * and all following characters must be a dash, lowercase letter, or digit, except the last
+ * character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static GlobalAddressId of(String address) {
+ return new GlobalAddressId(null, address);
+ }
+
+ /**
+ * Returns an address identity given project and address names. The address name must be 1-63
+ * characters long and comply with RFC1035. Specifically, the name must match the regular
+ * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static GlobalAddressId of(String project, String address) {
+ return new GlobalAddressId(project, address);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of a global address
+ * URL. Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static GlobalAddressId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid global address URL");
+ }
+ return GlobalAddressId.of(matcher.group(1), matcher.group(2));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalForwardingRuleId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalForwardingRuleId.java
new file mode 100644
index 000000000000..1b37e9a1adef
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalForwardingRuleId.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import com.google.common.base.Function;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Identity for a Google Compute Engine global forwarding rule.
+ */
+public final class GlobalForwardingRuleId extends ForwardingRuleId {
+
+ static final Function FROM_URL_FUNCTION =
+ new Function() {
+ @Override
+ public GlobalForwardingRuleId apply(String pb) {
+ return GlobalForwardingRuleId.fromUrl(pb);
+ }
+ };
+ static final Function TO_URL_FUNCTION =
+ new Function() {
+ @Override
+ public String apply(GlobalForwardingRuleId forwardingRuleId) {
+ return forwardingRuleId.selfLink();
+ }
+ };
+
+ private static final String REGEX = ResourceId.REGEX + "global/forwardingRules/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = -2648031793037534254L;
+
+ private GlobalForwardingRuleId(String project, String rule) {
+ super(project, rule);
+ }
+
+ @Override
+ public Type type() {
+ return Type.GLOBAL;
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/global/forwardingRules/" + rule();
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof GlobalForwardingRuleId && baseEquals((GlobalForwardingRuleId) obj);
+ }
+
+ @Override
+ GlobalForwardingRuleId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return GlobalForwardingRuleId.of(projectId, rule());
+ }
+
+ /**
+ * Returns a forwarding rule identity given the rule name. The forwarding rule name must be 1-63
+ * characters long and comply with RFC1035. Specifically, the name must match the regular
+ * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static GlobalForwardingRuleId of(String rule) {
+ return new GlobalForwardingRuleId(null, rule);
+ }
+
+ /**
+ * Returns a forwarding rule identity given the project rule names. The forwarding rule name must
+ * be 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular
+ * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static GlobalForwardingRuleId of(String project, String rule) {
+ return new GlobalForwardingRuleId(project, rule);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of a global forwarding
+ * rule URL. Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static GlobalForwardingRuleId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid global forwarding rule URL");
+ }
+ return GlobalForwardingRuleId.of(matcher.group(1), matcher.group(2));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java
index c12e24c903cc..343b0cacc94c 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java
@@ -16,28 +16,20 @@
package com.google.gcloud.compute;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.MoreObjects;
-
-import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Identity for a Google Compute Engine global operation.
*/
-public class GlobalOperationId extends ResourceId implements OperationId {
+public final class GlobalOperationId extends OperationId {
private static final String REGEX = ResourceId.REGEX + "global/operations/([^/]+)";
private static final Pattern PATTERN = Pattern.compile(REGEX);
private static final long serialVersionUID = 3945756772641577962L;
- private final String operation;
-
private GlobalOperationId(String project, String operation) {
- super(project);
- this.operation = checkNotNull(operation);
+ super(project, operation);
}
@Override
@@ -45,31 +37,19 @@ public Type type() {
return Type.GLOBAL;
}
- @Override
- public String operation() {
- return operation;
- }
-
@Override
public String selfLink() {
- return super.selfLink() + "/global/operations/" + operation;
- }
-
- @Override
- MoreObjects.ToStringHelper toStringHelper() {
- return super.toStringHelper().add("operation", operation);
+ return super.selfLink() + "/global/operations/" + operation();
}
@Override
public int hashCode() {
- return Objects.hash(baseHashCode(), operation);
+ return baseHashCode();
}
@Override
public boolean equals(Object obj) {
- return obj instanceof GlobalOperationId
- && baseEquals((GlobalOperationId) obj)
- && Objects.equals(operation, ((GlobalOperationId) obj).operation);
+ return obj instanceof GlobalOperationId && baseEquals((GlobalOperationId) obj);
}
@Override
@@ -77,7 +57,7 @@ GlobalOperationId setProjectId(String projectId) {
if (project() != null) {
return this;
}
- return GlobalOperationId.of(projectId, operation);
+ return GlobalOperationId.of(projectId, operation());
}
/**
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/InstanceId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/InstanceId.java
new file mode 100644
index 000000000000..408d95e641b4
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/InstanceId.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Identity for a Google Compute Engine virtual machine instance.
+ */
+public final class InstanceId extends ResourceId {
+
+ static final Function FROM_URL_FUNCTION = new Function() {
+ @Override
+ public InstanceId apply(String pb) {
+ return InstanceId.fromUrl(pb);
+ }
+ };
+ static final Function TO_URL_FUNCTION = new Function() {
+ @Override
+ public String apply(InstanceId instanceId) {
+ return instanceId.selfLink();
+ }
+ };
+
+ private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/instances/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = -2787043125223159922L;
+
+ private final String zone;
+ private final String instance;
+
+ private InstanceId(String project, String zone, String instance) {
+ super(project);
+ this.zone = checkNotNull(zone);
+ this.instance = checkNotNull(instance);
+ }
+
+ /**
+ * Returns the name of the instance. The name must be 1-63 characters long and comply with
+ * RFC1035. Specifically, the name must match the regular expression
+ * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter,
+ * and all following characters must be a dash, lowercase letter, or digit, except the last
+ * character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public String instance() {
+ return instance;
+ }
+
+ /**
+ * Returns the name of the zone this instance belongs to.
+ */
+ public String zone() {
+ return zone;
+ }
+
+ /**
+ * Returns the identity of the zone this instance belongs to.
+ */
+ public ZoneId zoneId() {
+ return ZoneId.of(project(), zone);
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/zones/" + zone + "/instances/" + instance;
+ }
+
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return MoreObjects.toStringHelper(this).add("zone", zone).add("instance", instance);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.baseHashCode(), zone, instance);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof InstanceId)) {
+ return false;
+ }
+ InstanceId other = (InstanceId) obj;
+ return baseEquals(other)
+ && Objects.equals(zone, other.zone)
+ && Objects.equals(instance, other.instance);
+ }
+
+ @Override
+ InstanceId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return InstanceId.of(projectId, zone, instance);
+ }
+
+ /**
+ * Returns an instance identity given the zone identity and the instance name. The instance name
+ * must be 1-63 characters long and comply with RFC1035. Specifically, the name must match the
+ * regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static InstanceId of(ZoneId zoneId, String instance) {
+ return new InstanceId(zoneId.project(), zoneId.zone(), instance);
+ }
+
+ /**
+ * Returns an instance identity given the zone and instance names. The instance name must be 1-63
+ * characters long and comply with RFC1035. Specifically, the name must match the regular
+ * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static InstanceId of(String zone, String instance) {
+ return new InstanceId(null, zone, instance);
+ }
+
+ /**
+ * Returns an instance identity given project, zone and instance names. The instance name must be
+ * 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular
+ * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static InstanceId of(String project, String zone, String instance) {
+ return new InstanceId(project, zone, instance);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of an instance URL.
+ * Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static InstanceId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid instance URL");
+ }
+ return InstanceId.of(matcher.group(1), matcher.group(2), matcher.group(3));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java
index 36d3037bc41b..0166e03ed325 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java
@@ -78,9 +78,14 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
- return obj instanceof LicenseId
- && baseEquals((LicenseId) obj)
- && Objects.equals(license, ((LicenseId) obj).license);
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof LicenseId)) {
+ return false;
+ }
+ LicenseId other = (LicenseId) obj;
+ return baseEquals(other) && Objects.equals(license, other.license);
}
@Override
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java
index d9c446dddf72..2d7bfa7d26c8 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java
@@ -160,7 +160,7 @@ public MachineTypeId machineTypeId() {
}
/**
- * Returns an unique identifier for the machine type; defined by the service.
+ * Returns the unique identifier for the machine type; defined by the service.
*/
public String id() {
return id;
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java
index 1252719e05d7..a431d29d1e85 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java
@@ -28,7 +28,7 @@
/**
* Identity for a Google Compute Engine machine type.
*/
-public final class MachineTypeId extends ZoneResourceId {
+public final class MachineTypeId extends ResourceId {
static final Function FROM_URL_FUNCTION =
new Function() {
@@ -45,14 +45,16 @@ public String apply(MachineTypeId machineTypeId) {
}
};
- private static final String REGEX = ZoneResourceId.REGEX + "machineTypes/([^/]+)";
+ private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/machineTypes/([^/]+)";
private static final Pattern PATTERN = Pattern.compile(REGEX);
private static final long serialVersionUID = -5819598544478859608L;
+ private final String zone;
private final String machineType;
private MachineTypeId(String project, String zone, String machineType) {
- super(project, zone);
+ super(project);
+ this.zone = checkNotNull(zone);
this.machineType = checkNotNull(machineType);
}
@@ -63,26 +65,47 @@ public String machineType() {
return machineType;
}
+ /**
+ * Returns the name of the zone this machine type belongs to.
+ */
+ public String zone() {
+ return zone;
+ }
+
+ /**
+ * Returns the identity of the zone this machine type belongs to.
+ */
+ public ZoneId zoneId() {
+ return ZoneId.of(project(), zone);
+ }
+
@Override
public String selfLink() {
- return super.selfLink() + "/machineTypes/" + machineType;
+ return super.selfLink() + "/zones/" + zone + "/machineTypes/" + machineType;
}
@Override
MoreObjects.ToStringHelper toStringHelper() {
- return super.toStringHelper().add("machineType", machineType);
+ return super.toStringHelper().add("zone", zone).add("machineType", machineType);
}
@Override
public int hashCode() {
- return Objects.hash(baseHashCode(), machineType);
+ return Objects.hash(baseHashCode(), zone, machineType);
}
@Override
public boolean equals(Object obj) {
- return obj instanceof MachineTypeId
- && baseEquals((MachineTypeId) obj)
- && Objects.equals(machineType, ((MachineTypeId) obj).machineType);
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof MachineTypeId)) {
+ return false;
+ }
+ MachineTypeId other = (MachineTypeId) obj;
+ return baseEquals(other)
+ && Objects.equals(zone, other.zone)
+ && Objects.equals(machineType, other.machineType);
}
@Override
@@ -90,7 +113,7 @@ MachineTypeId setProjectId(String projectId) {
if (project() != null) {
return this;
}
- return MachineTypeId.of(projectId, zone(), machineType);
+ return MachineTypeId.of(projectId, zone, machineType);
}
/**
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java
index 7b8a888cf40c..ce519edc970d 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java
@@ -17,8 +17,6 @@
package com.google.gcloud.compute;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.gcloud.compute.OperationId.Type.REGION;
-import static com.google.gcloud.compute.OperationId.Type.ZONE;
import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java
index 7f9100aa61a2..5ddf2dae43a2 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java
@@ -16,10 +16,25 @@
package com.google.gcloud.compute;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
/**
- * Interface for Google Compute Engine operation identities.
+ * Base class for Google Compute Engine operation identities.
*/
-public interface OperationId {
+public abstract class OperationId extends ResourceId {
+
+ private static final long serialVersionUID = -5502909279744388604L;
+
+ private final String operation;
+
+ OperationId(String project, String operation) {
+ super(project);
+ this.operation = checkNotNull(operation);
+ }
/**
* Possible types for a Google Compute Engine operation identity.
@@ -30,11 +45,13 @@ enum Type {
* addresses or snapshots.
*/
GLOBAL,
+
/**
* Region operations are those operations that deal with resources that live in a region, such
* as subnetworks.
*/
REGION,
+
/**
* Zone operations are those operations that deal with resources that live in a zone, such as
* disks and instances.
@@ -45,20 +62,32 @@ enum Type {
/**
* Returns the type of this operation identity.
*/
- Type type();
-
- /**
- * Returns the name of the project.
- */
- String project();
+ public abstract Type type();
/**
* Returns the name of the operation resource.
*/
- String operation();
+ public String operation() {
+ return operation;
+ }
- /**
- * Returns a fully qualified URL to the operation.
- */
- String selfLink();
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return super.toStringHelper().add("operation", operation);
+ }
+
+ @Override
+ final int baseHashCode() {
+ return Objects.hash(super.baseHashCode(), operation);
+ }
+
+ @Override
+ final boolean baseEquals(ResourceId resourceId) {
+ return resourceId instanceof OperationId
+ && super.baseEquals(resourceId)
+ && Objects.equals(operation, ((OperationId) resourceId).operation);
+ }
+
+ @Override
+ abstract OperationId setProjectId(String projectId);
}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java
index 470acf4e9061..fb7890187a14 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java
@@ -241,7 +241,7 @@ public RegionId regionId() {
}
/**
- * Returns an unique identifier for the region; defined by the service.
+ * Returns the unique identifier for the region; defined by the service.
*/
public String id() {
return id;
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionAddressId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionAddressId.java
new file mode 100644
index 000000000000..6ea0538b0edf
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionAddressId.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Identity for a Google Compute Engine region address.
+ */
+public final class RegionAddressId extends AddressId {
+
+ private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/addresses/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = 8170980880371085238L;
+
+ private final String region;
+
+ private RegionAddressId(String project, String region, String address) {
+ super(project, address);
+ this.region = checkNotNull(region);
+ }
+
+ @Override
+ public Type type() {
+ return Type.REGION;
+ }
+
+ /**
+ * Returns the name of the region this address belongs to.
+ */
+ public String region() {
+ return region;
+ }
+
+ /**
+ * Returns the identity of the region this address belongs to.
+ */
+ public RegionId regionId() {
+ return RegionId.of(project(), region);
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/regions/" + region + "/addresses/" + address();
+ }
+
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return super.toStringHelper().add("region", region);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(baseHashCode(), region);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RegionAddressId)) {
+ return false;
+ }
+ RegionAddressId other = (RegionAddressId) obj;
+ return baseEquals(other) && Objects.equals(region, other.region);
+ }
+
+ @Override
+ RegionAddressId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return RegionAddressId.of(projectId, region, address());
+ }
+
+ /**
+ * Returns a region address identity given the region identity and the address name. The address
+ * name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63
+ * characters long and match the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means
+ * the first character must be a lowercase letter, and all following characters must be a dash,
+ * lowercase letter, or digit, except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static RegionAddressId of(RegionId regionId, String address) {
+ return new RegionAddressId(regionId.project(), regionId.region(), address);
+ }
+
+ /**
+ * Returns a region address identity given the region and address names. The address name must be
+ * 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular
+ * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static RegionAddressId of(String region, String address) {
+ return new RegionAddressId(null, region, address);
+ }
+
+ /**
+ * Returns a region address identity given project, region and address names. The address name
+ * must be 1-63 characters long and comply with RFC1035. Specifically, the name must match the
+ * regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a
+ * lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static RegionAddressId of(String project, String region, String address) {
+ return new RegionAddressId(project, region, address);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of a region address
+ * URL. Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static RegionAddressId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid region address URL");
+ }
+ return RegionAddressId.of(matcher.group(1), matcher.group(2), matcher.group(3));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionForwardingRuleId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionForwardingRuleId.java
new file mode 100644
index 000000000000..b6e7e120f94a
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionForwardingRuleId.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.gcloud.compute;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Identity for a Google Compute Engine region's forwarding rule.
+ */
+public final class RegionForwardingRuleId extends ForwardingRuleId {
+
+ static final Function FROM_URL_FUNCTION =
+ new Function() {
+ @Override
+ public RegionForwardingRuleId apply(String pb) {
+ return RegionForwardingRuleId.fromUrl(pb);
+ }
+ };
+ static final Function TO_URL_FUNCTION =
+ new Function() {
+ @Override
+ public String apply(RegionForwardingRuleId forwardingRuleId) {
+ return forwardingRuleId.selfLink();
+ }
+ };
+
+ private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/forwardingRules/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = 7885327931402904667L;
+
+ private final String region;
+
+ private RegionForwardingRuleId(String project, String region, String rule) {
+ super(project, rule);
+ this.region = checkNotNull(region);
+ }
+
+ @Override
+ public Type type() {
+ return Type.REGION;
+ }
+
+ /**
+ * Returns the name of the region this forwarding rule belongs to.
+ */
+ public String region() {
+ return region;
+ }
+
+ /**
+ * Returns the identity of the region this forwarding rule belongs to.
+ */
+ public RegionId regionId() {
+ return RegionId.of(project(), region);
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/regions/" + region + "/forwardingRules/" + rule();
+ }
+
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return MoreObjects.toStringHelper(this).add("region", region);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(baseHashCode(), region);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RegionForwardingRuleId)) {
+ return false;
+ }
+ RegionForwardingRuleId other = (RegionForwardingRuleId) obj;
+ return baseEquals(other) && Objects.equals(region, other.region);
+ }
+
+ @Override
+ RegionForwardingRuleId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return RegionForwardingRuleId.of(projectId, region, rule());
+ }
+
+ /**
+ * Returns a region forwarding rule identity given the region identity and the rule name. The
+ * forwarding rule name must be 1-63 characters long and comply with RFC1035. Specifically, the
+ * name must match the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first
+ * character must be a lowercase letter, and all following characters must be a dash, lowercase
+ * letter, or digit, except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static RegionForwardingRuleId of(RegionId regionId, String rule) {
+ return new RegionForwardingRuleId(regionId.project(), regionId.region(), rule);
+ }
+
+ /**
+ * Returns a region forwarding rule identity given the region and rule names. The forwarding rule
+ * name must be 1-63 characters long and comply with RFC1035. Specifically, the name must match
+ * the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must
+ * be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit,
+ * except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static RegionForwardingRuleId of(String region, String rule) {
+ return new RegionForwardingRuleId(null, region, rule);
+ }
+
+ /**
+ * Returns a region forwarding rule identity given project, region and rule names. The forwarding
+ * rule name must be 1-63 characters long and comply with RFC1035. Specifically, the name must
+ * match the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character
+ * must be a lowercase letter, and all following characters must be a dash, lowercase letter, or
+ * digit, except the last character, which cannot be a dash.
+ *
+ * @see RFC1035
+ */
+ public static RegionForwardingRuleId of(String project, String region, String rule) {
+ return new RegionForwardingRuleId(project, region, rule);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of a region forwarding
+ * rule URL. Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static RegionForwardingRuleId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid region forwarding rule URL");
+ }
+ return RegionForwardingRuleId.of(matcher.group(1), matcher.group(2), matcher.group(3));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java
index 403edd47ce48..7e0f03e1e3ac 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java
@@ -83,9 +83,14 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
- return obj instanceof RegionId
- && baseEquals((RegionId) obj)
- && Objects.equals(region, ((RegionId) obj).region);
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RegionId)) {
+ return false;
+ }
+ RegionId other = (RegionId) obj;
+ return baseEquals(other) && Objects.equals(region, other.region);
}
@Override
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java
index 96a772b5b9ea..b244c60fadf0 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java
@@ -27,17 +27,17 @@
/**
* Identity for a Google Compute Engine region's operation.
*/
-public final class RegionOperationId extends RegionResourceId implements OperationId {
+public final class RegionOperationId extends OperationId {
- private static final String REGEX = RegionResourceId.REGEX + "operations/([^/]+)";
+ private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/operations/([^/]+)";
private static final Pattern PATTERN = Pattern.compile(REGEX);
private static final long serialVersionUID = 5816161906501886782L;
- private final String operation;
+ private final String region;
private RegionOperationId(String project, String region, String operation) {
- super(project, region);
- this.operation = checkNotNull(operation);
+ super(project, operation);
+ this.region = checkNotNull(region);
}
@Override
@@ -45,31 +45,45 @@ public Type type() {
return Type.REGION;
}
- @Override
- public String operation() {
- return operation;
+ /**
+ * Returns the name of the region this operation belongs to.
+ */
+ public String region() {
+ return region;
+ }
+
+ /**
+ * Returns the identity of the region this operation belongs to.
+ */
+ public RegionId regionId() {
+ return RegionId.of(project(), region);
}
@Override
public String selfLink() {
- return super.selfLink() + "/operations/" + operation;
+ return super.selfLink() + "/regions/" + region + "/operations/" + operation();
}
@Override
MoreObjects.ToStringHelper toStringHelper() {
- return MoreObjects.toStringHelper(this).add("operation", operation);
+ return MoreObjects.toStringHelper(this).add("region", region);
}
@Override
public int hashCode() {
- return Objects.hash(baseHashCode(), operation);
+ return Objects.hash(baseHashCode(), region);
}
@Override
public boolean equals(Object obj) {
- return obj instanceof RegionOperationId
- && baseEquals((RegionOperationId) obj)
- && Objects.equals(operation, ((RegionOperationId) obj).operation);
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RegionOperationId)) {
+ return false;
+ }
+ RegionOperationId other = (RegionOperationId) obj;
+ return baseEquals(other) && Objects.equals(region, other.region);
}
@Override
@@ -77,7 +91,7 @@ RegionOperationId setProjectId(String projectId) {
if (project() != null) {
return this;
}
- return RegionOperationId.of(projectId, region(), operation);
+ return RegionOperationId.of(projectId, region, operation());
}
/**
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionResourceId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionResourceId.java
deleted file mode 100644
index eeb288b07be1..000000000000
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionResourceId.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.gcloud.compute;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.Objects;
-
-/**
- * A base class for the identity of Google Compute Engine resources that live in a region.
- */
-public abstract class RegionResourceId extends ResourceId {
-
- static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/";
- private static final long serialVersionUID = 5569092266957249294L;
-
- private final String region;
-
- RegionResourceId(String project, String region) {
- super(project);
- this.region = checkNotNull(region);
- }
-
- RegionResourceId(RegionId regionId) {
- super(regionId.project());
- this.region = checkNotNull(regionId.region());
- }
-
- /**
- * Returns the name of the region this resource belongs to.
- */
- public final String region() {
- return region;
- }
-
- /**
- * Returns the identity of the region this resource belongs to.
- */
- public final RegionId regionId() {
- return RegionId.of(project(), region);
- }
-
- @Override
- public String selfLink() {
- return super.selfLink() + "/regions/" + region;
- }
-
- @Override
- ToStringHelper toStringHelper() {
- return super.toStringHelper().add("region", region);
- }
-
- @Override
- final int baseHashCode() {
- return Objects.hash(super.baseHashCode(), region);
- }
-
- @Override
- final boolean baseEquals(ResourceId resourceId) {
- return resourceId instanceof RegionResourceId
- && super.baseEquals(resourceId)
- && Objects.equals(region, ((RegionResourceId) resourceId).region);
- }
-}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java
index 903f994118de..7c766bef27c9 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java
@@ -270,7 +270,7 @@ public String description() {
}
/**
- * Returns an unique identifier for the zone; defined by the service.
+ * Returns the unique identifier for the zone; defined by the service.
*/
public String id() {
return id;
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java
index 74ac5be58201..56386ace5455 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java
@@ -78,9 +78,14 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
- return obj instanceof ZoneId
- && baseEquals((ZoneId) obj)
- && Objects.equals(zone, ((ZoneId) obj).zone);
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ZoneId)) {
+ return false;
+ }
+ ZoneId other = (ZoneId) obj;
+ return baseEquals(other) && Objects.equals(zone, other.zone);
}
@Override
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java
index 837ca6888c83..99161b0f4eda 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java
@@ -27,17 +27,17 @@
/**
* Identity for a Google Compute Engine zone operation.
*/
-public final class ZoneOperationId extends ZoneResourceId implements OperationId {
+public final class ZoneOperationId extends OperationId {
- private static final String REGEX = ZoneResourceId.REGEX + "operations/([^/]+)";
+ private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/operations/([^/]+)";
private static final Pattern PATTERN = Pattern.compile(REGEX);
private static final long serialVersionUID = 4910670262094017392L;
- private final String operation;
+ private final String zone;
private ZoneOperationId(String project, String zone, String operation) {
- super(project, zone);
- this.operation = checkNotNull(operation);
+ super(project, operation);
+ this.zone = checkNotNull(zone);
}
@Override
@@ -45,31 +45,40 @@ public Type type() {
return Type.ZONE;
}
- @Override
- public String operation() {
- return operation;
+ /**
+ * Returns the name of the zone this operation belongs to.
+ */
+ public String zone() {
+ return zone;
+ }
+
+ /**
+ * Returns the identity of the zone this address belongs to.
+ */
+ public ZoneId zoneId() {
+ return ZoneId.of(project(), zone);
}
@Override
public String selfLink() {
- return super.selfLink() + "/operations/" + operation;
+ return super.selfLink() + "/zones/" + zone + "/operations/" + operation();
}
@Override
MoreObjects.ToStringHelper toStringHelper() {
- return MoreObjects.toStringHelper(this).add("operation", operation);
+ return MoreObjects.toStringHelper(this).add("zone", zone);
}
@Override
public int hashCode() {
- return Objects.hash(baseHashCode(), operation);
+ return Objects.hash(baseHashCode(), zone);
}
@Override
public boolean equals(Object obj) {
return obj instanceof ZoneOperationId
&& baseEquals((ZoneOperationId) obj)
- && Objects.equals(operation, ((ZoneOperationId) obj).operation);
+ && Objects.equals(zone, ((ZoneOperationId) obj).zone);
}
@Override
@@ -77,7 +86,7 @@ ZoneOperationId setProjectId(String projectId) {
if (project() != null) {
return this;
}
- return ZoneOperationId.of(projectId, zone(), operation);
+ return ZoneOperationId.of(projectId, zone, operation());
}
/**
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneResourceId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneResourceId.java
deleted file mode 100644
index 60117684c056..000000000000
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneResourceId.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.gcloud.compute;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.Objects;
-
-/**
- * A base class for the identity of Google Compute Engine resources that live in a zone.
- */
-public abstract class ZoneResourceId extends ResourceId {
-
- static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/";
- private static final long serialVersionUID = -6249546895344926888L;
-
- private final String zone;
-
- ZoneResourceId(String project, String zone) {
- super(project);
- this.zone = checkNotNull(zone);
- }
-
- ZoneResourceId(ZoneId zoneId) {
- super(zoneId.project());
- this.zone = checkNotNull(zoneId.zone());
- }
-
- /**
- * Returns the name of the zone this resource belongs to.
- */
- public final String zone() {
- return zone;
- }
-
- /**
- * Returns the identity of the zone this resource belongs to.
- */
- public final ZoneId zoneId() {
- return ZoneId.of(project(), zone);
- }
-
- @Override
- public String selfLink() {
- return super.selfLink() + "/zones/" + zone;
- }
-
- @Override
- ToStringHelper toStringHelper() {
- return super.toStringHelper().add("zone", zone);
- }
-
- @Override
- final int baseHashCode() {
- return Objects.hash(super.baseHashCode(), zone);
- }
-
- @Override
- final boolean baseEquals(ResourceId resourceId) {
- return resourceId instanceof ZoneResourceId
- && super.baseEquals(resourceId)
- && Objects.equals(zone, ((ZoneResourceId) resourceId).zone);
- }
-}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java
index 266b31cd7c93..3613c75a4b7c 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java
@@ -22,6 +22,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -51,6 +52,16 @@ public ComputeOptions options() {
return options;
}
+ /**
+ * Returns a base name for testing resources generated using a random UUID. This base name can be
+ * prepended to resource names to prevent name clashes. This method always returns a 30 characters
+ * long prefix. Since Compute Engine resource names can be at most 63 characters long your suffix
+ * should be no longer than 33 characters.
+ */
+ public static String baseResourceName() {
+ return "test-" + UUID.randomUUID().toString().replace("-", "").substring(0, 24) + "-";
+ }
+
/**
* Creates a {@code RemoteComputeHelper} object for the given project id and JSON key input
* stream.
@@ -60,8 +71,7 @@ public ComputeOptions options() {
* @return A {@code RemoteComputeHelper} object for the provided options
* @throws ComputeHelperException if {@code keyStream} is not a valid JSON key stream
*/
- public static RemoteComputeHelper create(String projectId, InputStream keyStream)
- throws ComputeHelperException {
+ public static RemoteComputeHelper create(String projectId, InputStream keyStream) {
try {
ComputeOptions computeOptions = ComputeOptions.builder()
.authCredentials(AuthCredentials.createForJson(keyStream))
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java b/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java
index 740ad73b5b2e..66152f5464a4 100644
--- a/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java
@@ -16,6 +16,7 @@
package com.google.gcloud.spi;
+import com.google.api.services.compute.model.Address;
import com.google.api.services.compute.model.DiskType;
import com.google.api.services.compute.model.License;
import com.google.api.services.compute.model.MachineType;
@@ -228,4 +229,73 @@ public Y y() {
* @throws ComputeException upon failure
*/
boolean deleteZoneOperation(String zone, String operation);
+
+ /**
+ * Returns the requested global address or {@code null} if not found.
+ *
+ * @throws ComputeException upon failure
+ */
+ Address getGlobalAddress(String address, Map