package ameba.core.ws.rs;
import com.fasterxml.jackson.databind.util.ISO8601Utils;
import org.glassfish.jersey.internal.inject.ExtractorException;
import org.glassfish.jersey.message.internal.HttpDateFormat;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import javax.inject.Singleton;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.ParsePosition;
import java.time.*;
import java.util.Date;
import java.util.TimeZone;
/**
* <p>ParamConverters class.</p>
*
* @author icode
*/
public class ParamConverters {
private static final String SYS_TZ;
static {
TimeZone tz = TimeZone.getDefault();
int offset = tz.getRawOffset();
int z = offset / (60 * 60 * 1000);
String tzs = String.valueOf(Math.abs(z));
if (z >= 0 && z <= 9) {
tzs = "+0" + tzs;
} else if (z >= 0) {
tzs = "+" + tzs;
} else if (z < 0 && z > -9) {
tzs = "-0" + tzs;
} else if (z < 0) {
tzs = "-" + tzs;
}
z = (Math.abs(offset) / (60 * 1000)) % 60;
if (z <= 9) {
tzs += "0";
}
tzs += z;
SYS_TZ = tzs;
}
private ParamConverters() {
}
/**
* <p>parseTimestamp.</p>
*
* @param value a {@link java.lang.String} object.
* @return a {@link java.lang.Long} object.
*/
public static Long parseTimestamp(String value) {
if (value.matches("^[0-9]+$")) {
try {
return Long.parseLong(value);
} catch (Exception e) {
return null;
}
}
return null;
}
/**
* <p>parseDate.</p>
*
* @param value a {@link java.lang.String} object.
* @param pos a {@link java.text.ParsePosition} object.
* @return a {@link java.util.Date} object.
*/
public static Date parseDate(String value, ParsePosition pos) {
Long timestamp = parseTimestamp(value);
if (timestamp != null) {
return new Date(timestamp);
}
if (value.contains(" ")) {
value = value.replace(" ", "+");
}
if (!(value.contains("-") || value.contains("+")) && !value.endsWith("Z")) {
value += SYS_TZ;
}
try {
return ISO8601Utils.parse(value, pos);
} catch (ParseException e) {
throw new ExtractorException(e);
}
}
/**
* <p>parseDate.</p>
*
* @param value a {@link java.lang.String} object.
* @return a {@link java.util.Date} object.
*/
public static Date parseDate(String value) {
return parseDate(value, new ParsePosition(0));
}
private static Instant parseInstant(String value) {
return parseDate(value).toInstant();
}
/**
* Provider of {@link ParamConverter param converter} that produce the target Java {@link Enum enum} type instance
* by invoking a static {@code fromString(String)} method on the target enum type.
*/
@Singleton
public static class TypeFromStringEnum implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(final Class<T> rawType,
final Type genericType,
final Annotation[] annotations) {
return (!Enum.class.isAssignableFrom(rawType)) ? null : new ParamConverter<T>() {
@Override
public T fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
try {
return rawType.getEnumConstants()[Integer.parseInt(value)];
} catch (NumberFormatException e) {
String eName = value.toUpperCase();
Enum[] result = (Enum[]) rawType.getEnumConstants();
for (Enum r : result) {
if (r.name().equals(eName)) {
return rawType.cast(r);
}
}
return null;
}
}
@Override
public String toString(T value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
};
}
}
@Singleton
@SuppressWarnings("unchecked")
public static class BooleanProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(final Class<T> rawType, Type genericType, Annotation[] annotations) {
if (boolean.class.isAssignableFrom(rawType) || Boolean.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new ParamConverter<Boolean>() {
@Override
public Boolean fromString(String value) {
return "".equals(value)
|| "true".equalsIgnoreCase(value)
|| "1".equals(value);
}
@Override
public String toString(Boolean value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
};
}
return null;
}
}
/**
* Provider of {@link ParamConverter param converter} that convert the supplied string into a Java
* {@link Date} instance using conversion method from the
* {@link HttpDateFormat http date formatter} utility class.
*/
@Singleton
@SuppressWarnings("unchecked")
public static class DateProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(final Class<T> rawType,
final Type genericType,
final Annotation[] annotations) {
if (LocalDateTime.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new LocalDateTimeParamConverter();
} else if (Duration.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new DurationParamConverter();
} else if (Instant.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new InstantParamConverter();
} else if (LocalDate.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new LocalDateParamConverter();
} else if (LocalTime.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new LocalTimeParamConverter();
} else if (Period.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new PeriodParamConverter();
} else if (Date.class.isAssignableFrom(rawType)) {
return new ParamConverter<T>() {
@Override
public T fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return rawType.cast(parseDate(value));
}
@Override
public String toString(final T value) throws IllegalArgumentException {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
};
}
return null;
}
}
public static class DurationParamConverter implements ParamConverter<Duration> {
@Override
public Duration fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return Duration.parse(value);
}
@Override
public String toString(Duration value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
}
public static class PeriodParamConverter implements ParamConverter<Period> {
@Override
public Period fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return Period.parse(value);
}
@Override
public String toString(Period value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
}
public static class InstantParamConverter implements ParamConverter<Instant> {
@Override
public Instant fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return parseInstant(value);
}
@Override
public String toString(Instant value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
}
public static class LocalDateParamConverter implements ParamConverter<LocalDate> {
@Override
public LocalDate fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return LocalDate.from(parseInstant(value));
}
@Override
public String toString(LocalDate value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
}
public static class LocalDateTimeParamConverter implements ParamConverter<LocalDateTime> {
@Override
public LocalDateTime fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return LocalDateTime.from(parseInstant(value));
}
@Override
public String toString(LocalDateTime value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
}
public static class LocalTimeParamConverter implements ParamConverter<LocalTime> {
@Override
public LocalTime fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return LocalTime.from(parseInstant(value));
}
@Override
public String toString(LocalTime value) {
if (value == null) {
throw new IllegalArgumentException(
LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value")
);
}
return value.toString();
}
}
}