package dials.filter; import org.joda.time.DateTime; import org.joda.time.LocalTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.math.BigDecimal; import java.util.Map; public class FilterDataHelper { private Map<String, Object> dataObjects; private String[] dateTimePatterns = new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd"}; private String[] localTimePatterns = new String[]{"HH:mm:ss", "HH:mm", "HH"}; public FilterDataHelper(FilterData filterData) { dataObjects = filterData.getDataObjects(); } public <T> T getData(String dataName, Class<T> expectedType) throws FilterDataException { Object dataObject = dataObjects.get(dataName.toLowerCase()); if (isNull(dataObject)) { throw new FilterDataException("Data " + dataName + " was not provided"); } if (isAssignableFrom(dataObject, expectedType)) { return expectedType.cast(dataObject); } else { try { return attemptStringBasedDataConverstion(dataName, String.class.cast(dataObject), expectedType); } catch (ClassCastException e) { throw getDataRepresentativeFilterDataException(dataName, expectedType); } } } private boolean isNull(Object object) { return object == null; } private boolean isAssignableFrom(Object object, Class<?> expectedType) { return isAssignableFrom(object.getClass(), expectedType); } private boolean isAssignableFrom(Class<?> providedType, Class<?> expectedType) { return expectedType.isAssignableFrom(providedType); } private <T> T attemptStringBasedDataConverstion(String dataName, String dataObject, Class<T> expectedType) throws FilterDataException { if (isAssignableFrom(String.class, expectedType)) { return handleString(dataObject, expectedType); } else if (isAssignableFrom(Integer.class, expectedType)) { return handleInteger(dataName, dataObject, expectedType); } else if (isAssignableFrom(Long.class, expectedType)) { return handleLong(dataName, dataObject, expectedType); } else if (isAssignableFrom(BigDecimal.class, expectedType)) { return handleBigDecimal(dataName, dataObject, expectedType); } else if (isAssignableFrom(DateTime.class, expectedType)) { return handleDateTime(dataName, dataObject, expectedType); } else if (isAssignableFrom(LocalTime.class, expectedType)) { return handleLocalTime(dataName, dataObject, expectedType); } else { throw new FilterDataException("Provided type " + expectedType.getSimpleName() + " is not yet supported"); } } private <T> T handleString(String dataObject, Class<T> expectedType) { return expectedType.cast(dataObject); } private <T> T handleInteger(String dataName, String dataObject, Class<T> expectedType) throws FilterDataException { try { return expectedType.cast(Integer.parseInt(dataObject)); } catch (NumberFormatException | ClassCastException e) { throw getDataRepresentativeFilterDataException(dataName, expectedType); } } private <T> T handleDateTime(String dataName, String dataObject, Class<T> expectedType) throws FilterDataException { for (String pattern : dateTimePatterns) { DateTimeFormatter formatter = DateTimeFormat.forPattern(pattern); try { return expectedType.cast(formatter.parseDateTime(dataObject)); } catch (Exception e) { continue; } } throw getDataRepresentativeFilterDataException(dataName, expectedType); } private <T> T handleLocalTime(String dataName, String dataObject, Class<T> expectedType) throws FilterDataException { for (String pattern : localTimePatterns) { DateTimeFormatter formatter = DateTimeFormat.forPattern(pattern); try { return expectedType.cast(formatter.parseLocalTime(dataObject)); } catch (Exception e) { continue; } } throw getDataRepresentativeFilterDataException(dataName, expectedType); } private <T> T handleLong(String dataName, String dataObject, Class<T> expectedType) throws FilterDataException { try { return expectedType.cast(Long.parseLong(dataObject)); } catch (NumberFormatException | ClassCastException e) { throw getDataRepresentativeFilterDataException(dataName, expectedType); } } private <T> T handleBigDecimal(String dataName, String dataObject, Class<T> expectedType) throws FilterDataException { try { return expectedType.cast(new BigDecimal(dataObject)); } catch (NumberFormatException | ClassCastException e) { throw getDataRepresentativeFilterDataException(dataName, expectedType); } } private FilterDataException getDataRepresentativeFilterDataException(String dataName, Class expectedType) { return new FilterDataException("Unable to represent " + dataName + " as " + expectedType.getSimpleName()); } }