/** * Converts dates and times to an R representation. * * <p>The following are represented as strings: * * <ul> * <li>LocalDate * </ul> * * The following are represented as doubles (seconds since 1970-01-01 epoch): * * <ul> * <li>Expiry* * <li>Instant * <li>ZonedDateTime* * </ul> * * * although sent to R as a double, they can also be received as strings */ public class DateTimeConverter extends AbstractTypeConverter { private static final JavaTypeInfo<Value> VALUE = JavaTypeInfo.builder(Value.class).get(); private static final JavaTypeInfo<Value> VALUE_ALLOW_NULL = JavaTypeInfo.builder(Value.class).allowNull().get(); private static final JavaTypeInfo<Instant> INSTANT = JavaTypeInfo.builder(Instant.class).get(); private static final JavaTypeInfo<Instant> INSTANT_ALLOW_NULL = JavaTypeInfo.builder(Instant.class).allowNull().get(); private static final JavaTypeInfo<LocalDate> LOCAL_DATE = JavaTypeInfo.builder(LocalDate.class).get(); private static final JavaTypeInfo<LocalDate> LOCAL_DATE_ALLOW_NULL = JavaTypeInfo.builder(LocalDate.class).allowNull().get(); private static final JavaTypeInfo<ZonedDateTime> ZONED_DATE_TIME = JavaTypeInfo.builder(ZonedDateTime.class).get(); private static final JavaTypeInfo<ZonedDateTime> ZONED_DATE_TIME_ALLOW_NULL = JavaTypeInfo.builder(ZonedDateTime.class).allowNull().get(); private static final JavaTypeInfo<Expiry> EXPIRY = JavaTypeInfo.builder(Expiry.class).get(); private static final JavaTypeInfo<Expiry> EXPIRY_ALLOW_NULL = JavaTypeInfo.builder(Expiry.class).allowNull().get(); private static final TypeMap TO_VALUE = TypeMap.of(ZERO_LOSS, INSTANT, LOCAL_DATE) .with(MINOR_LOSS, ZONED_DATE_TIME) .with(MAJOR_LOSS, EXPIRY); private static final TypeMap TO_VALUE_ALLOW_NULL = TypeMap.of(ZERO_LOSS, INSTANT_ALLOW_NULL, LOCAL_DATE_ALLOW_NULL) .with(MINOR_LOSS, ZONED_DATE_TIME_ALLOW_NULL) .with(MAJOR_LOSS, EXPIRY_ALLOW_NULL); private static final TypeMap FROM_VALUE = TypeMap.of(MINOR_LOSS, VALUE); private static final TypeMap FROM_VALUE_ALLOW_NULL = TypeMap.of(MINOR_LOSS, VALUE_ALLOW_NULL); @Override public boolean canConvertTo(final JavaTypeInfo<?> targetType) { final Class<?> clazz = targetType.getRawClass(); if (clazz == Value.class) { return true; } else { for (JavaTypeInfo<?> toData : (targetType.isAllowNull() ? TO_VALUE_ALLOW_NULL : TO_VALUE).keySet()) { if (clazz == toData.getRawClass()) { return true; } } return false; } } @Override public void convertValue( final ValueConversionContext conversionContext, final Object value, final JavaTypeInfo<?> type) { if ((value == null) && type.isAllowNull()) { conversionContext.setResult(null); return; } final Class<?> clazz = type.getRawClass(); if (clazz == Value.class) { if (value instanceof LocalDate) { conversionContext.setResult(ValueUtils.of(((LocalDate) value).toString())); } else if (value instanceof InstantProvider) { conversionContext.setResult( ValueUtils.of((double) ((InstantProvider) value).toInstant().getEpochSeconds())); } else { conversionContext.setFail(); } } else if (clazz == LocalDate.class) { final String str = ((Value) value).getStringValue(); if (str != null) { try { conversionContext.setResult(LocalDate.parse(str)); } catch (CalendricalException e) { conversionContext.setFail(); } } else { conversionContext.setFail(); } } else if (clazz == Instant.class) { final Double epochSeconds = ((Value) value).getDoubleValue(); if (epochSeconds != null) { conversionContext.setResult(Instant.ofEpochSeconds(epochSeconds.longValue())); } else { conversionContext.setFail(); } } else if (clazz == ZonedDateTime.class) { final ZonedDateTime zdt = valueToZonedDateTime((Value) value); if (zdt != null) { conversionContext.setResult(zdt); } else { conversionContext.setFail(); } } else if (clazz == Expiry.class) { final ZonedDateTime zdt = valueToZonedDateTime((Value) value); if (zdt != null) { conversionContext.setResult(new Expiry(zdt)); } else { conversionContext.setFail(); } } else { conversionContext.setFail(); } } private static ZonedDateTime valueToZonedDateTime(final Value v) { final Double epochSeconds = v.getDoubleValue(); if (epochSeconds != null) { return ZonedDateTime.ofEpochSeconds(epochSeconds.longValue(), TimeZone.UTC); } else { final String dateTime = v.getStringValue(); if (dateTime != null) { try { return ZonedDateTime.parse(dateTime); } catch (CalendricalException e) { // Ignore } try { return ZonedDateTime.of(LocalDate.parse(dateTime), LocalTime.MIDDAY, TimeZone.UTC); } catch (CalendricalException e) { // Ignore } } } return null; } @Override public Map<JavaTypeInfo<?>, Integer> getConversionsTo(final JavaTypeInfo<?> targetType) { final Class<?> clazz = targetType.getRawClass(); if (clazz == Value.class) { return targetType.isAllowNull() ? TO_VALUE_ALLOW_NULL : TO_VALUE; } else { return targetType.isAllowNull() ? FROM_VALUE_ALLOW_NULL : FROM_VALUE; } } }
/** * Provides the most primitive level of view client type conversion. View clients are converted * to/from the {@link ViewClientKey} representation which is least efficient but all that is * available in the general case. A specific language binding that can track objects should replace * this with a conversion scheme that can work with the references detached from {@link * UserViewClients}. * * <p>It is expected that functions which take a {@link ViewClientHandle} as a parameter should * unlock it when they are done. */ public class UserViewClientConverter extends AbstractTypeConverter { /** Default instance. */ public static final UserViewClientConverter INSTANCE = new UserViewClientConverter(); private static final JavaTypeInfo<ViewClientKey> VIEW_CLIENT_KEY = JavaTypeInfo.builder(ViewClientKey.class).get(); private static final JavaTypeInfo<ViewClientHandle> VIEW_CLIENT_HANDLE = JavaTypeInfo.builder(ViewClientHandle.class).get(); private static final TypeMap TO_VIEW_CLIENT_KEY = TypeMap.of(ZERO_LOSS, VIEW_CLIENT_HANDLE); private static final TypeMap TO_VIEW_CLIENT_HANDLE = TypeMap.of(ZERO_LOSS, VIEW_CLIENT_KEY); protected UserViewClientConverter() {} /** * The key used by the default type converter. A binding specific converter should be declared * with this key to replace the default. * * @return the key */ public static String getTypeConverterKeyImpl() { return UserViewClient.class.getSimpleName(); } @Override public String getTypeConverterKey() { return getTypeConverterKeyImpl(); } @Override public boolean canConvertTo(final JavaTypeInfo<?> targetType) { return (targetType.getRawClass() == ViewClientKey.class) || (targetType.getRawClass() == ViewClientHandle.class); } @Override public void convertValue( final ValueConversionContext conversionContext, final Object value, final JavaTypeInfo<?> type) { if (type.getRawClass() == ViewClientKey.class) { final ViewClientHandle viewClient = (ViewClientHandle) value; conversionContext.setResult(viewClient.get().getViewClientKey()); viewClient.unlock(); } else { final ViewClientKey key = (ViewClientKey) value; conversionContext.setResult( conversionContext.getUserContext().getViewClients().lockViewClient(key)); } } @Override public Map<JavaTypeInfo<?>, Integer> getConversionsTo(final JavaTypeInfo<?> targetType) { if (targetType.getRawClass() == ViewClientKey.class) { return TO_VIEW_CLIENT_KEY; } else { return TO_VIEW_CLIENT_HANDLE; } } }
/** Basic conversions to/from the {@link Value} type. */ public final class ValueConverter implements TypeConverter { private static final JavaTypeInfo<Value> VALUE_NOT_NULL = JavaTypeInfo.builder(Value.class).get(); private static final JavaTypeInfo<Value> VALUE_NULL = JavaTypeInfo.builder(Value.class).allowNull().get(); private static final JavaTypeInfo<Boolean> BOOLEAN_NOT_NULL = JavaTypeInfo.builder(Boolean.class).get(); private static final JavaTypeInfo<Boolean> BOOLEAN_NULL = JavaTypeInfo.builder(Boolean.class).allowNull().get(); private static final JavaTypeInfo<Integer> INTEGER_NOT_NULL = JavaTypeInfo.builder(Integer.class).get(); private static final JavaTypeInfo<Integer> INTEGER_NULL = JavaTypeInfo.builder(Integer.class).allowNull().get(); private static final JavaTypeInfo<Double> DOUBLE_NOT_NULL = JavaTypeInfo.builder(Double.class).get(); private static final JavaTypeInfo<Double> DOUBLE_NULL = JavaTypeInfo.builder(Double.class).allowNull().get(); private static final JavaTypeInfo<String> STRING_NOT_NULL = JavaTypeInfo.builder(String.class).get(); private static final JavaTypeInfo<String> STRING_NULL = JavaTypeInfo.builder(String.class).allowNull().get(); private static final JavaTypeInfo<FudgeMsg> MESSAGE_NOT_NULL = JavaTypeInfo.builder(FudgeMsg.class).get(); private static final JavaTypeInfo<FudgeMsg> MESSAGE_NULL = JavaTypeInfo.builder(FudgeMsg.class).allowNull().get(); private static final TypeMap TO_VALUE_NOT_NULL = TypeMap.of( ZERO_LOSS, BOOLEAN_NOT_NULL, INTEGER_NOT_NULL, DOUBLE_NOT_NULL, STRING_NOT_NULL, MESSAGE_NOT_NULL); private static final TypeMap TO_VALUE_ALLOW_NULL = TypeMap.of(ZERO_LOSS, BOOLEAN_NULL, INTEGER_NULL, DOUBLE_NULL, STRING_NULL, MESSAGE_NULL); private static final TypeMap FROM_VALUE_NOT_NULL = TypeMap.of(ZERO_LOSS, VALUE_NOT_NULL); private static final TypeMap FROM_VALUE_ALLOW_NULL = TypeMap.of(ZERO_LOSS, VALUE_NULL); @Override public boolean canConvertTo(JavaTypeInfo<?> targetType) { final Class<?> clazz = targetType.getRawClass(); if (clazz == Value.class) { return true; } else { for (JavaTypeInfo<?> toData : (targetType.isAllowNull() ? TO_VALUE_ALLOW_NULL : TO_VALUE_NOT_NULL).keySet()) { if (clazz == toData.getRawClass()) { return true; } } return false; } } @Override public Map<JavaTypeInfo<?>, Integer> getConversionsTo(JavaTypeInfo<?> targetType) { final Class<?> clazz = targetType.getRawClass(); if (clazz == Value.class) { return targetType.isAllowNull() ? TO_VALUE_ALLOW_NULL : TO_VALUE_NOT_NULL; } else { return targetType.isAllowNull() ? FROM_VALUE_ALLOW_NULL : FROM_VALUE_NOT_NULL; } } @Override public String toString() { return TypeConverter.class.getSimpleName() + "[to/from " + Value.class.getName() + "]"; } @Override public void convertValue( ValueConversionContext conversionContext, Object valueObject, JavaTypeInfo<?> type) { final Class<?> clazz = type.getRawClass(); if (clazz == Value.class) { if (valueObject instanceof Boolean) { conversionContext.setResult(ValueUtil.of((Boolean) valueObject)); } else if (valueObject instanceof Integer) { conversionContext.setResult(ValueUtil.of((Integer) valueObject)); } else if (valueObject instanceof Double) { conversionContext.setResult(ValueUtil.of((Double) valueObject)); } else if (valueObject instanceof String) { conversionContext.setResult(ValueUtil.of((String) valueObject)); } else if (valueObject instanceof FudgeMsg) { conversionContext.setResult(ValueUtil.of((FudgeMsg) valueObject)); } else { conversionContext.setFail(); } return; } else { if (valueObject instanceof Value) { final Value value = (Value) valueObject; if (ValueUtil.isNull(value)) { if (type.isAllowNull()) { conversionContext.setResult(null); } else { conversionContext.setFail(); } } else if (clazz == Boolean.class) { if (value.getBoolValue() != null) { conversionContext.setResult(value.getBoolValue()); } else { conversionContext.setFail(); } } else if (clazz == Integer.class) { if (value.getIntValue() != null) { conversionContext.setResult(value.getIntValue()); } else { conversionContext.setFail(); } } else if (clazz == Double.class) { if (value.getDoubleValue() != null) { conversionContext.setResult(value.getDoubleValue()); } else { conversionContext.setFail(); } } else if (clazz == String.class) { if (value.getStringValue() != null) { conversionContext.setResult(value.getStringValue()); } else { conversionContext.setFail(); } } else if (clazz == FudgeMsg.class) { if (value.getMessageValue() != null) { conversionContext.setResult(value.getMessageValue()); } else { conversionContext.setFail(); } } else { conversionContext.setFail(); } return; } else if (valueObject == null) { if (type.isAllowNull()) { conversionContext.setResult(null); return; } } } conversionContext.setFail(); } }