diff --git a/gcloud-java-core/pom.xml b/gcloud-java-core/pom.xml
index cde25fd1d7f0..f195f7900407 100644
--- a/gcloud-java-core/pom.xml
+++ b/gcloud-java-core/pom.xml
@@ -108,5 +108,10 @@
gax
0.0.13
+
+ com.google.api.grpc
+ grpc-core-proto
+ 0.0.4
+
diff --git a/gcloud-java-core/src/main/java/com/google/cloud/MonitoredResourceDescriptor.java b/gcloud-java-core/src/main/java/com/google/cloud/MonitoredResourceDescriptor.java
new file mode 100644
index 000000000000..d743e1d39629
--- /dev/null
+++ b/gcloud-java-core/src/main/java/com/google/cloud/MonitoredResourceDescriptor.java
@@ -0,0 +1,345 @@
+/*
+ * 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.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * This class describes the schema of Cloud monitored resources. Monitored resource descriptors
+ * contain a type name and a set of labels. For example, the monitored resource descriptor for
+ * Google Compute Engine VM instances has a type of {@code gce_instance} and specifies the use of
+ * the labels {@code instance_id} and {@code zone} to identify particular VM instances.
+ */
+public class MonitoredResourceDescriptor implements Serializable {
+
+ private static final long serialVersionUID = -3702077512777687441L;
+ public static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public MonitoredResourceDescriptor apply(
+ com.google.api.MonitoredResourceDescriptor pb) {
+ return fromPb(pb);
+ }
+ };
+
+ private final String type;
+ private final String name;
+ private final String displayName;
+ private final String description;
+ private final List labels;
+
+ /**
+ * This class describes a label for a monitored resource. Label descriptors contain the key for
+ * the label, the type of data that the label can hold and an optional description.
+ */
+ public static class LabelDescriptor implements Serializable {
+
+ private static final long serialVersionUID = -2811608103754481777L;
+ private static final Function
+ FROM_PB_FUNCTION = new Function() {
+ @Override
+ public LabelDescriptor apply(com.google.api.LabelDescriptor descriptorPb) {
+ return fromPb(descriptorPb);
+ }
+ };
+ private static final Function
+ TO_PB_FUNCTION = new Function() {
+ @Override
+ public com.google.api.LabelDescriptor apply(LabelDescriptor descriptor) {
+ return descriptor.toPb();
+ }
+ };
+
+ private final String key;
+ private final ValueType valueType;
+ private final String description;
+
+ /**
+ * Value types that can be used as label values.
+ */
+ public enum ValueType {
+ STRING(com.google.api.LabelDescriptor.ValueType.STRING),
+ BOOL(com.google.api.LabelDescriptor.ValueType.BOOL),
+ INT64(com.google.api.LabelDescriptor.ValueType.INT64);
+
+ private com.google.api.LabelDescriptor.ValueType typePb;
+
+ ValueType(com.google.api.LabelDescriptor.ValueType typePb) {
+ this.typePb = typePb;
+ }
+
+ com.google.api.LabelDescriptor.ValueType toPb() {
+ return typePb;
+ }
+
+ static ValueType fromPb(com.google.api.LabelDescriptor.ValueType typePb) {
+ switch (typePb) {
+ case STRING:
+ return ValueType.STRING;
+ case BOOL:
+ return ValueType.BOOL;
+ case INT64:
+ return ValueType.INT64;
+ default:
+ throw new IllegalArgumentException("Unrecognized label type");
+ }
+ }
+ }
+
+ LabelDescriptor(String key, ValueType valueType, String description) {
+ this.key = checkNotNull(key);
+ this.valueType = checkNotNull(valueType);
+ this.description = description;
+ }
+
+ /**
+ * Returns the key associated to this label.
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Returns the type of data that can be assigned to this label.
+ */
+ public ValueType valueType() {
+ return valueType;
+ }
+
+ /**
+ * Returns the optional human-readable description for this label. If not set, this method
+ * returns {@code null}.
+ */
+ public String description() {
+ return description;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(key, valueType, description);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !obj.getClass().equals(LabelDescriptor.class)) {
+ return false;
+ }
+ LabelDescriptor other = (LabelDescriptor) obj;
+ return Objects.equals(key, other.key)
+ && Objects.equals(valueType, other.valueType)
+ && Objects.equals(description, other.description);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("key", key)
+ .add("valueType", valueType)
+ .add("description", description)
+ .toString();
+ }
+
+ com.google.api.LabelDescriptor toPb() {
+ com.google.api.LabelDescriptor.Builder builder = com.google.api.LabelDescriptor.newBuilder()
+ .setKey(key)
+ .setValueType(valueType.toPb());
+ if (description != null) {
+ builder.setDescription(description);
+ }
+ return builder.build();
+ }
+
+ static LabelDescriptor fromPb(com.google.api.LabelDescriptor descriptorPb) {
+ String description = null;
+ if (descriptorPb.getDescription() != null && !descriptorPb.getDescription().equals("")) {
+ description = descriptorPb.getDescription();
+ }
+ return new LabelDescriptor(descriptorPb.getKey(),
+ ValueType.fromPb(descriptorPb.getValueType()), description);
+ }
+ }
+
+ static class Builder {
+
+ private final String type;
+ private String name;
+ private String displayName;
+ private String description;
+ private List labels = new ArrayList<>();
+
+ Builder(String type) {
+ this.type = type;
+ }
+
+ Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ Builder displayName(String displayName) {
+ this.displayName = displayName;
+ return this;
+ }
+
+ Builder description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ Builder labels(List labels) {
+ this.labels = labels;
+ return this;
+ }
+
+ MonitoredResourceDescriptor build() {
+ return new MonitoredResourceDescriptor(this);
+ }
+ }
+
+ MonitoredResourceDescriptor(Builder builder) {
+ this.type = checkNotNull(builder.type);
+ this.name = builder.name;
+ this.displayName = builder.displayName;
+ this.description = builder.description;
+ this.labels = checkNotNull(builder.labels);
+ }
+
+ /**
+ * Returns the monitored resource type. For example, the type {@code cloudsql_database} represents
+ * databases in Google Cloud SQL.
+ */
+ public String type() {
+ return type;
+ }
+
+ /**
+ * Returns an optional name for the monitored resource descriptor. If not set, this method returns
+ * {@code null}.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns an optional concise name for the monitored resource type. This value might be displayed
+ * in user interfaces. For example, {@code Google Cloud SQL Database}. If not set, this method
+ * returns {@code null}.
+ */
+ public String displayName() {
+ return displayName;
+ }
+
+ /**
+ * Returns an optional detailed description of the monitored resource type. This value might be
+ * used in documentation. If not set, this method returns {@code null}.
+ */
+ public String description() {
+ return description;
+ }
+
+ /**
+ * Returns a list of labels used to describe instances of this monitored resource type. For
+ * example, an individual Google Cloud SQL database is identified by values for the labels
+ * {@code database_id} and {@code region}.
+ */
+ public List labels() {
+ return labels;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(type, name, displayName, description, labels);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !obj.getClass().equals(MonitoredResourceDescriptor.class)) {
+ return false;
+ }
+ MonitoredResourceDescriptor other = (MonitoredResourceDescriptor) obj;
+ return Objects.equals(type, other.type)
+ && Objects.equals(name, other.name)
+ && Objects.equals(displayName, other.displayName)
+ && Objects.equals(description, other.description)
+ && Objects.equals(labels, other.labels);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("type", type)
+ .add("name", name)
+ .add("displayName", displayName)
+ .add("description", description)
+ .add("labels", labels)
+ .toString();
+ }
+
+ public com.google.api.MonitoredResourceDescriptor toPb() {
+ com.google.api.MonitoredResourceDescriptor.Builder builder =
+ com.google.api.MonitoredResourceDescriptor.newBuilder()
+ .setType(type)
+ .addAllLabels(Iterables.transform(labels, LabelDescriptor.TO_PB_FUNCTION));
+ if (name != null) {
+ builder.setName(name);
+ }
+ if (displayName != null) {
+ builder.setDisplayName(displayName);
+ }
+ if (description != null) {
+ builder.setDescription(description);
+ }
+ return builder.build();
+ }
+
+ static Builder builder(String type) {
+ return new Builder(type);
+ }
+
+ public static MonitoredResourceDescriptor fromPb(
+ com.google.api.MonitoredResourceDescriptor descriptorPb) {
+ Builder builder = builder(descriptorPb.getType());
+ if (descriptorPb.getName() != null && !descriptorPb.getName().equals("")) {
+ builder.name(descriptorPb.getName());
+ }
+ if (descriptorPb.getDisplayName() != null && !descriptorPb.getDisplayName().equals("")) {
+ builder.displayName(descriptorPb.getDisplayName());
+ }
+ if (descriptorPb.getDescription() != null && !descriptorPb.getDescription().equals("")) {
+ builder.description(descriptorPb.getDescription());
+ }
+ builder.labels(Lists.transform(descriptorPb.getLabelsList(), LabelDescriptor.FROM_PB_FUNCTION));
+ return builder.build();
+ }
+}
diff --git a/gcloud-java-core/src/test/java/com/google/cloud/MonitoredResourceDescriptorTest.java b/gcloud-java-core/src/test/java/com/google/cloud/MonitoredResourceDescriptorTest.java
new file mode 100644
index 000000000000..cab0438e05d8
--- /dev/null
+++ b/gcloud-java-core/src/test/java/com/google/cloud/MonitoredResourceDescriptorTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.cloud;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.google.cloud.MonitoredResourceDescriptor.LabelDescriptor;
+import com.google.cloud.MonitoredResourceDescriptor.LabelDescriptor.ValueType;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class MonitoredResourceDescriptorTest {
+
+ private static final LabelDescriptor BOOLEAN_LABEL =
+ new LabelDescriptor("booleanKey", ValueType.BOOL, "Boolean label");
+ private static final LabelDescriptor STRING_LABEL =
+ new LabelDescriptor("stringKey", ValueType.STRING, "String label");
+ private static final LabelDescriptor INT_LABEL =
+ new LabelDescriptor("intKey", ValueType.INT64, "Int label");
+ private static final LabelDescriptor INT_LABEL_NO_DESCRIPTION =
+ new LabelDescriptor("intKey", ValueType.INT64, null);
+ private static final String TYPE = "resource_type";
+ private static final String NAME = "resourceName";
+ private static final String DISPLAY_NAME = "Display Name";
+ private static final String DESCRIPTION = "Resource Descriptor";
+ private static final List LABELS =
+ ImmutableList.of(BOOLEAN_LABEL, STRING_LABEL, INT_LABEL);
+ private static final MonitoredResourceDescriptor RESOURCE_DESCRIPTOR =
+ MonitoredResourceDescriptor.builder(TYPE)
+ .name(NAME)
+ .displayName(DISPLAY_NAME)
+ .description(DESCRIPTION)
+ .labels(LABELS)
+ .build();
+
+ @Test
+ public void testLabelDescriptor() {
+ assertEquals("booleanKey", BOOLEAN_LABEL.key());
+ assertEquals(ValueType.BOOL, BOOLEAN_LABEL.valueType());
+ assertEquals("Boolean label", BOOLEAN_LABEL.description());
+ assertEquals("stringKey", STRING_LABEL.key());
+ assertEquals(ValueType.STRING, STRING_LABEL.valueType());
+ assertEquals("String label", STRING_LABEL.description());
+ assertEquals("intKey", INT_LABEL.key());
+ assertEquals(ValueType.INT64, INT_LABEL.valueType());
+ assertEquals("Int label", INT_LABEL.description());
+ assertEquals("intKey", INT_LABEL_NO_DESCRIPTION.key());
+ assertEquals(ValueType.INT64, INT_LABEL_NO_DESCRIPTION.valueType());
+ assertNull(INT_LABEL_NO_DESCRIPTION.description());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals(TYPE, RESOURCE_DESCRIPTOR.type());
+ assertEquals(NAME, RESOURCE_DESCRIPTOR.name());
+ assertEquals(DISPLAY_NAME, RESOURCE_DESCRIPTOR.displayName());
+ assertEquals(DESCRIPTION, RESOURCE_DESCRIPTOR.description());
+ assertEquals(LABELS, RESOURCE_DESCRIPTOR.labels());
+ MonitoredResourceDescriptor resourceDescriptor =
+ MonitoredResourceDescriptor.builder(TYPE).build();
+ assertEquals(TYPE, resourceDescriptor.type());
+ assertNull(resourceDescriptor.name());
+ assertNull(resourceDescriptor.displayName());
+ assertNull(resourceDescriptor.description());
+ assertEquals(ImmutableList.of(), resourceDescriptor.labels());
+ }
+
+
+ @Test
+ public void testToAndFromPbLabelDescriptor() {
+ compareLabelDescriptor(BOOLEAN_LABEL, LabelDescriptor.fromPb(BOOLEAN_LABEL.toPb()));
+ compareLabelDescriptor(STRING_LABEL, LabelDescriptor.fromPb(STRING_LABEL.toPb()));
+ compareLabelDescriptor(INT_LABEL, LabelDescriptor.fromPb(INT_LABEL.toPb()));
+ compareLabelDescriptor(INT_LABEL_NO_DESCRIPTION,
+ LabelDescriptor.fromPb(INT_LABEL_NO_DESCRIPTION.toPb()));
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ compareResourceDescriptor(RESOURCE_DESCRIPTOR,
+ MonitoredResourceDescriptor.fromPb(RESOURCE_DESCRIPTOR.toPb()));
+ MonitoredResourceDescriptor resourceDescriptor =
+ MonitoredResourceDescriptor.builder(TYPE).build();
+ compareResourceDescriptor(resourceDescriptor,
+ MonitoredResourceDescriptor.fromPb(resourceDescriptor.toPb()));
+ }
+
+ private void compareLabelDescriptor(LabelDescriptor expected, LabelDescriptor value) {
+ assertEquals(expected, value);
+ assertEquals(expected.key(), value.key());
+ assertEquals(expected.valueType(), value.valueType());
+ assertEquals(expected.description(), value.description());
+ assertEquals(expected.hashCode(), value.hashCode());
+ assertEquals(expected.toString(), value.toString());
+ }
+
+ private void compareResourceDescriptor(MonitoredResourceDescriptor expected,
+ MonitoredResourceDescriptor value) {
+ assertEquals(expected, value);
+ assertEquals(expected.type(), value.type());
+ assertEquals(expected.name(), value.name());
+ assertEquals(expected.displayName(), value.displayName());
+ assertEquals(expected.description(), value.description());
+ assertEquals(expected.labels(), value.labels());
+ assertEquals(expected.hashCode(), value.hashCode());
+ assertEquals(expected.toString(), value.toString());
+ }
+}