Skip to content

Commit

Permalink
Merge pull request #202 from sinch/DEVEXP-726-define-queue-status-inc…
Browse files Browse the repository at this point in the history
…oming-field-as-instant

feat (Mailgun/Messages):  Support 'QueueStatusDisabledDetails.until'as Instant
  • Loading branch information
JPPortier authored Jan 31, 2025
2 parents 28b8db8 + 3ef2b84 commit 30fd3f0
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,13 @@ public void getSendingQueuesStatusResult() {
ExceededQueueQuota.builder()
.setIsDisabled(false)
.setDetails(
QueueStatusDisabledDetails.builder().setUntil("").setReason("").build())
QueueStatusDisabledDetails.builder().setUntil(null).setReason("").build())
.build())
.setScheduled(
ExceededQueueQuota.builder()
.setIsDisabled(false)
.setDetails(
QueueStatusDisabledDetails.builder().setUntil("").setReason("").build())
QueueStatusDisabledDetails.builder().setUntil(null).setReason("").build())
.build())
.build();

Expand Down
130 changes: 119 additions & 11 deletions core/src/main/com/sinch/sdk/core/utils/DateUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.logging.Logger;

/** Utility class for Date */
public class DateUtil {

private static final DateTimeFormatter RFC822_ZONED_FORMAT =
DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss z");

private static final DateTimeFormatter RFC822_GMT_FORMAT =
DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss").withZone(ZoneId.of("GMT"));

private static final Logger LOGGER = Logger.getLogger(DateUtil.class.getName());

private DateUtil() {}

/**
Expand Down Expand Up @@ -41,20 +53,116 @@ public static Instant toInstant(OffsetDateTime value) {
*/
public static Instant failSafeTimeStampToInstant(String value) {

if (null == value) {
String trimmed = null == value ? "" : value.trim();

if (trimmed.isEmpty()) {
return null;
}

Instant parsed = parseISO8601(trimmed);
if (null != parsed) {
return parsed;
}

parsed = parseISO8601WithOffset(trimmed);
if (null != parsed) {
return parsed;
}

// fallback: this is not an ISO8601 compliant format: give a chance and assume it is GMT zone
parsed = parseISO8601WithoutOffset(trimmed);
if (null != parsed) {
return parsed;
}

// do not break deserialization: fallback to empty value
LOGGER.severe(String.format("Unable to parse '%s' date string", value));

return null;
}

private static Instant parseISO8601(String trimmed) {
try {
return Instant.parse(trimmed);
} catch (DateTimeParseException _unused) {
return null;
}
}

private static Instant parseISO8601WithOffset(String trimmed) {
try {
return OffsetDateTime.parse(trimmed).toInstant();
} catch (DateTimeParseException _unused) {
return null;
}
}

Instant timestamp;
private static Instant parseISO8601WithoutOffset(String trimmed) {
try {
timestamp = Instant.parse(value);
} catch (DateTimeParseException e) {
try {
timestamp = OffsetDateTime.parse(value).toInstant();
} catch (DateTimeParseException dte) {
timestamp = LocalDateTime.parse(value).toInstant(ZoneOffset.UTC);
}
}
return timestamp;
return LocalDateTime.parse(trimmed).toInstant(ZoneOffset.UTC);
} catch (DateTimeParseException _unused) {
return null;
}
}

/**
* Convert String to Instant
*
* <p>Consume a date time in form of RFC-822 format
*
* @param value An RFC-822 compliant string
* @return Extracted Instant value
* @since __TO_BE_DEFINED__
*/
public static Instant RFC822StringToInstant(String value) {

String trimmed = null == value ? "" : value.trim();

if (trimmed.isEmpty()) {
return null;
}

Instant parsed = parseRFC822(trimmed);
if (null != parsed) {
return parsed;
}

parsed = parseRFC822WithZone(trimmed);
if (null != parsed) {
return parsed;
}

// fallback: this is not an RFC compliant format: give a chance and assume it is GMT zone
parsed = parseRFC822WithoutZoneNorOffset(trimmed);
if (null != parsed) {
return parsed;
}

LOGGER.severe(String.format("Unable to parse '%s' date string", value));
return null;
}

private static Instant parseRFC822(String trimmed) {
try {
return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(trimmed));
} catch (DateTimeParseException _unused) {
return null;
}
}

private static Instant parseRFC822WithZone(String trimmed) {
try {
return ZonedDateTime.parse(trimmed, RFC822_ZONED_FORMAT).toInstant();
} catch (DateTimeParseException _unused) {
return null;
}
}

private static Instant parseRFC822WithoutZoneNorOffset(String trimmed) {
try {
return ZonedDateTime.parse(trimmed, RFC822_GMT_FORMAT).toInstant();
} catch (DateTimeParseException _unused) {
return null;
}
}
}
35 changes: 25 additions & 10 deletions core/src/main/com/sinch/sdk/core/utils/databind/Mapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

public class Mapper {

public static final PropertyFilter uninitializedFilter =
private static final PropertyFilter uninitializedFilter =
new SimpleBeanPropertyFilter() {
@Override
public void serializeAsField(
Expand Down Expand Up @@ -95,19 +95,19 @@ public static ObjectMapper getInstance() {

private static class LazyHolder {

public static final SimpleModule module =
static final SimpleModule module =
new JavaTimeModule()
.addDeserializer(OffsetDateTime.class, new OffsetDateTimeCustomDeserializer())
.addDeserializer(Instant.class, new InstantCustomDeserializer());

public static final SimpleModule optionalValueModule =
static final SimpleModule optionalValueModule =
new SimpleModule("optionalValueModule")
.addSerializer(OptionalValue.class, new OptionalValueSerializer());
public static final SimpleModule dynamicEnumModule =
static final SimpleModule dynamicEnumModule =
new SimpleModule("dynamicEnumModule")
.addSerializer(EnumDynamic.class, new EnumDynamicSerializer());

public static final SimpleModule validationDeserializationModule =
static final SimpleModule validationDeserializationModule =
new SimpleModule("deserializationModule")
.setDeserializerModifier(new BuilderDeserializerWithValidation());

Expand All @@ -128,7 +128,7 @@ private static class LazyHolder {
.registerModule(validationDeserializationModule);
}

public static final class OffsetDateTimeCustomDeserializer
private static final class OffsetDateTimeCustomDeserializer
extends JsonDeserializer<OffsetDateTime> {

@Override
Expand All @@ -148,18 +148,33 @@ public OffsetDateTime deserialize(JsonParser parser, DeserializationContext cont
}
}

public static final class InstantCustomDeserializer extends JsonDeserializer<Instant> {
private static final class InstantCustomDeserializer extends JsonDeserializer<Instant> {

@Override
public Instant deserialize(JsonParser parser, DeserializationContext context)
throws IOException {

String text = parser.getText();
return DateUtil.failSafeTimeStampToInstant(text);

if (null == text) {
return null;
}

String trimmed = text.trim();
if (trimmed.isEmpty()) {
return null;
}

// RFC Date are starting with character not a digit
if (Character.isDigit(text.charAt(0))) {
return DateUtil.failSafeTimeStampToInstant(text);
}

return DateUtil.RFC822StringToInstant(text);
}
}

public static class EnumDynamicSerializer extends JsonSerializer<EnumDynamic> {
private static class EnumDynamicSerializer extends JsonSerializer<EnumDynamic> {

@Override
public void serialize(EnumDynamic value, JsonGenerator jgen, SerializerProvider provider)
Expand All @@ -168,7 +183,7 @@ public void serialize(EnumDynamic value, JsonGenerator jgen, SerializerProvider
}
}

public static class OptionalValueSerializer extends JsonSerializer<OptionalValue> {
private static class OptionalValueSerializer extends JsonSerializer<OptionalValue> {

@Override
public void serialize(OptionalValue value, JsonGenerator jgen, SerializerProvider provider)
Expand Down
79 changes: 79 additions & 0 deletions core/src/test/java/com/sinch/sdk/core/utils/DateUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ void failSafeTimeStampNullGuard() {
assertNull(instant);
}

@Test
void failSafeTimeStampFromBlankString() {
Instant instant = DateUtil.failSafeTimeStampToInstant(" ");
assertNull(instant);
}

@Test
void failSafeTimeStampFromStringWithBlanks() {
Instant instant = DateUtil.failSafeTimeStampToInstant(" 2024-05-04T10:00:00.1234 ");
assertEquals("2024-05-04T10:00:00.123400Z", instant.toString());
}

@Test
void failSafeTimeStampNoTZ() {
Instant instant = DateUtil.failSafeTimeStampToInstant("2024-05-04T10:00:00.1234");
Expand All @@ -49,4 +61,71 @@ void failSafeTimeStampFromUTC() {
Instant instant = DateUtil.failSafeTimeStampToInstant("2024-05-04T10:00:00.1234Z");
assertEquals("2024-05-04T10:00:00.123400Z", instant.toString());
}

@Test
void failSafeTimeStampInvalid() {
Instant instant = DateUtil.failSafeTimeStampToInstant("2024 05 04 10 00 00 1234 ");
assertNull(instant);
}

@Test
void RFC822NullGuard() {
Instant instant = DateUtil.RFC822StringToInstant(null);
assertNull(instant);
}

@Test
void RFC822FromBlankString() {
Instant instant = DateUtil.RFC822StringToInstant(" ");
assertNull(instant);
}

@Test
void RFC822FromStringWithBlanks() {
Instant instant = DateUtil.RFC822StringToInstant(" Mon, 2 Jan 2006 15:04:05 MST ");
assertEquals("2006-01-02T22:04:05Z", instant.toString());
}

@Test
void RFC822WithUnsupportedMST() {
Instant instant = DateUtil.RFC822StringToInstant("Mon, 2 Jan 2006 15:04:05 MST");
assertEquals("2006-01-02T22:04:05Z", instant.toString());
}

@Test
void RFC822WithGMT() {
Instant instant = DateUtil.RFC822StringToInstant("Mon, 2 Jan 2006 15:04:05 GMT");
assertEquals("2006-01-02T15:04:05Z", instant.toString());
}

@Test
void RFC822WithUnsupportedUT() {
Instant instant = DateUtil.RFC822StringToInstant("Mon, 2 Jan 2006 15:04:05 UT");
assertEquals("2006-01-02T15:04:05Z", instant.toString());
}

@Test
void RFC822WithUnsupportedEST() {
Instant instant = DateUtil.RFC822StringToInstant("Mon, 2 Jan 2006 15:04:05 EST");
assertEquals("2006-01-02T20:04:05Z", instant.toString());
}

@Test
void RFC822WithOffset() {
Instant instant = DateUtil.RFC822StringToInstant("Mon, 2 Jan 2006 15:04:05 +0100");
assertEquals("2006-01-02T14:04:05Z", instant.toString());
}

@Test
void RFC822NoOffset() {
Instant instant = DateUtil.RFC822StringToInstant("Mon, 2 Jan 2006 15:04:05");
assertEquals("2006-01-02T15:04:05Z", instant.toString());
}

@Test
void RFC822Invalid() {
// 12th of January 2006 is not a Monday (it was a Thursday)
Instant instant = DateUtil.RFC822StringToInstant("Mon, 12 Jan 2006 15:04:05 +0100");
assertNull(instant);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package com.sinch.sdk.domains.mailgun.models.v1.emails.response;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.Instant;

/** QueueStatusDisabledDetails */
@JsonDeserialize(builder = QueueStatusDisabledDetailsImpl.Builder.class)
Expand All @@ -21,7 +22,7 @@ public interface QueueStatusDisabledDetails {
*
* @return until
*/
String getUntil();
Instant getUntil();

/**
* Get reason
Expand Down Expand Up @@ -49,7 +50,7 @@ interface Builder {
* @return Current builder
* @see #getUntil
*/
Builder setUntil(String until);
Builder setUntil(Instant until);

/**
* see getter
Expand Down
Loading

0 comments on commit 30fd3f0

Please sign in to comment.