diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatch.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatch.java index 88275db690..91de69af63 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatch.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatch.java @@ -36,18 +36,19 @@ public class CloudWatch { * List metrics based on the criteria in the {@link ListMetricsOptions} passed in. * * @param cloudWatchClient the CloudWatch client + * @param region the region to list metrics in * @param options the options describing the ListMetrics request * * @return iterable of metrics fitting the criteria */ public static Iterable listMetrics(final CloudWatchClient cloudWatchClient, - final ListMetricsOptions options) { + final String region, final ListMetricsOptions options) { return new Iterable() { public Iterator iterator() { return new AbstractIterator() { private ListMetricsOptions lastOptions = options; - private ListMetricsResponse response = cloudWatchClient.listMetrics(lastOptions); + private ListMetricsResponse response = cloudWatchClient.listMetrics(region, lastOptions); private Iterator iterator = response.getMetrics().iterator(); /** @@ -63,7 +64,7 @@ public class CloudWatch { .namespace(lastOptions.getNamespace()) .nextToken(response.getNextToken()) .build(); - response = cloudWatchClient.listMetrics(lastOptions); + response = cloudWatchClient.listMetrics(region, lastOptions); iterator = response.getMetrics().iterator(); } if (iterator.hasNext()) { diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchAsyncClient.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchAsyncClient.java index e2be54e122..c98e12873e 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchAsyncClient.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchAsyncClient.java @@ -21,12 +21,15 @@ package org.jclouds.cloudwatch; import com.google.common.util.concurrent.ListenableFuture; import org.jclouds.aws.filters.FormSigner; import org.jclouds.cloudwatch.domain.Datapoint; +import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse; import org.jclouds.cloudwatch.domain.ListMetricsResponse; import org.jclouds.cloudwatch.domain.Statistics; import org.jclouds.cloudwatch.functions.ISO8601Format; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; +import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2; import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandler; +import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandlerV2; import org.jclouds.cloudwatch.xml.ListMetricsResponseHandler; import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; @@ -60,6 +63,7 @@ public interface CloudWatchAsyncClient { /** * @see CloudWatchClient#getMetricStatisticsInRegion */ + @Deprecated @POST @Path("/") @XMLResponseParser(GetMetricStatisticsResponseHandler.class) @@ -75,12 +79,25 @@ public interface CloudWatchAsyncClient { GetMetricStatisticsOptions... options); /** - * @see CloudWatchClient#listMetrics(org.jclouds.cloudwatch.options.ListMetricsOptions) + * @see CloudWatchClient#listMetrics(String, org.jclouds.cloudwatch.options.ListMetricsOptions) */ @POST @Path("/") @XMLResponseParser(ListMetricsResponseHandler.class) @FormParams(keys = "Action", values = "ListMetrics") - ListenableFuture listMetrics(ListMetricsOptions options); + ListenableFuture listMetrics( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + ListMetricsOptions options); + + /** + * @see CloudWatchClient#getMetricStatistics(String, org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2) + */ + @POST + @Path("/") + @XMLResponseParser(GetMetricStatisticsResponseHandlerV2.class) + @FormParams(keys = "Action", values = "GetMetricStatistics") + ListenableFuture getMetricStatistics( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + GetMetricStatisticsOptionsV2 options); } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchClient.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchClient.java index 7a643510ca..cb3da3bb92 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchClient.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/CloudWatchClient.java @@ -19,9 +19,11 @@ package org.jclouds.cloudwatch; import org.jclouds.cloudwatch.domain.Datapoint; +import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse; import org.jclouds.cloudwatch.domain.ListMetricsResponse; import org.jclouds.cloudwatch.domain.Statistics; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; +import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2; import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.concurrent.Timeout; import org.jclouds.javax.annotation.Nullable; @@ -79,10 +81,10 @@ public interface CloudWatchClient { * @param options * more filtering options (e.g. instance ID) */ + @Deprecated Set getMetricStatisticsInRegion(@Nullable String region, String metricName, String namespace, Date startTime, Date endTime, int period, Statistics statistics, GetMetricStatisticsOptions... options); - /** * Returns a list of valid metrics stored for the AWS account owner. * @@ -90,12 +92,23 @@ public interface CloudWatchClient { *

Note

Up to 500 results are returned for any one call. To retrieve further results, use returned * NextToken ({@link org.jclouds.cloudwatch.domain.ListMetricsResponse#getNextToken()}) * value with subsequent calls .To retrieve all available metrics with one call, use - * {@link CloudWatch#listMetrics(CloudWatchClient, org.jclouds.cloudwatch.options.ListMetricsOptions)}. + * {@link CloudWatch#listMetrics(CloudWatchClient, String, org.jclouds.cloudwatch.options.ListMetricsOptions)}. * + * @param region the region to query metrics in * @param options the options describing the metrics query * - * @return the list of valid metrics based on the AWS account owner and the options passed in + * @return the response object */ - ListMetricsResponse listMetrics(ListMetricsOptions options); + ListMetricsResponse listMetrics(@Nullable String region, ListMetricsOptions options); + + /** + * Gets statistics for the specified metric. + * + * @param region the region to gather metrics in + * @param options the options describing the metric statistics query + * + * @return the response object + */ + GetMetricStatisticsResponse getMetricStatistics(@Nullable String region, GetMetricStatisticsOptionsV2 options); } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Datapoint.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Datapoint.java index 9548321cb3..c9f0459d66 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Datapoint.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Datapoint.java @@ -18,10 +18,11 @@ */ package org.jclouds.cloudwatch.domain; -import java.util.Date; - +import com.google.common.base.Objects; import org.jclouds.javax.annotation.Nullable; +import java.util.Date; + /** * @see @@ -118,17 +119,7 @@ public class Datapoint { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((average == null) ? 0 : average.hashCode()); - result = prime * result + ((customUnit == null) ? 0 : customUnit.hashCode()); - result = prime * result + ((maximum == null) ? 0 : maximum.hashCode()); - result = prime * result + ((minimum == null) ? 0 : minimum.hashCode()); - result = prime * result + ((samples == null) ? 0 : samples.hashCode()); - result = prime * result + ((sum == null) ? 0 : sum.hashCode()); - result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode()); - result = prime * result + ((unit == null) ? 0 : unit.hashCode()); - return result; + return Objects.hashCode(average, customUnit, maximum, minimum, samples, sum, timestamp, unit); } @Override @@ -140,53 +131,27 @@ public class Datapoint { if (getClass() != obj.getClass()) return false; Datapoint other = (Datapoint) obj; - if (average == null) { - if (other.average != null) - return false; - } else if (!average.equals(other.average)) - return false; - if (customUnit == null) { - if (other.customUnit != null) - return false; - } else if (!customUnit.equals(other.customUnit)) - return false; - if (maximum == null) { - if (other.maximum != null) - return false; - } else if (!maximum.equals(other.maximum)) - return false; - if (minimum == null) { - if (other.minimum != null) - return false; - } else if (!minimum.equals(other.minimum)) - return false; - if (samples == null) { - if (other.samples != null) - return false; - } else if (!samples.equals(other.samples)) - return false; - if (sum == null) { - if (other.sum != null) - return false; - } else if (!sum.equals(other.sum)) - return false; - if (timestamp == null) { - if (other.timestamp != null) - return false; - } else if (!timestamp.equals(other.timestamp)) - return false; - if (unit == null) { - if (other.unit != null) - return false; - } else if (!unit.equals(other.unit)) - return false; - return true; + return Objects.equal(this.average, other.average) && + Objects.equal(this.customUnit, other.customUnit) && + Objects.equal(this.maximum, other.maximum) && + Objects.equal(this.minimum, other.minimum) && + Objects.equal(this.samples, other.samples) && + Objects.equal(this.sum, other.sum) && + Objects.equal(this.timestamp, other.timestamp) && + Objects.equal(this.unit, other.unit); } @Override public String toString() { - return "[average=" + average + ", customUnit=" + customUnit + ", maximum=" + maximum + ", minimum=" + minimum - + ", samples=" + samples + ", sum=" + sum + ", timestamp=" + timestamp + ", unit=" + unit + "]"; + return Objects.toStringHelper(this) + .add("timestamp", timestamp) + .add("customUnit", customUnit) + .add("maximum", maximum) + .add("minimum", minimum) + .add("average", average) + .add("sum", sum) + .add("samples", samples) + .add("unit", unit).toString(); } } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Dimension.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Dimension.java index 45514cbd89..6fe8228c84 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Dimension.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Dimension.java @@ -18,6 +18,8 @@ */ package org.jclouds.cloudwatch.domain; +import com.google.common.base.Objects; + /** * @see * @@ -47,6 +49,14 @@ public class Dimension { return value; } + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(name, value); + } + /** * {@inheritDoc} */ @@ -59,17 +69,8 @@ public class Dimension { if (getClass() != obj.getClass()) return false; Dimension other = (Dimension)obj; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - if (value == null) { - if (other.value != null) - return false; - } else if (!value.equals(other.value)) - return false; - return true; + return Objects.equal(this.name, other.name) && + Objects.equal(this.value, other.value); } /** @@ -77,7 +78,9 @@ public class Dimension { */ @Override public String toString() { - return "[name=" + name + ", value=" + value + "]"; + return Objects.toStringHelper(this) + .add("name", name) + .add("value", value).toString(); } } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java new file mode 100644 index 0000000000..35c195f0f8 --- /dev/null +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java @@ -0,0 +1,94 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudwatch.domain; + +import com.google.common.base.Objects; +import com.google.common.collect.Sets; +import org.jclouds.javax.annotation.Nullable; + +import java.util.Set; + +/** + * @see + * + * @author Jeremy Whitlock + */ +public class GetMetricStatisticsResponse { + + private final Set datapoints; + private final String label; + + public GetMetricStatisticsResponse(@Nullable Set datapoints, String label) { + if (datapoints == null) { + this.datapoints = Sets.newLinkedHashSet(); + } else { + this.datapoints = datapoints; + } + this.label = label; + } + + /** + * return the list of {@link Datapoint} for the metric + */ + public Set getDatapoints() { + return datapoints; + } + + /** + * return the label describing the specified metric + */ + public String getLabel() { + return label; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(datapoints, label); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + GetMetricStatisticsResponse other = (GetMetricStatisticsResponse)obj; + return Objects.equal(this.datapoints, other.datapoints) && + Objects.equal(this.label, other.label); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("label", label) + .add("datapoints", datapoints).toString(); + } + +} diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/ListMetricsResponse.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/ListMetricsResponse.java index ed74019d34..7411f46a7e 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/ListMetricsResponse.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/ListMetricsResponse.java @@ -18,10 +18,10 @@ */ package org.jclouds.cloudwatch.domain; +import com.google.common.base.Objects; import com.google.common.collect.Sets; import org.jclouds.javax.annotation.Nullable; -import java.util.Iterator; import java.util.Set; /** @@ -34,7 +34,7 @@ public class ListMetricsResponse { private final Set metrics; private final String nextToken; - public ListMetricsResponse(Set metrics, String nextToken) { + public ListMetricsResponse(@Nullable Set metrics, @Nullable String nextToken) { // Default to an empty set if (metrics == null) { this.metrics = Sets.newLinkedHashSet(); @@ -63,6 +63,14 @@ public class ListMetricsResponse { * {@inheritDoc} */ @Override + public int hashCode() { + return Objects.hashCode(metrics, nextToken); + } + + /** + * {@inheritDoc} + */ + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -71,17 +79,8 @@ public class ListMetricsResponse { if (getClass() != obj.getClass()) return false; ListMetricsResponse other = (ListMetricsResponse)obj; - if (metrics == null) { - if (other.metrics != null) - return false; - } else if (!metrics.equals(other.metrics)) - return false; - if (nextToken == null) { - if (other.nextToken != null) - return false; - } else if (!nextToken.equals(other.nextToken)) - return false; - return true; + return Objects.equal(this.metrics, other.metrics) && + Objects.equal(this.nextToken, other.nextToken); } /** @@ -89,27 +88,9 @@ public class ListMetricsResponse { */ @Override public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append("[metrics=["); - - Iterator iterator = metrics.iterator(); - - while (iterator.hasNext()) { - builder.append(iterator.next()); - - if (iterator.hasNext()) { - builder.append(", "); - } - } - - builder.append("]"); - - builder.append(", nextToken=") - .append(nextToken) - .append("]"); - - return builder.toString(); + return Objects.toStringHelper(this) + .add("metrics", metrics) + .add("nextToken", nextToken).toString(); } } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Metric.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Metric.java index 7c6fbaf343..1a4f79d282 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Metric.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/Metric.java @@ -18,10 +18,10 @@ */ package org.jclouds.cloudwatch.domain; +import com.google.common.base.Objects; import com.google.common.collect.Sets; import org.jclouds.javax.annotation.Nullable; -import java.util.Iterator; import java.util.Set; /** @@ -73,33 +73,11 @@ public class Metric { * {@inheritDoc} */ @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append("[metricName=") - .append(metricName) - .append(", namespace=") - .append(namespace); - - - builder.append(", dimensions=["); - - Iterator iterator = dimensions.iterator(); - - while (iterator.hasNext()) { - builder.append(iterator.next()); - - if (iterator.hasNext()) { - builder.append(", "); - } - } - - builder.append("]]"); - - return builder.toString(); + public int hashCode() { + return Objects.hashCode(dimensions, metricName, namespace); } - /** + /** * {@inheritDoc} */ @Override @@ -111,22 +89,20 @@ public class Metric { if (getClass() != obj.getClass()) return false; Metric other = (Metric)obj; - if (metricName == null) { - if (other.metricName != null) - return false; - } else if (!metricName.equals(other.metricName)) - return false; - if (namespace == null) { - if (other.namespace != null) - return false; - } else if (!namespace.equals(other.namespace)) - return false; - if (dimensions == null) { - if (other.dimensions != null) - return false; - } else if (!dimensions.equals(other.dimensions)) - return false; - return true; + return Objects.equal(this.dimensions, other.dimensions) && + Objects.equal(this.metricName, other.metricName) && + Objects.equal(this.namespace, other.namespace); } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("namespace", namespace) + .add("metricName", metricName) + .add("dimension", dimensions).toString(); + } + } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptions.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptions.java index 62eb050733..7a3c5de87a 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptions.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptions.java @@ -18,12 +18,12 @@ */ package org.jclouds.cloudwatch.options; -import static com.google.common.base.Preconditions.checkNotNull; - import org.jclouds.aws.util.AWSUtils; import org.jclouds.cloudwatch.domain.Unit; import org.jclouds.http.options.BaseHttpRequestOptions; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Options used to control metric statistics are returned * @@ -32,6 +32,7 @@ import org.jclouds.http.options.BaseHttpRequestOptions; * /> * @author Andrei Savu */ +@Deprecated public class GetMetricStatisticsOptions extends BaseHttpRequestOptions { public static final GetMetricStatisticsOptions NONE = new GetMetricStatisticsOptions(); @@ -73,5 +74,7 @@ public class GetMetricStatisticsOptions extends BaseHttpRequestOptions { GetMetricStatisticsOptions options = new GetMetricStatisticsOptions(); return options.unit(unit); } + } + } diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptionsV2.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptionsV2.java new file mode 100644 index 0000000000..602b0d3e37 --- /dev/null +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/GetMetricStatisticsOptionsV2.java @@ -0,0 +1,373 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudwatch.options; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; +import org.jclouds.cloudwatch.domain.Dimension; +import org.jclouds.cloudwatch.domain.Statistics; +import org.jclouds.cloudwatch.domain.Unit; +import org.jclouds.date.DateService; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.http.options.BaseHttpRequestOptions; +import org.jclouds.javax.annotation.Nullable; + +import java.util.Date; +import java.util.Set; + +/** + * Options use to get statistics for the specified metric. + * + * @see + * + * @author Jeremy Whitlock + */ +@Beta +public class GetMetricStatisticsOptionsV2 extends BaseHttpRequestOptions { + + private static final DateService dateService = new SimpleDateFormatDateService(); + private final Set dimensions; + private final Date endTime; + private final String metricName; + private final String namespace; + private final int period; + private final Date startTime; + private final Set statistics; + private final Unit unit; + + /** + * Private constructor to enforce using {@link Builder}. + */ + private GetMetricStatisticsOptionsV2(@Nullable Set dimensions, Date endTime, String metricName, + String namespace, int period, Date startTime, Set statistics, + Unit unit) { + this.dimensions = dimensions; + this.endTime = endTime; + this.metricName = metricName; + this.namespace = namespace; + this.period = period; + this.startTime = startTime; + this.statistics = statistics; + this.unit = unit; + } + + /** + * return the set of dimensions for this request + */ + @Nullable + public Set getDimensions() { + return dimensions; + } + + /** + * return the end time for this request + */ + public Date getEndTime() { + return endTime; + } + + /** + * return the metric name for this request + */ + public String getMetricName() { + return metricName; + } + + /** + * return the namespace for this request + */ + public String getNamespace() { + return namespace; + } + + /** + * return the period for this request + */ + public int getPeriod() { + return period; + } + + /** + * return the start time for this request + */ + public Date getStartTime() { + return startTime; + } + + /** + * return the statistics for this request + */ + public Set getStatistics() { + return statistics; + } + + /** + * return the unit for this request + */ + public Unit getUnit() { + return unit; + } + + /** + * Returns a new builder. The generated builder is equivalent to the builder + * created by the {@link Builder} constructor. + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Set dimensions = Sets.newLinkedHashSet(); + private Date endTime; + private String metricName; + private String namespace; + private int period; + private Date startTime; + private Set statistics = Sets.newLinkedHashSet(); + private Unit unit; + + /** + * Creates a new builder. The returned builder is equivalent to the builder + * generated by {@link ListMetricsOptions#builder}. + */ + public Builder() {} + + /** + * A list of dimensions describing qualities of the metric. (Set can be 10 or less items.) + * + * @param dimensions the dimensions describing the qualities of the metric + * + * @return this {@code Builder} object + * + * @throws IllegalArgumentException if this is invoked more than 10 times + */ + public Builder dimensions(Set dimensions) { + if (dimensions != null) { + Preconditions.checkArgument(dimensions.size() <= 10, "dimensions can have 10 or fewer members."); + this.dimensions = dimensions; + } + return this; + } + + /** + * A dimension describing qualities of the metric. (Can be called multiple times up to a maximum of 10 times.) + * + * @param dimension the dimension describing the qualities of the metric + * + * @return this {@code Builder} object + * + * @throws IllegalArgumentException if the number of dimensions would be greater than 10 after adding + */ + public Builder dimension(Dimension dimension) { + if (dimension != null) { + Preconditions.checkArgument(dimensions.size() < 10, "dimension member maximum count of 10 exceeded."); + this.dimensions.add(dimension); + } + return this; + } + + /** + * The time stamp to use for determining the last datapoint to return. The value specified is exclusive so + * results will include datapoints up to the time stamp specified. (Should be called once. Subsequent calls + * will overwrite the previous value.) + * + * @param endTime the timestamp to use for determining the last datapoint to return + * + * @return this {@code Builder} object + * + * @throws NullPointerException if endTime is null + */ + public Builder endTime(Date endTime) { + Preconditions.checkNotNull(endTime, "endTime cannot be null."); + this.endTime = endTime; + return this; + } + + /** + * The name of the metric. (Should be called once. Subsequent calls will overwrite the previous value.) + * + * @param metricName the metric name to filter against + * + * @return this {@code Builder} object + * + * @throws NullPointerException if metricName is null + * @throws IllegalArgumentException if metricName is empty + */ + public Builder metricName(String metricName) { + Preconditions.checkNotNull(metricName, "metricName cannot be null."); + Preconditions.checkArgument(metricName.length() > 1, "metricName must not be empty."); + this.metricName = metricName; + return this; + } + + /** + * The namespace of the metric. (Should be called once. Subsequent calls will overwrite the previous value. + * See {@link org.jclouds.cloudwatch.domain.Namespaces} for the known list of namespaces.) + * + * @param namespace the namespace to filter against + * + * @return this {@code Builder} object + * + * @throws NullPointerException if namespace is null + * @throws IllegalArgumentException if namespace is empty + */ + public Builder namespace(String namespace) { + Preconditions.checkNotNull(namespace, "namespace cannot be null."); + Preconditions.checkArgument(namespace.length() > 1, "namespace must not be empty."); + this.namespace = namespace; + return this; + } + + /** + * The granularity, in seconds, of the returned datapoints. Period must be at least 60 seconds and must be a + * multiple of 60. The default value is 60. (Should be called once. Subsequent calls will overwrite the + * previous value.) + * + * @param period the granularity, in seconds, of the returned datapoints + * + * @return this {@code Builder} object + * + * @throws NullPointerException if period is null + * @throws IllegalArgumentException if period is less than 60 or not a multiple of 60 + */ + public Builder period(int period) { + Preconditions.checkNotNull(period, "period cannot be null."); + Preconditions.checkArgument(period >= 60 && period % 60 == 0, "period must be greater than 60 and as a " + + "multiple of 60."); + this.period = period; + return this; + } + + /** + * The time stamp to use for determining the first datapoint to return. The value specified is inclusive so + * results include datapoints with the time stamp specified. (Should be called once. Subsequent calls will + * overwrite the previous value.) + * + * @param startTime The time stamp to use for determining the first datapoint to return + * + * @return this {@code Builder} object + * + * @throws NullPointerException if startTime is null + */ + public Builder startTime(Date startTime) { + Preconditions.checkNotNull(startTime, "startTime cannot be null."); + this.startTime = startTime; + return this; + } + + /** + * The metric statistics to return. (Should be called once. Subsequent calls will overwrite the previous + * value.) + * + * @param statistics the metric statistics to return. + * + * @return this {@code Builder} object + * + * @throws IllegalArgumentException if the number of statistics is greater than 5 + * @throws NullPointerException if statistics is null + */ + public Builder statistics(Set statistics) { + Preconditions.checkNotNull(statistics, "statistics cannot be null."); + Preconditions.checkArgument(statistics.size() <= 5, "statistics can have 5 or fewer members."); + this.statistics = statistics; + return this; + } + + /** + * The metric statistic to return. (Can be called multiple times up to a maximum of 5 times.) + * + * @param statistic the metric statistic to return + * + * @return this {@code Builder} object + * + * @throws IllegalArgumentException if the number of statistics would be greater than 5 after adding + * @throws NullPointerException if statistic is null + */ + public Builder statistic(Statistics statistic) { + Preconditions.checkNotNull(statistic, "statistic cannot be null."); + Preconditions.checkArgument(statistics.size() < 5, "statistics member maximum count of 5 exceeded."); + this.statistics.add(statistic); + return this; + } + + /** + * The unit for the metric. (Should be called once. Subsequent calls will overwrite the previous value.) + * + * @param unit the unit for the metric + * + * @return this {@code Builder} object + * + * @throws NullPointerException if unit is null + */ + public Builder unit(Unit unit) { + Preconditions.checkNotNull(unit, "unit cannot be null."); + this.unit = unit; + return this; + } + + /** + * Returns a newly-created {@code GetMetricStatisticsOptionsV2} based on the contents of + * the {@code Builder}. + * + * @throws NullPointerException if any of the required fields are null + * @throws IllegalArgumentException if any of the provided fields don't meet required criteria + */ + public GetMetricStatisticsOptionsV2 build() { + Preconditions.checkNotNull(endTime, "endTime cannot be null."); + Preconditions.checkNotNull(metricName, "metricName cannot be null."); + Preconditions.checkNotNull(namespace, "namespace cannot be null."); + Preconditions.checkNotNull(period, "period cannot be null."); + Preconditions.checkNotNull(startTime, "startTime cannot be null."); + Preconditions.checkNotNull(statistics, "statistics cannot be null."); + Preconditions.checkNotNull(unit, "unit cannot be null."); + Preconditions.checkArgument(statistics.size() >= 1, "statistics must have at least one member"); + + GetMetricStatisticsOptionsV2 options = new GetMetricStatisticsOptionsV2(dimensions, endTime, metricName, + namespace, period, startTime, + statistics, unit); + int dimensionIndex = 1; + int statisticIndex = 1; + + for (Dimension dimension : dimensions) { + options.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName()); + options.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue()); + dimensionIndex++; + } + + options.formParameters.put("EndTime", dateService.iso8601SecondsDateFormat(endTime)); + options.formParameters.put("MetricName", metricName); + options.formParameters.put("Namespace", namespace); + options.formParameters.put("Period", Integer.toString(period)); + options.formParameters.put("StartTime", dateService.iso8601SecondsDateFormat(startTime)); + + for (Statistics statistic : statistics) { + options.formParameters.put("Statistics.member." + statisticIndex, statistic.toString()); + statisticIndex++; + } + + options.formParameters.put("Unit", unit.toString()); + + return options; + } + + } + +} diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/ListMetricsOptions.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/ListMetricsOptions.java index 1c2c7df580..ee4b024410 100644 --- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/ListMetricsOptions.java +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/options/ListMetricsOptions.java @@ -18,11 +18,12 @@ */ package org.jclouds.cloudwatch.options; +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; import org.jclouds.cloudwatch.domain.Dimension; import org.jclouds.http.options.BaseHttpRequestOptions; import org.jclouds.javax.annotation.Nullable; -import java.util.LinkedHashSet; import java.util.Set; /** @@ -92,7 +93,7 @@ public class ListMetricsOptions extends BaseHttpRequestOptions { public static class Builder { - private Set dimensions = new LinkedHashSet(); + private Set dimensions = Sets.newLinkedHashSet(); private String metricName; private String namespace; private String nextToken; @@ -104,58 +105,62 @@ public class ListMetricsOptions extends BaseHttpRequestOptions { public Builder() {} /** - * Filter available metrics specific to the namespace provided. To get all metrics regardless of the namespace, - * do not use this builder option. Only one namespace can be specified at a time so multiple invocations of - * this will just overwrite what was set prior. Available AWS namespaces are listed in the - * {@link org.jclouds.cloudwatch.domain.Namespaces} class. You can also use custom namespaces if you've - * configured CloudWatch for such things. + * The namespace to filter against. (Should be called once. Subsequent calls will overwrite the previous value. + * See {@link org.jclouds.cloudwatch.domain.Namespaces} for the known list of namespaces.) * - * @param namespace the namespace to filter the returned metrics by + * @param namespace the namespace to filter against * * @return this {@code Builder} object + * + * @throws IllegalArgumentException if namespace is empty */ public Builder namespace(String namespace) { + if (namespace != null) { + Preconditions.checkArgument(namespace.length() > 1, "namespace must not be empty."); + } this.namespace = namespace; return this; } /** - * Filter available metrics specific to the provided metric name. To get all metrics regardless of the metric - * name, do not use this builder option. Only one namespace can be specified at a time so multiple invocations - * of this will just overwrite what was set prior. Available AWS metric names are listed in the - * org.jclouds.cloudwatch.domain.*Constants classes and are AWS product specific. You can also use custom - * metric names if you've configured CloudWatch for such things. + * The name of the metric to filter against. (Should be called once. Subsequent calls will overwrite the + * previous value.) * - * @param metricName the metric name to filter the returned metrics by + * @param metricName the metric name to filter against * * @return this {@code Builder} object + * + * @throws IllegalArgumentException if metricName is empty */ public Builder metricName(String metricName) { + if (metricName != null) { + Preconditions.checkArgument(metricName.length() > 1, "metricName must not be empty."); + } this.metricName = metricName; return this; } /** - * Same as {@link #dimension(org.jclouds.cloudwatch.domain.Dimension)} but replaces the current set of - * dimensions with the one passed in. + * A list of dimensions to filter against. (Set can be 10 or less items.) * - * @see #dimension(org.jclouds.cloudwatch.domain.Dimension) + * @param dimensions the dimensions to filter against + * + * @return this {@code Builder} object + * + * @throws IllegalArgumentException if the number of dimensions would be greater than 10 after adding */ public Builder dimensions(Set dimensions) { - if (dimensions.size() > 10) { - throw new IllegalArgumentException("The maximum number of dimensions for ListOptions is 10."); + if (dimensions != null) { + Preconditions.checkArgument(dimensions.size() <= 10, "dimensions can have 10 or fewer members."); + this.dimensions = dimensions; } - this.dimensions = dimensions; return this; } /** - * Filter available metrics based on the {@link Dimension} passed in. To get all metrics regardless of the - * dimension, do not use this builder option. You can specify up to 10 different dimensions per request. - * Available AWS dimensions are listed in the org.jclouds.cloudwatch.domain.*Constants classes and are AWS - * product specific. You can also use custom dimensions if you've configured CloudWatch for such things. + * A dimension to filter the available metrics by. (Can be called multiple times up to a maximum of 10 times.) * - * @param dimension the dimension to filter the returned metrics by + * @param dimension a dimension to filter the returned metrics by * * @return this {@code Builder} object * @@ -163,19 +168,16 @@ public class ListMetricsOptions extends BaseHttpRequestOptions { */ public Builder dimension(Dimension dimension) { if (dimension != null) { - if (this.dimensions.size() >= 10) { - throw new IllegalArgumentException("You have exceeded the maximum number of dimensions per " + - "request."); - } + Preconditions.checkArgument(dimensions.size() < 10, "dimension member maximum count of 10 exceeded."); this.dimensions.add(dimension); } return this; } /** - * Specify that this request is a follow-up to retrieve more data from a paginated request. + * The token returned by a previous call to indicate that there is more data available. * - * @param nextToken the next token + * @param nextToken the next token indicating that there is more data available * * @return this {@code Builder} object */ @@ -192,22 +194,22 @@ public class ListMetricsOptions extends BaseHttpRequestOptions { ListMetricsOptions lmo = new ListMetricsOptions(namespace, metricName, dimensions, nextToken); int dimensionIndex = 1; - if (this.namespace != null) { - lmo.formParameters.put("Namespace", this.namespace); + if (namespace != null) { + lmo.formParameters.put("Namespace", namespace); } - if (this.metricName != null) { - lmo.formParameters.put("MetricName", this.metricName); + if (metricName != null) { + lmo.formParameters.put("MetricName", metricName); } - for (Dimension dimension : this.dimensions) { + for (Dimension dimension : dimensions) { lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName()); lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue()); dimensionIndex++; } - if (this.nextToken != null) { - lmo.formParameters.put("NextToken", this.nextToken); + if (nextToken != null) { + lmo.formParameters.put("NextToken", nextToken); } return lmo; diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/xml/GetMetricStatisticsResponseHandlerV2.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/xml/GetMetricStatisticsResponseHandlerV2.java new file mode 100644 index 0000000000..bf3e71b60d --- /dev/null +++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/xml/GetMetricStatisticsResponseHandlerV2.java @@ -0,0 +1,90 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudwatch.xml; + +import com.google.common.collect.Sets; +import org.jclouds.cloudwatch.domain.Datapoint; +import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.util.SaxUtils; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +import javax.inject.Inject; +import java.util.Set; + +/** + * @see + * + * @author Jeremy Whitlock + */ +public class GetMetricStatisticsResponseHandlerV2 extends ParseSax.HandlerWithResult { + + private StringBuilder currentText = new StringBuilder(); + private Set datapoints = Sets.newLinkedHashSet(); + private String label; + private final DatapointHandler datapointHandler; + private boolean inDatapoints; + + @Inject + public GetMetricStatisticsResponseHandlerV2(DatapointHandler DatapointHandler) { + this.datapointHandler = DatapointHandler; + } + + public GetMetricStatisticsResponse getResult() { + return new GetMetricStatisticsResponse(datapoints, label); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if (qName.equals("Datapoints")) { + inDatapoints = true; + } + if (inDatapoints) { + datapointHandler.startElement(uri, localName, qName, attributes); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (inDatapoints) { + if (qName.equals("Datapoints")) { + inDatapoints = false; + } else { + datapointHandler.endElement(uri, localName, qName); + if (qName.equals("member")) { + this.datapoints.add(datapointHandler.getResult()); + } + } + } else if (qName.equals("Label")) { + label = SaxUtils.currentOrNull(currentText); + } + + currentText = new StringBuilder(); + } + + public void characters(char ch[], int start, int length) { + if (inDatapoints) { + datapointHandler.characters(ch, start, length); + } else { + currentText.append(ch, start, length); + } + } + +} diff --git a/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/CloudWatchAsyncClientTest.java b/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/CloudWatchAsyncClientTest.java index 22c820464f..a79ce1a9bd 100644 --- a/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/CloudWatchAsyncClientTest.java +++ b/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/CloudWatchAsyncClientTest.java @@ -31,7 +31,9 @@ import org.jclouds.cloudwatch.domain.Dimension; import org.jclouds.cloudwatch.domain.EC2Constants; import org.jclouds.cloudwatch.domain.Namespaces; import org.jclouds.cloudwatch.domain.Statistics; +import org.jclouds.cloudwatch.domain.Unit; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; +import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2; import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandler; import org.jclouds.date.DateService; @@ -67,17 +69,71 @@ import static org.testng.Assert.assertEquals; public class CloudWatchAsyncClientTest extends BaseAsyncClientTest { /** - * Tests that {@link CloudWatchAsyncClient#listMetrics(org.jclouds.cloudwatch.options.ListMetricsOptions)} works + * Tests that {@link CloudWatchAsyncClient#getMetricStatistics(String, org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2)} + * works as expected. + * + * @throws Exception if anything goes wrong + */ + public void testGetMetricStatisticsV2() throws Exception { + Dimension dimension1 = new Dimension(EC2Constants.Dimension.INSTANCE_ID, "SOMEINSTANCEID"); + Dimension dimension2 = new Dimension(EC2Constants.Dimension.INSTANCE_TYPE, "t1.micro"); + Date endTime = new Date(10000000l); + String metricName = EC2Constants.MetricName.CPU_UTILIZATION; + String namespace = Namespaces.EC2; + int period = 60; + Date startTime = new Date(10000000l); + Statistics statistic1 = Statistics.MAXIMUM; + Statistics statistic2 = Statistics.MINIMUM; + Unit unit = Unit.PERCENT; + + GetMetricStatisticsOptionsV2 goodOptions = GetMetricStatisticsOptionsV2.builder() + .dimension(dimension1) + .dimension(dimension2) + .endTime(endTime) + .metricName(metricName) + .namespace(namespace) + .period(period) + .startTime(startTime) + .statistic(statistic1) + .statistic(statistic2) + .unit(unit).build(); + Method method = CloudWatchAsyncClient.class.getMethod("getMetricStatistics", String.class, + GetMetricStatisticsOptionsV2.class); + HttpRequest request = processor.createRequest(method, null, goodOptions); + + assertRequestLineEquals(request, "POST https://monitoring.us-east-1.amazonaws.com/ HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Host: monitoring.us-east-1.amazonaws.com\n"); + + // Note: Order of request params is alphabetical + assertPayloadEquals(request, + "Action=GetMetricStatistics" + + "&Dimensions.member.1.Name=" + dimension1.getName() + + "&Dimensions.member.1.Value=" + dimension1.getValue() + + "&Dimensions.member.2.Name=" + dimension2.getName() + + "&Dimensions.member.2.Value=" + dimension2.getValue() + + "&EndTime=1970-01-01T02%3A46%3A40Z" + + "&MetricName=" + metricName + + "&Namespace=" + URLEncoder.encode(namespace, "UTF-8") + + "&Period=" + period + + "&StartTime=1970-01-01T02%3A46%3A40Z" + + "&Statistics.member.1=" + statistic1 + + "&Statistics.member.2=" + statistic2 + + "&Unit=" + unit, + "application/x-www-form-urlencoded", false); + } + + /** + * Tests that {@link CloudWatchAsyncClient#listMetrics(String, org.jclouds.cloudwatch.options.ListMetricsOptions)} works * as expected. * * @throws Exception if anything goes wrong */ public void testListMetrics() throws Exception { - Method method = CloudWatchAsyncClient.class.getMethod("listMetrics", ListMetricsOptions.class); + Method method = CloudWatchAsyncClient.class.getMethod("listMetrics", String.class, ListMetricsOptions.class); HttpRequest request; // Test an empty request - request = processor.createRequest(method, ListMetricsOptions.builder().build()); + request = processor.createRequest(method, null, ListMetricsOptions.builder().build()); assertRequestLineEquals(request, "POST https://monitoring.us-east-1.amazonaws.com/ HTTP/1.1"); assertNonPayloadHeadersEqual(request, "Host: monitoring.us-east-1.amazonaws.com\n"); @@ -92,12 +148,12 @@ public class CloudWatchAsyncClientTest extends BaseAsyncClientTest 0) { + for (Metric metric : metricsResponse.getMetrics()) { + Set dimensions = metric.getDimensions(); + boolean testRan = false; + + for (Dimension dimension : dimensions) { + Date endTime = new Date(); + Calendar cal = Calendar.getInstance(); + + cal.add(Calendar.MINUTE, -60 * 24); // 24 hours + + GetMetricStatisticsOptionsV2 options = + GetMetricStatisticsOptionsV2.builder() + .dimension(dimension) + .endTime(endTime) + .metricName(metric.getMetricName()) + .namespace(metric.getNamespace()) + .period(300) + .startTime(cal.getTime()) + .statistics(ImmutableSet.of(Statistics.MAXIMUM, + Statistics.MINIMUM)) + .unit(Unit.PERCENT).build(); + GetMetricStatisticsResponse response = client.getMetricStatistics(null, options); + + if (response.getDatapoints().size() > 0) { + checkNotNull(response.getLabel()); + + for (Datapoint datapoint : response.getDatapoints()) { + checkArgument(datapoint.getAverage() == null); + checkNotNull(datapoint.getMaximum()); + checkNotNull(datapoint.getMinimum()); + } + + testRan = true; + break; + } + } + + if (testRan) { + break; + } + } + } + } + @Test protected void testListMetrics() { ListMetricsResponse response; @@ -70,7 +123,7 @@ public class CloudWatchClientLiveTest extends BaseContextLiveTest