Time zone fix
- removed unused dependencies - matched joda to entire monasca - switched to standard java date + added explicit UTC Change-Id: I04e986097010792aed772e83e529edb6d88a2125
This commit is contained in:
parent
df99b11a40
commit
fc30e21e5c
@ -30,7 +30,7 @@ A change has been submitted to StackForge to switch to bare-trusty for this buil
|
||||
* [monasca-common-streaming](https://github.com/stackforge/monasca-common/tree/master/java/monasca-common-streaming) - Streaming related utilities.
|
||||
* [monasca-common-testing](https://github.com/stackforge/monasca-common/tree/master/java/monasca-common-testing) - A set of testing related dependencies.
|
||||
* [monasca-common-util](https://github.com/stackforge/monasca-common/tree/master/java/monasca-common-util) - Various utilities such as for serialization, dependency injection, date and time, invocation retries, concurrency, etc.
|
||||
|
||||
* [monasca-common-hibernate](https://github.com/stackforge/monasca-common/tree/master/java/monasca-common-hibernate) - Hibernate based model of Monasca SQL schema
|
||||
|
||||
python monasca-common
|
||||
======================
|
||||
|
@ -10,9 +10,7 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<hibernate-core.version>4.3.10.Final</hibernate-core.version>
|
||||
<usertype.core.version>3.2.0.GA</usertype.core.version>
|
||||
<joda-time.version>2.8.1</joda-time.version>
|
||||
<hibernate-core.version>5.0.1.Final</hibernate-core.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -20,27 +18,12 @@
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-model</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>${hibernate-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jadira.usertype</groupId>
|
||||
<artifactId>usertype.core</artifactId>
|
||||
<version>${usertype.core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda-time.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -16,7 +16,9 @@
|
||||
package monasca.common.hibernate.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Version;
|
||||
@ -24,43 +26,38 @@ import javax.persistence.Version;
|
||||
import com.google.common.base.Objects;
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import monasca.common.hibernate.core.AuditablePersistable;
|
||||
|
||||
/**
|
||||
* <b>Abstract</b> implementation for {@link AuditablePersistable}.
|
||||
*
|
||||
* Defines auditable information such as:
|
||||
* <ol>
|
||||
* <li>{@link #createdAt} - creation date for entity</li>
|
||||
* <li>{@link #updatedAt} - last update date for entity</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param <T> primary key type
|
||||
*
|
||||
* @see AbstractPersistable
|
||||
*/
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
@MappedSuperclass
|
||||
abstract class AbstractAuditablePersistable<T extends Serializable>
|
||||
extends AbstractPersistable<T>
|
||||
implements AuditablePersistable<T> {
|
||||
static final String DATE_TIME_TYPE = "org.jadira.usertype.dateandtime.joda.PersistentDateTime";
|
||||
static final String DB_ZONE = "UTC";
|
||||
static final String JAVA_ZONE = "jvm";
|
||||
private static final long serialVersionUID = 2335373173379564615L;
|
||||
|
||||
@Column(name = "created_at", nullable = false)
|
||||
@Type(
|
||||
type = DATE_TIME_TYPE,
|
||||
parameters = {
|
||||
@Parameter(name = "databaseZone", value = DB_ZONE),
|
||||
@Parameter(name = "javaZone", value = JAVA_ZONE)
|
||||
}
|
||||
)
|
||||
private DateTime createdAt;
|
||||
private Date createdAt;
|
||||
|
||||
@Version
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
@Type(
|
||||
type = DATE_TIME_TYPE,
|
||||
parameters = {
|
||||
@Parameter(name = "databaseZone", value = DB_ZONE),
|
||||
@Parameter(name = "javaZone", value = JAVA_ZONE)
|
||||
}
|
||||
)
|
||||
private DateTime updatedAt;
|
||||
private Date updatedAt;
|
||||
|
||||
AbstractAuditablePersistable() {
|
||||
this(null, null, null);
|
||||
@ -77,47 +74,79 @@ abstract class AbstractAuditablePersistable<T extends Serializable>
|
||||
this.setDates(createdAt, updatedAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method that transform {@link DateTime} into plain {@link java.util.Date}
|
||||
*
|
||||
* @param value DateTime instance
|
||||
*
|
||||
* @return plain Date
|
||||
*
|
||||
* @see #nullSafeGetDate(Date)
|
||||
*/
|
||||
static Date nullSafeSetDate(@Nullable final DateTime value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toDateTime(DateTimeZone.UTC).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method that transform {@link Date} into plain {@link DateTime}
|
||||
*
|
||||
* @param value Date instance
|
||||
*
|
||||
* @return DateTime
|
||||
*
|
||||
* @see #nullSafeSetDate(DateTime)
|
||||
*/
|
||||
static DateTime nullSafeGetDate(@Nullable final Date value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return new DateTime(value.getTime(), DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
return nullSafeGetDate(this.createdAt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuditablePersistable<T> setCreatedAt(DateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
this.createdAt = nullSafeSetDate(createdAt);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
return nullSafeGetDate(this.updatedAt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuditablePersistable<T> setUpdatedAt(DateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
this.updatedAt = nullSafeSetDate(updatedAt);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that both {@link #createdAt} and {@link #updatedAt} will be
|
||||
* set to the earliest possible value in case passssed values are {@code NULL}
|
||||
* set to the earliest possible value in case passed values are {@code NULL}
|
||||
*
|
||||
* @param createdAt created date
|
||||
* @param updatedAt updated date
|
||||
*/
|
||||
private void setDates(final DateTime createdAt,
|
||||
final DateTime updatedAt) {
|
||||
if (createdAt == null && updatedAt == null) {
|
||||
this.updatedAt = DateTime.now();
|
||||
this.createdAt = DateTime.now();
|
||||
} else if (createdAt == null) {
|
||||
this.createdAt = DateTime.now();
|
||||
} else if (updatedAt == null) {
|
||||
this.updatedAt = DateTime.now();
|
||||
final Date date = DateTime.now(DateTimeZone.UTC).toDate();
|
||||
if (createdAt == null) {
|
||||
this.createdAt = date;
|
||||
} else {
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
this.createdAt = createdAt.toDateTime(DateTimeZone.UTC).toDate();
|
||||
}
|
||||
if (updatedAt == null) {
|
||||
this.updatedAt = date;
|
||||
} else {
|
||||
this.updatedAt = updatedAt.toDateTime(DateTimeZone.UTC).toDate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,17 @@ import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import monasca.common.hibernate.core.Persistable;
|
||||
|
||||
/**
|
||||
* <b>Abstract</b> implementation for {@link Persistable}.
|
||||
*
|
||||
* Defines primary key of a specific entity.
|
||||
* Primary key may take any arbitrary type that
|
||||
* is required by specific case.
|
||||
*
|
||||
* @param <T> primary key type
|
||||
*
|
||||
* @see AbstractAuditablePersistable
|
||||
*/
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
@MappedSuperclass
|
||||
|
@ -15,6 +15,7 @@
|
||||
package monasca.common.hibernate.db;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.CascadeType;
|
||||
@ -35,8 +36,6 @@ import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
@ -76,14 +75,7 @@ public class AlarmDb
|
||||
private String link;
|
||||
|
||||
@Column(name = "state_updated_at")
|
||||
@Type(
|
||||
type = DATE_TIME_TYPE,
|
||||
parameters = {
|
||||
@Parameter(name = "databaseZone", value = DB_ZONE),
|
||||
@Parameter(name = "javaZone", value = JAVA_ZONE)
|
||||
}
|
||||
)
|
||||
private DateTime stateUpdatedAt;
|
||||
private Date stateUpdatedAt;
|
||||
|
||||
@OneToMany(mappedBy = "alarmMetricId.alarm", fetch = FetchType.LAZY, cascade = {
|
||||
CascadeType.PERSIST,
|
||||
@ -119,7 +111,7 @@ public class AlarmDb
|
||||
this.link = link;
|
||||
this.state = state;
|
||||
this.lifecycleState = lifecycleState;
|
||||
this.stateUpdatedAt = stateUpdatedAt;
|
||||
this.setStateUpdatedAt(stateUpdatedAt);
|
||||
}
|
||||
|
||||
public AlarmState getState() {
|
||||
@ -150,11 +142,11 @@ public class AlarmDb
|
||||
}
|
||||
|
||||
public DateTime getStateUpdatedAt() {
|
||||
return stateUpdatedAt;
|
||||
return nullSafeGetDate(this.stateUpdatedAt);
|
||||
}
|
||||
|
||||
public AlarmDb setStateUpdatedAt(DateTime stateUpdatedAt) {
|
||||
this.stateUpdatedAt = stateUpdatedAt;
|
||||
this.stateUpdatedAt = nullSafeSetDate(stateUpdatedAt);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ package monasca.common.hibernate.db;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Basic;
|
||||
@ -36,7 +37,6 @@ import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@ -95,14 +95,7 @@ public class AlarmDefinitionDb
|
||||
private boolean actionsEnabled = DEFAULT_ACTIONS_ENABLED;
|
||||
|
||||
@Column(name = "deleted_at")
|
||||
@Type(
|
||||
type = DATE_TIME_TYPE,
|
||||
parameters = {
|
||||
@Parameter(name = "databaseZone", value = DB_ZONE),
|
||||
@Parameter(name = "javaZone", value = JAVA_ZONE)
|
||||
}
|
||||
)
|
||||
private DateTime deletedAt;
|
||||
private Date deletedAt;
|
||||
|
||||
@BatchSize(size = 50)
|
||||
@OneToMany(mappedBy = "alarmDefinition", fetch = FetchType.LAZY)
|
||||
@ -132,7 +125,7 @@ public class AlarmDefinitionDb
|
||||
this.severity = severity;
|
||||
this.matchBy = matchBy;
|
||||
this.actionsEnabled = actionsEnabled;
|
||||
this.deletedAt = deletedAt;
|
||||
this.setDeletedAt(deletedAt);
|
||||
}
|
||||
|
||||
public AlarmDefinitionDb(String id,
|
||||
@ -145,7 +138,7 @@ public class AlarmDefinitionDb
|
||||
}
|
||||
|
||||
public AlarmDefinitionDb setDeletedAt(final DateTime deletedAt) {
|
||||
this.deletedAt = deletedAt;
|
||||
this.deletedAt = nullSafeSetDate(deletedAt);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -220,7 +213,7 @@ public class AlarmDefinitionDb
|
||||
}
|
||||
|
||||
public DateTime getDeletedAt() {
|
||||
return deletedAt;
|
||||
return nullSafeGetDate(this.deletedAt);
|
||||
}
|
||||
|
||||
public boolean hasAlarm(final AlarmDb alarm) {
|
||||
|
@ -24,11 +24,12 @@ import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import monasca.common.model.alarm.AlarmOperator;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import monasca.common.model.alarm.AlarmOperator;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sub_alarm_definition")
|
||||
@NamedQueries({
|
||||
|
@ -84,7 +84,7 @@
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>4.3.0.Final</version>
|
||||
<version>5.2.1.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
|
@ -16,7 +16,17 @@
|
||||
*/
|
||||
package monasca.common.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
public final class Conversions {
|
||||
private static final String[] SUPPORTED_VARIANT_TO_ENUM_TYPES = new String[]{
|
||||
String.class.getSimpleName(),
|
||||
Number.class.getSimpleName(),
|
||||
Enum.class.getSimpleName()
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Java Object of type Number to an Integer
|
||||
@ -32,4 +42,91 @@ public final class Conversions {
|
||||
variant.getClass(), variant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Java Object to DateTime instance
|
||||
*
|
||||
* @param variant object of type supported in {@link org.joda.time.convert.ConverterManager}
|
||||
*
|
||||
* @return DateTime in {@link DateTimeZone#UTC}
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* @see #variantToDateTime(Object, DateTimeZone)
|
||||
* @see DateTime
|
||||
* @see DateTimeZone#UTC
|
||||
*/
|
||||
public static DateTime variantToDateTime(final Object variant) {
|
||||
return variantToDateTime(variant, DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Java Object to DateTime instance using given {@code timeZone}
|
||||
*
|
||||
* @param variant object of type supported in {@link org.joda.time.convert.ConverterManager}
|
||||
* @param timeZone timeZone to be used
|
||||
*
|
||||
* @return DateTime in {@code timeZone}
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* @see #variantToDateTime(Object)
|
||||
* @see DateTime
|
||||
* @see DateTimeZone
|
||||
*/
|
||||
public static DateTime variantToDateTime(final Object variant, final DateTimeZone timeZone) {
|
||||
if (variant instanceof DateTime) {
|
||||
return ((DateTime) variant).toDateTime(timeZone);
|
||||
}
|
||||
return new DateTime(variant, timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts variant to {@code enumClazz} instance.
|
||||
*
|
||||
* Supported variants are:
|
||||
* <ol>
|
||||
* <li>{@link String}, trimmed and upper-cased</li>
|
||||
* <li>{@link Number}, taken from {@link Class#getEnumConstants}</li>
|
||||
* <li>{@link Enum}, simple cast</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param variant object of type supported by this method, see above
|
||||
* @param enumClazz desired {@link Enum}
|
||||
* @param <T> enumType of {@code enumClazz}
|
||||
*
|
||||
* @return valid enum class instance
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Enum<T>> T variantToEnum(final Object variant, final Class<T> enumClazz) {
|
||||
if (variant == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (variant instanceof String) {
|
||||
return Enum.valueOf(enumClazz, ((String) variant).trim().toUpperCase());
|
||||
} else if (variant instanceof Number) {
|
||||
final Integer index = variantToInteger(variant);
|
||||
final T[] enumConstants = enumClazz.getEnumConstants();
|
||||
if (index < 0 || index >= enumConstants.length) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Variant of type \"%s\", and value \"%s\" is out of range [, %d]",
|
||||
variant.getClass(),
|
||||
variant,
|
||||
enumConstants.length
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return enumConstants[index];
|
||||
} else if (variant instanceof Enum) {
|
||||
return (T) variant;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("\"%s\", and value \"%s\" is not one of %s",
|
||||
variant.getClass(), variant, Arrays.toString(SUPPORTED_VARIANT_TO_ENUM_TYPES)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,12 +14,15 @@
|
||||
package monasca.common.util;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Test
|
||||
public class ConversionsTest {
|
||||
public void testInteger() {
|
||||
@ -49,4 +52,63 @@ public class ConversionsTest {
|
||||
public void testObject() {
|
||||
Conversions.variantToInteger(new Object());
|
||||
}
|
||||
|
||||
public void testDateTimeShouldNotEqualDifferentTZExplicit() {
|
||||
final DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
assertNotEquals(now, Conversions.variantToDateTime(now, DateTimeZone.forOffsetHours(2)));
|
||||
}
|
||||
|
||||
public void testDateTimeShouldNotEqualDifferentTZImplicit() {
|
||||
final DateTime now = DateTime.now();
|
||||
assertNotEquals(now, Conversions.variantToDateTime(now));
|
||||
}
|
||||
|
||||
public void testDateTimeShouldEqualSameTZImplicit() {
|
||||
final DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
assertEquals(now, Conversions.variantToDateTime(now));
|
||||
}
|
||||
|
||||
public void testDateTimeShouldEqualSameTZExplicit() {
|
||||
final DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
assertEquals(now, Conversions.variantToDateTime(now, DateTimeZone.UTC));
|
||||
}
|
||||
|
||||
public void testEnumFromString() {
|
||||
assertEquals(MockEnum.THIS, Conversions.variantToEnum("THIS", MockEnum.class));
|
||||
}
|
||||
|
||||
public void testEnumFromStringLowerCased() {
|
||||
assertEquals(MockEnum.THIS, Conversions.variantToEnum("this", MockEnum.class));
|
||||
}
|
||||
|
||||
public void testEnumFromStringWithSpaces() {
|
||||
assertEquals(MockEnum.THIS, Conversions.variantToEnum(" THIS ", MockEnum.class));
|
||||
}
|
||||
|
||||
public void testEnumFromNumber() {
|
||||
assertEquals(MockEnum.IS, Conversions.variantToEnum(1, MockEnum.class));
|
||||
}
|
||||
|
||||
public void testEnumFromNumberDouble() {
|
||||
assertEquals(MockEnum.IS, Conversions.variantToEnum(1.0, MockEnum.class));
|
||||
}
|
||||
|
||||
public void testEnumFromEnum() {
|
||||
assertEquals(MockEnum.TEST, Conversions.variantToEnum(MockEnum.TEST, MockEnum.class));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testEnumShouldFailUnsupportedType(){
|
||||
Conversions.variantToEnum(Lists.newArrayList(),MockEnum.class);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testEnumShouldFailInvalidEnumIndex(){
|
||||
final int invalidIndex = MockEnum.class.getEnumConstants().length + 1;
|
||||
Conversions.variantToEnum(invalidIndex, MockEnum.class);
|
||||
}
|
||||
|
||||
private enum MockEnum {
|
||||
THIS,IS,TEST
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user