/* * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. * * 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 monasca.api.app.command; import java.util.Arrays; import java.util.Map; import javax.annotation.Nullable; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.NotEmpty; import com.fasterxml.jackson.annotation.JsonProperty; import monasca.api.app.validation.DimensionValidation; import monasca.api.app.validation.MetricNameValidation; import com.hpcloud.mon.common.model.Services; import com.hpcloud.mon.common.model.metric.Metric; import monasca.api.resource.exception.Exceptions; public class CreateMetricCommand { private static final long TIME_2MIN = 120; private static final long TIME_2WEEKS = 1209600; private static final double VALUE_MIN = 8.515920e-109; private static final double VALUE_MAX = 1.174271e+108; @NotEmpty @Size(min = 1, max = 64) public String name; public Map dimensions; public long timestamp; public double value; public double[][] timeValues; public CreateMetricCommand() {} public CreateMetricCommand(String name, @Nullable Map dimensions, @Nullable Long timestamp, double value) { setName(name); setDimensions(dimensions); setTimestamp(timestamp); this.value = value; } public CreateMetricCommand(String name, @Nullable Map dimensions, @Nullable Long timestamp, double[][] timeValues) { setName(name); setDimensions(dimensions); setTimestamp(timestamp); this.timeValues = timeValues; } private static void validateTimestamp(long timestamp) { long time = System.currentTimeMillis() / 1000; if (timestamp > time + TIME_2MIN || timestamp < time - TIME_2WEEKS) throw Exceptions.unprocessableEntity("Timestamp %s is out of legal range", timestamp); } private static void validateValue(double value) { if (value < 0 || (value > 0 && (value < VALUE_MIN || value > VALUE_MAX))) throw Exceptions.unprocessableEntity("Value %s is out of legal range", value); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CreateMetricCommand other = (CreateMetricCommand) obj; if (dimensions == null) { if (other.dimensions != null) return false; } else if (!dimensions.equals(other.dimensions)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; // Note - Deep Equals is used here if (!Arrays.deepEquals(timeValues, other.timeValues)) return false; if (timestamp != other.timestamp) return false; if (Double.doubleToLongBits(value) != Double.doubleToLongBits(other.value)) return false; return true; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); // Note Deep hash code is used here result = prime * result + Arrays.deepHashCode(timeValues); result = prime * result + (int) (timestamp ^ (timestamp >>> 32)); long temp; temp = Double.doubleToLongBits(value); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @JsonProperty public void setDimensions(Map dimensions) { this.dimensions = dimensions == null || dimensions.isEmpty() ? null : DimensionValidation .normalize(dimensions); } @JsonProperty public void setName(String name) { this.name = MetricNameValidation.normalize(name); } @JsonProperty public void setTimestamp(Long timestamp) { this.timestamp = timestamp == null || timestamp.longValue() == 0L ? System.currentTimeMillis() / 1000L : timestamp.longValue(); } public Metric toMetric() { return timeValues == null || timeValues.length == 0 ? new Metric(name, dimensions, timestamp, value) : new Metric(name, dimensions, timestamp, timeValues); } public void validate() { // Validate name and dimensions if (dimensions != null) { String service = dimensions.get(Services.SERVICE_DIMENSION); MetricNameValidation.validate(name, service); DimensionValidation.validate(dimensions, service); } // Validate times and values validateTimestamp(timestamp); if (timeValues != null && timeValues.length > 0) { for (double[] timeValuePair : timeValues) { if (timeValuePair.length != 2) throw Exceptions.unprocessableEntity("All times_values must be timestamp / value pairs"); validateTimestamp((long) timeValuePair[0]); validateValue(timeValuePair[1]); } } else { validateValue(value); } } }